前面谈到互联网从早期对等通信模型转入后来内容分发模型后的一系列问题,诸如拥塞,安全等,本文谈谈关于性能的更普遍方面。
TCP/IP 祖师爷 1974 年的开山论文 A Protocol for Packet Network Intercommunication 以及随后 RFC675,标志着 TCP/IP 的正式诞生,在此之前还有一个里程碑事件,即 RFC33 NCP 标准化。
RFC33 解决了分布式通信问题,而 RFC675 解决了异构联网问题,基本奠定了后来互联网的格调,三岁看老,很多问题都要从幼年寻找答案并启发方案。
引论文 “CONNECTIONS AND ASSOCIATIONS” 小节初段:
Much of the thinking about process-to-process communication in paket switched networks has been influenced by the ubiquitous telephone system. The HOST-HOST protocol for the ARPANET deals explicitly with the opening and closing of simplex connections between processes [9],[10]. Evidence has been presented that message-based “connectionfree” protocols can be constructed [12], and this leads us to carefully examine the notion of a connection.
在这种背景下,虚电路是自然的,NCP 甚至强制约束了 256 个 “链路” 的用法(链路和 RFNM 机制的目的是防止单个用户使 IMP 或主机过载,详见 RFC33),另一方面,1970 年代 TCPIP 沙漏模型尚未形成,端到端观点则刚刚获得认可。IMP 只是一台普通主机,它的主要职责是转发它所携带主机的数据到目的地,它必须能清晰对应每一对源和目标,这一系列约束让 “连接” 和 “流” 自然对应。
由于当时的资源限制和以对等通信(类似电话)为主的网络使用方式,SPF 算法几乎是唯一路由方案,换句话说,当时的分布式网络路径是 Active-Standby 模式,而不是 Active-Active 模式。对等通信模型下的流量分布非常对称且均匀(接近正态分布),最短路径并不会出现后来内容分发模型下的拥塞问题(参考高速公路导航导致的拥堵)。只要路由没有重收敛,早期单核主机路由器基于目标的逐跳转发非常轻松且自然就能完成,这进一步加深了 “同流同路径”(否则,除了唯一的最短路径,没有其它路径) 的观念。
从早期数据包头地址格式以及后期 IP 路由对流的甄别方式可以看出这里面发生事件的前后关联。
RFC33(NCP) 形成了 40bit 地址结构,非常类似电话号码:
24 8 8+----------------------+-----------+----------+| User Number | | |+----------------------+-----------+----------+| |___AEN||___HOST numberFigure 3 A typical socket
RFC675(TCP) 继承了它(同时继承了 Listen,Accept 原语,但双工语义改变了,不再需要创建两个方向的连接,这反而更像 “打电话” 了,这属于端侧行为,很重要但与本文关系不大,放在括号里),随后 RFC791/793 将该地址最终标准化为 IP 地址和端口号,TCP,UDP 端口号位于同一位置,这方便路由器找到它们却无需关注具体协议。
RFC791 规范的 IP 协议最终确定了网络的行为,网络节点尽力而为无状态转发,数据包携带所有地址,路由器不保存任何关于具体数据包所属数据流的状态信息。这种转发结构具有非常大的扩展弹性,转发方式取决于路由算法,最初只有 Unicast,随后 Anycast,Multicast 非常容易加入。但由于霸王协议 TCP 的强制顺序流约束以及它事实上确实很容易被捕捉到的流特征(五元组非常容易被路由器获取),它竟然自己僵化了。
当路由器以及主机发展到非常善于并行处理时,TCP 无法享受这种高效率,反而拖慢了系统,同样的阻滞因素也限制了多路径,ECMP 路由,负载均衡,数据中心传输等技术的发展。
如果在路由器交换机保留流的语义,AQM,包分类等与拥塞控制有关的算法就不得不加权关于流的一切特征,包括不限于流的长短(大象流,突发流),流目标聚合,流源聚合,虽然路由器仍然不保存状态,但这些与包归属相关的流式计算却持续消耗计算资源(常见的对每一个包做 hash 分类,然后调度)。
省是省不了的,问题是资源消耗在哪里以及拿什么代价来换。按照沙漏模型和端到端的原则,网络不应该对数据包提供不需要的功能和触动,这体现在每个数据包都要经过复杂的包分类方面。
若按照每包分发而不是每流分发,拥塞也同时分发掉了,突发拥塞导致的排队时延抖动被次优路径稍微久但稳定的传输时延平滑掉了。去掉了顺序流约束,多路径,packet spray,概率路由便和 SPF-Unicast 一样自然而然。当我们放宽 SPF 中 Shortest 的定义,只要接近目的地的下一跳,都有机会传输数据包,传输流量的大小取决于路径的长度,当传输协议去除了顺序流约束,这些松散路由造成的乱序全由端主机负责。
交易达成了,路由器上复杂的包分类,流映射造成的计算资源消耗自然而然转移到端主机了。这笔交易是划算的,因为总有端主机不需要进行这些计算,同时拥塞的消除也提升了体验。
还是那个意思,我不打算用一种富含技巧性的方法对网络进行思想重构,而是重新评估,因为背景已经变化了。回到 1970 年代,源自打电话的连接流语义,源自互联异构网络(互联网宗旨之一就是利用已有网络,而已有网络总是异构的)的刚需,人们操心的重心自然不同。这让我回想起 1990 年代关于经理们用鼠标线联网的传说。
只有一条鼠标线,一条串口线时,没人会想到排队调度和拥塞控制,更不会有人设计一个专门进行排序重组的保序软件层,人们甚至会采用丑陋的硬编码,一个字符一个字符停等,只求一个完整的 “hello” 通过鼠标线显示在对方屏幕上这伟大时刻早点到来,等到这个过程变得司空见惯时,等到能买得起双绞线,光纤,交换机的时候,软件早已僵化,模块间千丝万缕的早期关联使其牵一发而动全身。这大概就是协议演化的过程,RFC817 也提到,程序员很难一开始就设计一个完备的适应未来的协议,任何协议都局限在当前它出现的背景之下。
关于 TCP/IP 底层架构的演进到本文为止告一段落,下面准备扯扯伯纳斯李,HTTP 登场,互联网为此而改变。
大卫 D 克拉克 曾经评论 “性能需要不完全的功能来换”,能理解这句话的人并不多,人们更加擅长在黑灯瞎火的半夜排查 TCP 吞吐非常差的这类问题,最终定位为 “路由器并行处理了数据包导致了大量乱序触发了大量快速重传”,然后自我感觉良好。人们厚今薄古,总认为 RFC33,675,817 这种过去的东西非常空洞,人们天然认为只有当代的科学技术才是第一生产力,过去的终成历史,属于没意义的文科范畴,持这些观点的人,有一个是一个,都是 SB。
浙江温州皮鞋湿,下雨进水不会胖。