为什么 Google 最后放弃了 TCP?

12 阅读6分钟

TCP 已经五十多岁了。

但它真正奇怪的地方不是“老”,而是:

它越来越难改了。

不是没人想改。

这些年 TCP 有过很多漂亮的升级:SACK、ECN、TCP Fast Open、Multipath TCP……问题是,代码写完了,标准有了,操作系统也支持了,最后却经常死在一个地方:路上。

这里的“路”不是网线,而是互联网中间那些你平时看不见的设备:防火墙、NAT、负载均衡、代理、企业网关、IDS/IPS。

它们不是 TCP 的设计者,却慢慢成了 TCP 的“隐形设计者”。

一个 RTT 的优化,为什么这么难?

TCP Fast Open 就是一个很典型的例子。

普通 TCP 要先三次握手,再传数据。TFO 的思路很简单:

能不能在 SYN 里直接带数据?

这样就能少等一次 RTT。

Linux 很早就支持了 TFO,RFC 7413 也在 2014 年正式发布。

技术上没什么问题。

问题在于:中间设备可能不认识它。

防火墙看到特殊 TCP 选项,可能直接丢弃;某些 NAT 或网络设备也可能错误处理。

于是 TFO 面临一个非常尴尬的现实:

不是不能用,而是不知道这条路能不能用。

所以它甚至需要 fallback:先试,如果发现这条路径不支持,就记住,下次老老实实走普通 TCP。

一个新特性的最佳实践,最后变成了:

如果互联网不喜欢你,那就假装自己不存在。

这其实就是 TCP 最大的问题:

两端可以升级,但中间的人不一定同意。

TCP 最大的问题不是老,而是僵化

这叫Protocol Ossification——协议僵化。

TCP 最初设计的时候,中间设备没那么聪明。

后来互联网越来越复杂,防火墙、NAT、代理、负载均衡器越来越多,它们开始观察 TCP 的 flag、option、序列号和连接状态。

慢慢地,一些原本只是“实现细节”的东西,变成了设备默认依赖的东西。

于是出现了一个非常荒诞的现象:

你修改协议本身没有问题,但你无法保证整个互联网接受你的修改。

这就是 Middlebox Ossification。

中间设备甚至不需要参与协议设计,只需要在某个位置说一句:

“我不认识这个。”

整个互联网就得考虑它。

所以 TCP 不是不能进化,而是:

每一次进化,都要先征得整个互联网的同意。

那不用 TCP 呢?

其实有人试过。

SCTP 在 1998 年就出现了,支持多宿主、多流、消息边界等特性。

但它有一个致命问题:

它既不是 TCP,也不是 UDP。

它是独立的 IP 协议。

于是防火墙、NAT、负载均衡器就开始犯难:

TCP?

不是。

UDP?

也不是。

那是什么?

SCTP:

协议号 132。

中间设备:

“没听过。”

于是一个很残酷的事实出现了:

一个协议技术上再漂亮,也不意味着互联网会让它通过。

这给 QUIC 上了非常重要的一课:

直接发明一个新的 IP 传输协议,可能比修改 TCP 更难。

所以 QUIC 选择了 UDP

UDP 很简单。

简单到几乎没有什么值得中间设备“理解”的东西。

它不是所有网络都放行,但相比一个全新的 IP 传输协议,它已经是现实互联网里最成熟的入口之一。

于是 Google 的工程师想:

TCP 的可靠传输、拥塞控制、多路复用都很好。

UDP 又足够普遍。

那我自己重新造一套。

于是 QUIC 出现了。

QUIC 本质上不是升级 TCP,而是绕开 TCP。

它借 UDP 作为外壳,在里面重新实现可靠传输、拥塞控制、流量控制、多路复用和 TLS。

这不是多么浪漫的设计。

更像是一条被现实逼出来的绕路:

TCP 改不了,那就不改 TCP。

为什么 QUIC 要把很多东西加密?

很多人认为 QUIC 加密只是为了安全。

其实还有一个非常重要的原因:

防止下一次协议僵化。

TCP 的教训是:

你让中间设备看得越多,它们就越容易开始依赖这些东西。

今天只是“观察”。

明天就可能变成“依赖”。

后天你想修改:

“不行,我们的设备不支持。”

所以 QUIC 尽量把传输层内部状态隐藏起来。

中间设备知道:

这里有一个 UDP 流量。

但不应该轻易看到 QUIC 内部的包号、ACK 范围、Stream 状态等细节。

这就是所谓的:

Ossification-resistant encryption——防僵化加密。

它的意义不仅是:

防黑客。

还有:

防止网络设备把今天的协议细节,变成明天无法修改的枷锁。

但 QUIC 也付出了代价

QUIC 绕开 TCP 的同时,也绕开了 TCP 五十多年积累下来的基础设施。

TCP 有成熟的内核实现、网卡卸载、GRO/GSO、TSO、零拷贝以及完整的监控体系。

QUIC 大量运行在用户空间,传输、加密、ACK、重传等逻辑都需要自己处理。

所以它并不是免费的。

CPU 成本、实现复杂度、运维成本都会增加。

另一个代价是可观测性。

以前网络工程师抓个 TCP 包,看 SEQ、ACK、Window、SACK,很多问题就能判断。

现在 QUIC:

抓包。

打开工具。

一堆密文。

不是说 QUIC 无法调试,而是:

整个网络可观测性体系都需要重新适应它。

所以 HTTP/3 为什么选择 QUIC?

不是因为 TCP 不能用了。

也不是因为 QUIC 在任何情况下都比 TCP 快。

更不是因为 QUIC 是一个完美协议。

真正的问题是:

TCP 越成功,越难改变。

几十年来,防火墙围着它建,NAT 围着它建,负载均衡器围着它建,操作系统围着它优化,网卡围着它做硬件卸载。

最后,这些东西共同形成了一堵墙。

于是出现了互联网最有意思的悖论:

TCP 越成功,越没人敢改它。

这就是为什么 QUIC 看起来不像 TCP 的“下一代”,反而像是从 TCP 旁边绕过去的一条新路。

TCP 是老水管。

QUIC 是从墙外重新接的一根管子。

新管子不一定更漂亮,也不一定更便宜,但至少有一件事:

它不用先说服整栋楼的人,同意你换水管。

所以 TCP 真正“死掉”的,不是生命。

它今天依然活得很好。

真正死掉的是:

它作为一个可以自由进化的协议,正在失去自由。

而 QUIC 的意义,也不只是“比 TCP 更快”。

它更像互联网对一个现实问题的回答:

既然旧路越来越难走,那就换一条路。

至于这条新路,几十年以后会不会也变成一座谁都不敢修改的老城?

那就是下一代工程师的故事了。

640.png