故事

开元年间,长安到安西的驿道全长七千二百里,共设一百六十三座驿站。每隔三十里一驿,驿卒换马不换人,日行五百里,六日可将皇帝敕令送至龟兹。这是当时世界上最快的信息通道。

天宝三载,河西节度使哥舒翰上书,说驿道近年屡遭吐蕃游骑袭扰,请求在沿途增设护驿兵。兵部算了一笔账:每驿增兵五十,一百六十三驿就是八千余人,粮饷、马匹、甲胄,岁费绢二十万匹。宰相李林甫把折子压了半个月,批了两个字:不准。

哥舒翰不服,二次上书,说护驿兵可以精简,每驿二十人即可,专守驿舍与烽火台,不追敌、不野战。李林甫这次批得多些:「吐蕃游骑所图者,非驿舍也,乃驿卒与马。尔增兵守舍,彼仍可于道半截之。截一处则全道迟,迟一日则西陲惊。二十万匹绢买不来六日必达。」

哥舒翰懂了,也不再争。他改做了一件事:每道敕令不再只发一份,而是发三份,分走三条道——主线走河西驿道,副线走青海道,第三条绕得更远,经回纥境入北庭。三份文书各自封在铜函里,函内夹一片薄铜,上刻发函时刻与编号。安西都护府收到后,比对三函,取最先到的那份为准,其余两份存档备查。

这办法没花兵部一文钱,却让敕令延误率从每年十余次降到了三年一次。哥舒翰在奏报里写:「敌能截我一道,不能截我三道;能劫我一函,不能劫我三函。护道之费,省于护函之智。」

李林甫把这十二个字抄给了兵部侍郎,说以后边镇递文书,都按这个办。

但故事没有停在哥舒翰这里。

三十年后,元和年间,宰相裴垍整理旧档,发现哥舒翰那套「三函并递」有个意想不到的代价。安西都护府为比对三函,专设了「合函司」,三名书吏每日只做一件事:拆铜函、对时刻、验封印、登编号。一年下来,合函司耗掉的纸墨、铜片、书吏俸禄,折合绢三千匹。更要紧的是,三函并非同时到,有时相差两三日,都护府得等齐了三份才能发令,这空等的两三日里,前线将校无所适从。

裴垍问了一个哥舒翰没问过的问题:「三函并递」防的是吐蕃截道,可元和年间吐蕃势衰,驿道安宁,这三函是不是白送了?

他查了近十年的记录:三函并递的文书里,真正因为截道而需要启用副函的,一次也没有;但因为三函不齐而延误发令的,每年平均十七次。也就是说,哥舒翰为防一种已不存在的风险,制造了一种真实存在的成本。

裴垍没有废掉三函制——祖宗成法,不好轻动——但他加了一条新规矩:寻常政务,单函走主线即可;只有军机要务,才启动三函。合函司裁去两人,省下的俸禄改修驿道桥梁。

这条规矩后来被写进《元和驿令》,原文是:「急则多途,缓则一径;多途之费,不恒于常;一径之省,不废于要。」翻译成现代话:可靠性不是免费的东西,你要它,就得知道自己在防什么、值不值。

又过了两百年,到了明朝。永乐大帝修《永乐大典》,征天下书手入文渊阁抄录。书手们分散在南北两京、各省藩府,抄完一册,送通政司核验,核验无误,再发还典藏。通政司的核验极严:逐字比对,错一字则全册返工。

有个叫陈济的书手,在文渊阁干了十年,发现核验制度有个怪处:通政司查的是「抄本与原本是否一致」,但抄录过程中真正的风险——书手看错、墨汁污纸、蠹虫蛀页——通政司一概不管。等抄本送到通政司,这些错误早已铸成,返工成本十倍于预防。

陈济给通政司提了一条建议:核验保留,但每册抄录中途,书手自查一次;自查用朱笔圈出存疑处,附笺说明。这样通政司的逐字比对可以只查朱笔圈出的地方,省下一半人力;而书手因为知道要自查,抄录时反而更仔细,错误率降了三成。

通政司的主事骂了他一顿:「尔一介书手,敢议朝廷制度?」把条陈扔了。

但陈济的条陈被文渊阁一名编修偷偷抄录,带到了私人书院里。后来这条「自查+抽检」的做法,慢慢流进了民间刻书坊、票号账本、漕运清单——凡是有多层传递、末端验收的地方,都有人试着把一部分「验」的权力往前推,推到离错误发生更近的地方。

他们未必知道哥舒翰和裴垍的故事,但摸索出了同一个道理:最末端的验收者再严格,也改不了上游已经发生的错;真正的可靠性,得在错误可能发生的那一层就拦住它。

概念解析

端到端原则(End-to-End Principle)由 Saltzer、Reed 与 Clark 在 1984 年提出,是互联网架构的核心哲学之一。它的表述很简洁:通信系统应当在「端点」实现可靠性,而非在中间节点层层叠加

「端点」是什么意思。 在分布式系统里,端点就是最终使用数据的那些节点——发信的书手与收信的都护府,而不是中间的驿站、通政司、驿道。哥舒翰的「三函并递」是在端点(都护府)实现可靠性:三份副本到齐后比对,中间任何一道被截都不影响最终结果。裴垍后来发现的,是这条原则的推论:如果端点已经有办法保证可靠,中间层再重复做同样的事,就是浪费

为什么中间层不可靠。 不是因为中间层的工程师不够聪明,而是因为中间层不知道「可靠」对端点意味着什么。通政司的逐字比对,对书手抄错字毫无办法;驿道的护驿兵,对吐蕃在道半截击毫无办法。中间层能做的,只是自己那一层能看到的错误——而真正的语义错误(抄错指令、理解偏差、时序错乱),往往只有端点能判断。

互联网里的体现。 TCP 协议是端到端原则最经典的实现:IP 层只管尽力投递,不保证不丢包、不乱序、不重传;这些保证全部由通信两端的 TCP 来实现。如果 IP 层试图保证「每个包必达」,它得维护大量状态,而这些状态在端点早已维护了一份——重复、冗余、且无法真正满足端点的语义需求(比如应用层要的是「这条消息处理完」,不是「这个包到达了」)。

反例与修正。 端到端原则不是「中间层什么都别做」。CDN 缓存、TLS 中间盒、负载均衡,都是中间层在做功——但它们做的是「性能优化」或「安全加固」,不是「替端点保证语义正确」。哥舒翰的驿道本身也需要维护桥梁、清淤河道,这些是中间层的本分;但「三函并递」这种可靠性机制,放在端点才有效。

裴垍的「急则多途,缓则一径」,本质上是根据端点的真实需求动态调整可靠性投入——不是无脑堆中间层,也不是一刀切地废掉所有冗余。

分布式系统的教训。 今天做微服务架构的人常犯哥舒翰后期的错:每个服务层都自己做重试、做幂等、做超时回退,结果端点的业务逻辑被层层包裹,错误发生时谁也说不清责任边界。端到端原则提醒我们:先问「端点需要什么保证」,再问「哪一层最适合实现它」。大多数时候,答案是最外层的那个调用方——它知道这笔订单是不是必须成功,知道用户能不能接受最终一致,知道重试三次和重试三十次的业务后果。

中间层知道的,只是一个包、一次 RPC、一段心跳。把这些拼成「可靠的业务语义」,只能是端点的活。

哥舒翰的三函铜函,今天变成了客户端的重试策略、数据库的写入确认、分布式事务的 Saga 补偿。变的只是容器,不变的是那个判断:**可靠性该放在能看清全貌的那一层——而那一层,通常在两端。