动机来自昨天下班路上快到家发的一则朋友圈:
作为因果的历史是不存在的。因为有无数种对等的解释。这个可以用拓扑学证明的,模型非常简单,事件作为点,事件之间的关系作为连接两点的有向边。
最近思考一个问题,传输协议这么多,为什么我们不能再创造一个,就像 github 上写一个项目那样。或者很多人都已经尝试这么做了,但发现这个过程很艰难,最终绝大多数充其量只是完成一个永远上不了线的 “设计”。
另一方面,我们也经常看到最新的传输协议,从 WebRTC 到 QUIC,再到数据中心的种种卷料,令人眼花缭乱。既然这件事他们能做到,对我们为什么这么难?
同时我还发现一个有趣的事实,在 2014 年直到 2016 年之前,包括国内几家大型互联网公司在内的其中 “业务大部门(非商务,纯技术的业务部门,比如短视频,公有云)” 很少有人精通 Linux 内核,TCP/IP 内核实现,RDMA 这种底层技术,他们的关注点在业务逻辑本身。可过了这个时间之后,几乎每个业务都会标配一个底层团队,这些团队紧密贴合业务,比如为 CDN 提供定制化 Linux 内核,为某个组件提供定制化传输协议,如此等等。
在和业务大部分的这些同行交流时,我发现他们简直就是一个 “基础架构” 团队。层出不穷的新协议往往就是这些团队的手笔,令人惊讶的是,无论是从名字还是从技术栈构成都显得更专业的 “专门做网络传输” 的那些高内聚团队,包括一些脱离业务面壁钻研的个人,在相同的目标上反而举步维艰。后者这些团队和个人类似于游泳冠军争夺赛现场配备的救生员那样多余。
曾经整个公司会共享一个非常精锐的工程技术,基础架构支撑部门,到了后来这些支撑部门的能力下沉到了各个业务方,每个业务都会一帮懂 Linux 内核的,懂 TCP/QUIC 的,懂软硬件一体化的,而后者这种组织方式更有利于传输协议的技术突破和落地。为什么更专业的团队却做不到。
我们理解网络协议的方式有问题。
分层协议栈确实将模型模块化了,但仅对学习和操作有益,对“构建”(如果可以叫构建的话)一个新协议非但无益,反而是阻力。我们从分层协议栈模型中看到的是一个个静态协议,而这个模型的“生成”(我故意不说构建)过程被掩盖了。 从电话网到 QUIC,从底层设施到传输层,没有一个协议是从它应该所处的位置那里被构建出来的,相反,几乎所有成功的协议都是自顶向下逐步“生长”出来的。
电话为了替代文书,以应对竞争白热化的工业化,进而才催生了将语音调制编码传输技术组合在一起,以电话替代电报,而不是先铺设了电缆,组合了这些技术,然后到处兜售,恰好有大体量的组织觉得电话比电报好而买了单。 说说最近的 QUIC。QUIC 一开始并不存在,最开始人们没有任何动机去做一个新的传输层以替代 TCP,最开始的需求仅仅是在 UDP 上承载 HTTP/2,至于 HTTP/2 的动机则是解决 HTTP/1 的小缺陷和小毛病,原罪并非 TCP,只是 HTTP/1 恰被 TCP 承载。
HTTP/2 初见雏形,将公共不变的部分抽出来,这才有了 QUIC 雏形。从来没有发生下面这样一个过程,某个团队或个人开发了一个叫 QUIC 的传输协议,然后到处推广,兜售,叫卖“来试试我们这个新协议,相比 TCP,我们的吞吐率可以提升 2 倍,我们的延时更加稳定,我们可以…”,从来没有这个过程。
TCP 再不好,这么多年大家有 workaround 就还好,远非不可忍受。单连接 HOL,多连接可缓解,且退一万步,以操作系统名义更新 TCP 也远比说服各厂商同步更新更容易。从使用角度上讲,TCP 的问题远没有广泛传播的那般严重,是对新协议的宣传放大了 TCP 的缺陷对现实的影响。TCP 有很多原始缺陷,但在绝大多数情况下不影响使用。 来看另一个更典型的例子,IP。 IP 几乎是所有网络流量必经之处。可往前推 40 多年,IP 并不存在,彼时它内嵌于 TCP。和 QUIC 脱胎于 HTTP/2 一样,IP 是从 TCP 里抽出来的公共不变的部分,形成了沙漏的细腰。而 TCP 本身,也是从更高层的实际传输需求中抽出来的公共不变的部分。从来没有这么一个过程,某个团队或个人开发了一个叫 TCP 的协议,然后到处兜售,叫卖“快来试试我们这个协议吧,…”,也从来没有哪个团队或个人 “研发” 出了 IP,并使用各种或正或邪的诡计让独立的上层协议 TCP 附着于其上,没有这样的过程。
看看那些试着以独立的技术解决问题的企图,令牌网,ATM 等,这些技术要么太依赖其它部分,要么则试图完全不干扰其它部分,保持完全透明。无论如何,它们没有一个抽丝剥茧的分合过程,从一开始就有了设定,有了假设,要解决什么问题,要谁来配合,以及不能打扰到谁,但显然,它们基本上都失败了。 野蛮过程成功了,规划却失败了,所以我们的理解出了问题。
和教科书以及 RFC 介绍相反,我们应该反过来理解这个过程而不能只看现实结果,这是类似生物演化或生长的过程,而不是产品设计和兜售的过程。要说有没有后者的方式设计出来的一套协议,ISO 的 OSI 七层模型便是,但显然,它的兜售并不成功,货没有卖出去。
世界本没有路,走的人多了,就有了路。路是走出来的,而不能先造出来然后逼着人走。为什么你 “设计” 了一个非常厉害的协议,却兜售不出去,反个方向理解,豁然开朗。修路的例子,我们总以为先有了路,才能拉动周边投资,但这情况说的只是我们,如果它本来就是荒野,一定是一个相反的过程,先有了投资(即业务),后有路。我不准备在这里详述欧洲市镇是如何生成和连通起来的,如果你去梳理这个历史过程,会发现这个 “生长” 的道理。
还是看 QUIC,如果没有 Chrome 浏览器,你觉得 QUIC 如何展开?它可能连个灰度的地方都没有。HTTP/2 要先标准化才有其它。HTTP/2 标准化的难度不说,QUIC 如何迭代更新,不断发布补丁吗?补丁又以谁的名义发布?如果 IE 实现了 QUIC,微软提出 QUIC 有个 bugfix 要更新,如何说服所有实现了 QUIC 的客户端同步更新?
假设 QUIC 不是从 HTTP/2 以 Chrome 为平台逐步生长,假设它是学术界或国内大厂从 0 到 99 憋出来的独立协议,大概率也就完成 draft 或论文后止步于 99 了,其它都好,就是用不起来。
QUIC 作为单独的传输协议之所以获得了成功(其实也不很成功,目前非理性成分还很多,参见:QUIC 的阻力),恰在于 Google 在 HTTP/2,Youtube 内容,Chrome 浏览器之间做了闭环。从前端,到后台,传输,再到灰度机会,一家呵护所有,所以才能集大成,缺了任何环节,QUIC 是使不出来的。
奇怪的是,被普遍认定为真理的低耦合不适用了,这些元素之间耦合并不低。除此之外,QUIC 也不高内聚,与 TCP 只有一个版本,少量选项可协商不同,QUIC 的功能并不独立,就说多流复用,只是 HTTP 的特征而并非通用传输之必须。
QUIC 尚有征途要走,就更别提那些冒失的花式传输协议了,简单来讲,这些协议很难真正上线用起来,出自学术界或者云厂商的 KPI 驱动,显然,论文发表了,KPI 完成了,事情就结束了。
TCP 有很多显而易见的问题,这些问题都不难解决,可还是没人修正。双边成本太高了,而升级部署这种事在研发工程中的分量总是被退而求其次,虽然 SRE 在这方面更有经验,但作为实施方, SRE 不好介入开发者说服业务适配的过程,所以适配的工作需要开发者自己做,但又多少专门做传输协议的有能力快速掌握和修改业务代码呢?又或者这些工程师都是全栈,又有多少业务方允许向协议开发者开放自己的业务代码呢?改出新毛病谁负责,代码泄露谁负责?
不能指望新协议脱胎于模块化的好模型,我们要关注场景。我们总以为传输协议是独立的模块,脱胎于调研后的设计,这是我们基于分层模型对网络协议的静态误解。相反,传输协议只能在未来展现。在最开始,传输协议和应用在一起。它必须从解决了特定问题的特定应用里被抽出来,然后再被安放在分层协议栈的某个位置后,才能被称之为一个传输协议,而我们的教科书或 RFC 显然隐藏了这个历史过程,给人一种这个协议原本就是被专门设计出来后摆在那个特定层的假象。
我们现在想象 200 年前的发动机,总觉得它是一个烧煤的,发出巨响,冒着黑烟的大立方体,输出动力驱动一个轮轴…在接下来的 200 年时间里,发送机变成了现在小巧的样子。但实际上一开始并没有发动机的概念,最初的那个烧煤的大家伙纯粹是用来抽水的,而不是驱动轮轴的,人们不知道除了抽水它还有什么用。瓦特的那个民间故事意思很明确,最开始并没有蒸汽机,只有茶壶煮水。从这个现象开始,到这个现象被利用了很久后,才有了蒸汽机的形态,随后一点一点逐步发展,抽丝剥茧,将这些抽出来的公共的动力提供者部分逐渐装备在各种物件儿上,才形成我们如今的公路交通系统。
公路交通系统形成的过程被我们认为是自然而然的,若按网络分层模型那样理解,这简直不可思议。道路是物理层,汽车算应用层,中间还要有各类交通规则,交警,保险机构等,每个模块都事先知道自己处在什么位置,要完成什么目标,显然,历史并不是这么过来的。早期蒸汽机甚至会装在马车上推马,有了汽车后却没有交通规则,车前要站一个步行领航旗手指挥,而汽车的量产是很晚期的事,在这近 200 年时间里,100 多年前人们就知道了电池能提供动力,可电池列装到汽车上也就近几年的事,电池作为动力源后,整车的结构至少是外观就要起变化,以往的大鼻孔,大嘴巴前脸连自欺的美感都谈不上,因为不再需要进气出气了。道路从来都是挖了又挖,土路变水泥沥青,然后拓宽,再修高架隧道,省道变高速,如此反复。这一切颇似 TCP/IP 的过程。
我们试着反着来,同样是完成搬运工作,按交通系统的形成方式理解网络协议的演化,很多隐藏的故事才能被理解,合理的变成了不合理,不合理的反而合理了。为什么一个精心设计的,在仿真环境吞吐延迟吊打标准 TCP 的传输协议始终无法上线,因为方向错了。周边与之适配的环境要么尚未准备好,要么根本就没有需求。但凡老协议还能过得去,新协议又没能颠覆,安土重迁的上层应用很难被撼动。正确的方向是自上而下,由应用去推动公共部分的抽离,最终形成一个新协议。
最后再讲讲 TCP,上周的文章 TCP 疑难杂症解析 还差一个故事。我觉得有在这里要补上这个故事的必要,因为 TCP 可能是互联网(最初叫 ARPAnet)上唯一一个相对独立的协议,因为在 TCP 伊始,应用本就不多,更加幸运的是,这本不多的应用却有几乎完全相同的需求,TCP 只需要满足这些需求即可。虽然 TCP 没那么明显地脱胎于应用,但在它的下层,却分离出去一个 IP。
这次我将从稍微大的格局而不是 feature 细节展开,看看 TCP 的演化历程是否包含固定的原则或范式。
TCP(内置 IP 的那个原始 TCP,即 RFC675)最初的目标是为 ARPAnet 提供 “一个” 传输控制协议(译文就是 “TCP”),彼时 ARPAnet 承载的重要应用大致分两类,远程登录和文件传输(经典神书《TCP/IP 详解(卷 1 )》出版于 1994 年后,依然将 TCP 流分为交互数据流和成块数据流两类,分别对应远程登录和文件传输两类应用),这两类应用共同的需求都要保证数据保序且不能丢,这几乎是唯二需求,开发这样的传输控制协议不需要兼顾太多东西,这让事情变得简单。TCP 处理速度已远快于打字速度,对于文件传输,TCP 的亮点在于它简化了传输控制流程,性能并不在这两类应用的需求之列,TCP 在 1974 年非常优秀,这是原始 TCP 的情况,至于上周文中的流式抽象如何影响性能的,是 IP 分离很久以后,性能开始影响传输体验时的后话,而性能总是最后考虑的事。
彼时比性能更重要的是端到端原则的争论。原始 TCP 并非端到端协议是该争论的一个背景,从 TCP 分离出 IP 是该争论暂时的一个结论。
从头说起吧。以下摘录提供了初始背景:
TCP 伊始是一个贯穿整个网络的传输控制协议,也是 ARPAnet 上唯一的协议。 中间节点不能说全部,至少自己本地 local net 的 gateway 需要对 TCP 进行操作,当接入 TCP 端越来越多时,网络 gateway 维护的状态以及处理复杂性将指数级增长,而需要 gateway 处理 TCP 的情形又是小概率发生的。这值得吗?
考虑当时的背景,网络初建是服务于数据的,网络要为数据提供确保质量的传输服务而非后来的 “尽力而为”。可想而知,这种网络在每一跳都要 “确保传输”,这是端到端的反面。
争论点的关键在于两个方面,首先,是否所有的应用都需要确保传输,其次,是否有应用有确保传输以外的服务,而网络又是如何感知到这种需要以及如何满足。端到端的观点倾向于 “自决”,谁拥有必要信息多谁解决问题。
争论最终采纳了端到端原则,将复杂性推给了端侧,而网络保持简单,最终这个简单的网络核心就是 IP,它从 TCP 中被抽出来,保留了路由到目的地最基本的,无状态的功能。在论文 《系统设计种的端到端争论》中,下面的话值得体会:
The function in question can completely and correctly be implemented only with the knowledge and help of the application standing at the end points of the communication system. Therefore, providing that questioned function as a feature of the communication system itself is not possible.
端到端原则的隐喻是,网络不要针对特定应用设计功能,不要针对特定功能优化网络,这会减少其它应用的功能,降低其它应用的效率,同时带来一些棘手但必须要处理的麻烦。
一个现实中违反端到端原则的例子卷客们都知道,阿里的 HPCC(High Precision Congestion Control),它依赖网络节点的 INT(In-Network Telemetry),即便在规模有限的数据中心,据说也没能实际部署,另一个更普遍的例子是数据中心 PFC 反压,只要想想反压死锁就够了,分布式状态非常难以维护。但这些都是情有可原,后面涉及争议的另一面还会提到。
但提到另一个广域网上违反端到端原则的实例就有趣多了。广域网设备种类繁多,从防火墙到各类 DPI,LB,不一而足,但它们均对 TCP 进行了固有假设,从而实现自身的一些功能,比如报文分类,LB 策略,这些设备强依赖 TCP 报文的格式,所以遇到它们不认识的 “畸形 TCP” 报文,这些报文就会被丢弃,这意味着 TCP 很难做升级迭代。本来 TCP 端和 IP 网络是解耦的,TCP 也确实不绑定 IP 特性,但显然,IP 反过来绑定了 TCP 的特性,从而也锁死了 TCP 协议。
但这并不意味着端到端原则就是绝对正确的,事情发展,必有反复。
随着互联网规模扩大,复杂性被成功压制到端侧足够久了,另一些问题浮上水面。一个是安全,一个是性能。
1986 年的拥塞崩溃同时涉及到了两者。一方面,网络不再可用,这是安全问题,另一方面,即使网络可用,也是龟速,这是性能问题,其原因正是端到端原则。很幸运,“端到端” 的拥塞控制机制随后被引入 TCP,这是 TCP 进化史上的重大事件。但大约 10 年后的事在 TCP 的覆盖范围以外。
到了 2000 后,互联网迅速膨胀,简单的网络核心很快成了一个公平但低效的地方,在这里公平是个贬义词。端到端原则只是互联网的一面,另一面是网络中立性原则,两个原则互为因果,就像双星系统一样纠缠。
若互联网仅恪守端到端原则,则网络必须中立,反过来也一样,网络中立,则必须将定制逻辑压到端侧,但世界显然不是非黑即白。如果网络完全中立,任何流量可在任何时间在任何位置注入网络,这意味着将任意接收端暴露于任意强度的攻击之下,没有规则,没有围墙,没有警察,能保护自己的只有自家的一道门。另一方面,即使这些流量都是无害的,当它们同时经过共享路径时,网络拥塞将严重降低互联网的连通效率和传输效率。
更为现实的是,互联网本身就是人类社会的映射,理想的去中心化互联网从来没存在过,运营商要盈利,内容提供商要盈利,国家,种族之间存在屏障,网络中立几乎就是奢望。
因此,必须稍微违反一些中立性原则,对某些流量以优待而对另一些流量以惩罚。
你看,TCP 一开始是个贯穿整个网络的大杂烩,胖网胖端,端到端原则的落实让它更合适做端到端协议,瘦网胖端,但是到了最后 TCP 依然是个贯穿整个网络的大杂烩,那个完全理想化的 TCP 在哪里?“交换机支持 TCP” 这种说法是错误的,因为教科书会告诉你即使三层交换机也与四层 TCP 无关,可现实显然不是这样。
如果你实现了一个传输协议,你是想让交换机与自己有关还是无关呢?QUIC 甚至将报文头也加密的做法明显是想让交换机与自己无关,以便今后可以安静地升级迭代,但这是不是意味着同时也放弃了中间节点提供的某些服务呢?总之,如果你想 “构建”(我依然用构建这个词,假设你能一瞬间将它构建出来) 一个各方面都足够好的传输协议,你不想把它做成大杂烩都不行。
本文开头描述的我的疑问,至此得到了一个解答。一个专业的精锐团队是高内聚的团队,这类团队设计的传输协议旨在不绑定任何应用,不对应用做任何假设,他们希望自己的传输协议是应用无关的,是交换机无关的,而这是不可能的,他们不知道一个大杂烩的传输协议意味着什么,或者他们从根本上就不认可大杂烩的存在,与脱胎于应用的大杂烩传输协议相比,这种专业的传输协议显然更不接地气。
比如,未来的流媒体传输协议标准几乎一定会内置编解码相关的特性和操作(参考这篇:有损传输实例),但当大多数流媒体已经被这个未来的协议承载的时候,它或许就开始甚至已经千疮百孔了,就好像当超过一定阈值的流量被 TCP 承载时,TCP 却越来越千疮百孔一样。
这是悠悠岁月淌过的现实,哪有什么倚天宝剑,只求岁月静好。
和网络协议无关的题外话,说两句,我的历史观,也是本文的动机。
人们倾向于事后为发生过的事做总结,给这件事勾勒一个轮廓并赋予其意义,就好像它是一个不可分割的整体。比如二战,人们为它选择一个开始标志和结束标志,以将它从历史中识别出来,为它贴上一个标签,并未该标签所指代的实体增加各种属性。这就和我们现在的网络教科书在 “事后” 将 TCP/IP 勾勒成模块化的分层模型一样。
但历史的当下并没有这样的轮廓,问一个 1943 年的苏联人,他不知道自己正在经历二战,他也不知道所谓的各种主义,一切都是大杂烩,毫无规则,毫无轮廓,大多数人跟平时生活没什么两样。
历史留下了可供人进行分析综合的结果,而抹去了得到这样结果的过程,因此历史可以被任意解释,在某种意义上(我的历史观),历史并不存在。
将每一个事件设成一个点,而任意两个件事件之间的一个关系设成连接这两点的一条边,那么整个历史就是一张网。这张网是精确的,还是模糊的?
我们已经把历史抽象成了一张网,可用几何拓扑关系来分析它。这张网有离散的孤岛吗?这张网有尚未发现的隐藏点吗?这张网的某两点之间有人们尚未理清关系的隐藏边吗?答案无疑都是肯定的,因为点和边构成的网只是包络,总有一些事件被遗忘,消失在历史中,连尘埃都不是,否则历史就是一个实心球而不是一张网了。
那么定论是,连接网中任意两点的路径有无数条,每个事件都是客观存在的,它们被遗忘从而成为隐藏的点却是主观的,因此除了有限的已经在网络中路径外,还有无数条隐藏的路径,它们经由被遗忘的隐藏的点被路由。关键点在于,每一条或显式或隐藏的路径,都是历史事件的一种解释。
历史可以被任意解释,那么历史还精确吗?历史作为一个对象,真的还存在吗?
历史不需要解释,历史是实在(reality)。随着隐藏点不断被点亮,随着解释的增多,这张网越繁复,点边越多,作为对象的历史就越厚重,但作为实在的历史却依然还是那一个,我们永远不可能还原它。
我聊历史,讨厌聊主义,我喜欢分析事件背后的关联,这是我的历史观。在这个历史观的指引下,我才建议换个视角,自上而下再看一遍 TCP/IP 协议栈,幸好 TCP/IP 只诞生了 40 多年,我们有能力尽力关联起更多事件,连接更多边,这张网最终会被连成纷乱的大杂烩,毫无规则,毫无轮廓,处处偶然,伸向永远,但只有这样才越来越逼近历史走过的真实的路。
推荐一本书《技术的本质-技术是什么,它是如何进化的》,摘录其中一段话结束本文:
技术的进化根本就没有可以预先决定的确切顺序。我们无法事先就知道哪个现象会被发现并转化为新技术的基础;也无法在巨大的组合可能性中事先指出哪种组合会被创造…作为这些不确定性的结果,技术体的进化具有历史偶然性。它依赖于历史上的小事件…这些小的偏差并不随时间均匀出现…如果历史可以重演…也因此会发展大致相同的技术。但是它们出现的顺序和时机将可能不同,这将导致经济和社会历史变得与现在不同。
浙江温州皮鞋湿,下雨进水不会胖。