导读:TCP已经死了吗?从技术角度来观察一下。
HTTP/2 已经在 84% 的生产系统中运行。大多数工程师认为它解决了 Web 的性能问题,但是事实并非如此。
HTTP/2 无法解决的问题
HTTP/2 引入了多路复用技术——通过单个 TCP 连接发送多个请求。在此之前,浏览器为了加快页面加载速度,通常会打开 6 到 8 个并行连接。HTTP/2 简化了这一流程。一个连接,多个数据流,压缩头部信息。看起来是一个完美的解决方案。
问题出在TCP上。
TCP保证数据包按顺序传输。如果某个数据包在传输过程中丢失,TCP会缓存其后的所有数据包,并等待丢失的数据包被重新发送。即使这些缓存的数据包属于完全无关的请求,也无关紧要。所有数据包都会等待。
这叫做队首阻塞。
HTTP/2 通过一个 TCP 连接复用 20 个数据流,一旦丢失一个数据包,所有 20 个数据流都会被阻塞。不是阻塞丢失数据包所在的那个数据流,而是所有数据流。这些数据流之间没有任何关联,但 TCP 协议并不知道这一点。它只看到一个连接被阻塞,然后就把整个连接都阻塞了。
在丢包率低于 2% 的情况下,HTTP/2 的性能不如 HTTP/1.1。在丢包率达到 12% 时,HTTP/2 完成一次传输需要 113 秒,而 HTTP/3 只需 21 秒即可完成。这并非微小的差距。HTTP/2 的速度比它原本要取代的协议慢了 81.5%。
HTTP/3 的不同之处
HTTP/3 并没有试图修复 TCP,而是用一种叫做 QUIC(快速 UDP 互联网连接)的东西完全取代了 TCP。
QUIC 基于 UDP 协议运行。大多数工程师第一次听到这个说法时,都会认为这是一个糟糕的设计。UDP 是无连接的,而且不可靠。它没有顺序保证,只是发送数据包,并不关心数据包是否到达。
但这正是关键所在。QUIC 以 UDP 为基础,重建了可靠性、拥塞控制和流量控制机制——但与 TCP 有一个关键区别:QUIC 本身就支持流式传输。
在QUIC协议中,当数据包丢失时,只会影响该数据包所属的数据流。其他所有数据流都会立即继续处理。TCP协议无法解决的队头阻塞问题根本不是QUIC协议的问题。
QUIC 比 TCP 做得更好的三件事
首先是流独立性,我们刚才已经介绍过了。即使流 3 丢包,流 1、2、4 到 20 也不会中断。
第二点是更快的握手。使用 TLS 的 TCP 连接需要 3 次往返才能传输一个字节的应用程序数据。客户端和服务器需要先建立 TCP 连接,然后再协商 TLS 加密。QUIC 将这两者合并为一次握手,只需 1 次往返。对于之前连接过的服务器,QUIC 可以零次往返发送应用程序数据——因为它会重用上次会话的加密状态。
Cloudflare 在生产环境中对此进行了测量。与 HTTP/2 相比,HTTP/3 将首字节响应时间缩短了 12.4%,即 176 毫秒对比 201 毫秒。在高流量系统中,这种差异会更加显著。
第三点是连接迁移。TCP 连接由四个要素标识:源 IP 地址、源端口、目标 IP 地址和目标端口。如果其中任何一个要素发生变化,连接就会断开。这种情况会在移动用户从 Wi-Fi 切换到蜂窝网络时发生——他们的源 IP 地址会发生变化,TCP 连接需要重新建立。
QUIC 通过与 IP 地址无关的连接 ID 来识别连接。即使在传输过程中切换网络,连接也能无缝衔接。服务器会识别相同的连接 ID 并继续传输。对于频繁在不同网络间切换的移动用户而言,这省去了大量的重新连接开销。
QUIC 的底层工作原理
每个 QUIC 数据包都包含连接 ID、数据包编号、加密有效载荷和流帧。与 TCP 不同,QUIC 会对数据包元数据(包括数据包编号本身)进行加密。因此,攻击者无法通过数据包计数或时间模式推断流量行为。
丢包检测的工作原理是跟踪已发送的数据包及其确认信息。当确认信息在超时时间内未到达时,QUIC 会将数据包标记为丢失并重新发送。重新发送的数据包会获得新的数据包编号——这与 TCP 不同,TCP 的重传会重用原始序列号。这一点至关重要,因为它消除了歧义。在 TCP 中,当收到重传数据包的 ACK 时,您无法始终确定该 ACK 是针对原始传输还是重传。而在 QUIC 中,每个数据包都有一个唯一的编号,因此每个 ACK 都是明确的。
更精确的往返时间测量结果可直接用于改进拥塞控制。QUIC 在用户空间而非内核中实现拥塞控制。这意味着 Cloudflare 或任何其他运营商无需等待 Linux 内核更新即可部署改进的拥塞控制算法。
HTTP/3 何时胜出,何时未胜出
HTTP/3 并非在所有情况下都更优。它取决于用户实际所处的网络环境。
当丢包率高于 2% 时,HTTP/3 具有明显的优势,这涵盖了大多数移动网络、拥塞的 Wi-Fi 网络和长途连接。对于小于 50KB 的小文件传输,HTTP/3 也更胜一筹,因为更快的握手速度可以显著缩短请求总时间。此外,当用户在会话期间切换网络时,HTTP/3 也同样具有优势。
在数据中心之间通过专用光纤传输的低延迟、无延迟连接上,HTTP/2 仍然更胜一筹。在丢包率接近于零的纯净网络上,TCP 的内核级优化和成熟的工具链优于 QUIC 的用户空间实现。对于干净网络上超过 1MB 的大数据传输,握手节省的时间微乎其微,此时 TCP 优化的内核代码优势就显现出来了。
客户端如何发现 HTTP/3
服务器不能直接开始使用HTTP/3协议。客户端需要先知道它可用。
客户端首次连接时,使用基于 TCP 的 HTTP/2 协议。服务器会返回一个 Alt-Svc 头部,表明 UDP 端口 443 上支持 HTTP/3。客户端会缓存此信息。下次请求时,客户端会首先尝试 HTTP/3,如果 QUIC 不可用,则回退到 HTTP/2。
这种回退机制的重要性远超大多数人的想象。UDP 流量会被企业防火墙、移动运营商以及不支持 QUIC 协议的中间设备拦截或限速。目前,35% 的网站支持 HTTP/3,但只有约 40% 的符合条件的流量实际使用了 HTTP/3。其余流量则会静默回退到 HTTP/2。一个正确的 HTTP/3 实现必须始终妥善处理回退机制——如果 QUIC 失败,用户不应该察觉到任何异常。
这对身为工程师的你意味着什么?
如果你运行的是面向公众的服务,并且你的用户使用移动设备或网络环境不稳定,那么启用 HTTP/3 就非常值得。所有主流 CDN,例如 Cloudflare、Fastly 和 AWS CloudFront,都支持 HTTP/3。对于大多数团队来说,启用 HTTP/3 只需要更改配置,而无需重建基础设施。
你这边需要做的就是在负载均衡器上开放 UDP 端口 443,并且源服务器或 CDN 支持 QUIC 协议。客户端由浏览器处理——Chrome、Firefox 和 Safari 都支持 HTTP/3。
如果你的流量主要在数据中心之间传输,或者你的用户使用可靠的有线连接,那么 HTTP/2 仍然是更好的选择。在做决定之前,请务必了解你的丢包率。
自 1974 年以来,TCP 一直是互联网的基石。QUIC 并没有抛弃 TCP 的所有成果——它保留了 TCP 中行之有效的部分,修复了内核层面无法修复的问题,并将其应用于真正能够提升性能的领域。这并非激进的变革,而是优秀的工程实践。
希望你对HTTP3的工作原理有了清晰的了解。感谢大家阅读。
作者:手扶拖拉斯基
本篇文章为 @ 场长 创作并授权 21CTO 发布,未经许可,请勿转载。
内容授权事宜请您联系 webmaster@21cto.com或关注 21CTO 微信公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。
请扫描二维码,使用微信支付哦。