2.8 QUIC 设计原理与实践
QUIC(Quick UDP Internet Connection,快速 UDP 网络连接)是一种基于 UDP 封装的安全可靠传输协议,旨在取代 TCP,成为新一代互联网的主流传输协议。
许多人可能认为是 IETF 在推动 QUIC 替代 TCP。实际上,QUIC 的开发始于 Google。
早在 2013 年,Google 就在其后端服务(如 Google.com 和 YouTube.com)及 Chrome 浏览器中启用了名为“QUIC”(业内称为 gQUIC)的全新传输协议。2015 年,Google 将 gQUIC 提交给 IETF,经 IETF 规范化后的 QUIC 被称为“iQUIC”。早期的 iQUIC 有多个“草稿”版本,如 h3-27、h3-29 和 h3 v1 等。2018 年末,IETF 发布了基于 QUIC 协议的最新一代的互联网标准 HTTP/3。
图 2-26 展示了各个 HTTP 协议的区别。可以看出,HTTP/3 最大的特点是:底层基于 QUIC 协议,默认集成了 TLS 安全协议。
图 2-26 各个版本的 HTTP 协议对比
2.8.1 QUIC 出现的背景
QUIC 出现之前,HTTP 使用 TCP 作为可靠数据传输的底层协议。
作为四十年前开发的传输层通信协议,TCP 的设计者显然没有预见今天移动设备盛行的场景。在当今复杂的移动网络环境中,TCP 存在先天的设计缺陷,集中在以下几点:
- 建立连接时握手延迟大:HTTPS 初次连接(TCP 握手 + TLS 握手)至少需要 3 个 RTT 才能建立。
- 队头阻塞问题:以 HTTP/2 为例,多个数据请求在同一个 TCP 连接上所有 stream(流,HTTP/2 传输的数据单元)必须按顺序依次传输。如果一个 stream 的数据丢失,后面其他的 stream 将被阻塞,直到丢失的数据被重传。
- TCP 协议僵化问题:作为一个运行了接近 40 多年的协议,许多中间设备(如防火墙和路由器)已经变得依赖某些隐式规则,打补丁或者说推动 TCP 协议更新脱离现实。
2.8.2 QUIC 的特点
在汲取 TCP 的设计经验以及现在的网络环境因素影响,QUIC 基于 UDP 实现了一种全新的可靠性传输机制,具有更低的延迟和更高的吞吐量。
下面列举 QUIC 的部分重要特性,这些特性是 QUIC 被寄予厚望的关键。
1. 支持连接迁移
当用户网络环境发生变化,这在移动端相当普遍,例如 WIFI 切换到 4G 时,TCP 基于四元组的方式无法保持连接的存活。而 QUIC 由于使用 Connection ID 标识连接,当源地址发生改变时,连接不受环境变化影响,因此 QUIC 可以实现网络变化的无缝切换,从而保证连接存活和数据正常收发。
图 2-27 QUIC 支持连接迁移
2. 低时延连接
以 HTTPS 请求为例,即使是最新的 TLS 1.3 协议,初次连接也至少需要 2-RTT 才能开启数据传输。此外,像 TCP Fastopen 类补丁方案,由于协议僵化原因,实际上不会在复杂网络起到作用。
QUIC 内部集成了 TLS 安全协议,无需像 TCP 先经过三次握手,再经过 TLS 握手才开启数据传输。QUIC 初次连接只需要 1- RTT 就能开启数据传输。
图 2-28 不同协议开启数据传输时,需要的 RTT数
3. 可插拔拥塞控制
笔者曾推动升级某核心网络系统的 TCP 拥塞控制算法,过程艰难,主要因为需要升级操作系统内核版本。
大多数 QUIC 实现工作在用户空间,支持灵活“插拔”不同的拥塞控制算法,如 Cubic、BBR 和 PCC 等。这让工程师在无需深入内核开发的情况下,能灵活调整可靠传输机制和拥塞控制策略。如 Cloudflare 开发的开源 QUIC 实现 quiche,提供了 setSendAlgorithm 方法,工程师可直接选择合适的拥塞控制算法,无需经过操作系统内核。
4. 降低对丢包的敏感度
先来看 HTTP/2 Stream 的处理。
如图 2-29 所示,若一个属于 Stream2 的 TCP 数据包丢失(如图中标记为 5 的圆圈),将导致后续数据包的传输阻塞。该问题就是业界常常提到的“队头阻塞”(head-of-line blocking)。
相比之下,QUIC 为每个 Stream 设计了独立的控制机制,Stream 之间没有顺序依赖。这意味着,如果一个属于 Stream2 的 UDP 数据包丢失,它只会影响 Stream2 的处理,不会阻塞 Stream1 和 Stream3 的传输。
这样的设计有效避免了 TCP 协议中的队头阻塞问题。
图 2-29 QUIC Stream 的设计减小了丢包的影响
此外,还需提及 QUIC 实现的另一个特性 —— QPACK。QPACK 通过更高效的头部压缩技术,减少了网络传输中的冗余数据量。这种压缩机制不仅提升了数据传输的效率,还能缓解前面提到的“队头阻塞”。
经过上述全方面的优化设计,QUIC 确保了在当今网络环境中比 TCP 更安全、更快速的连接以及更高的传输效率。
2.8.3 QUIC 实践
笔者在本文中花了大量篇幅探讨和赞美 QUIC 协议。那么,QUIC 在实际应用中的表现究竟如何呢?
说一千道一万,不如动手做一遍。2022 年,爱奇艺基础架构团队针对 HTTP/1.1、HTTP/2 和 HTTP/3,在不同网络条件测试它们之间性能差异。笔者将测试数据在此分享,供读者参考。
从请求耗时表现来看(图 2-30),相同的网络质量下,HTTP/3 的耗时比 HTTP/2 降低了近一半,证明了上述的讨论不虚。
图 2-30 不同网络质量下,各协议耗时表现(耗时单位 ms)
不过,测试中也发现了一个值得注意的问题:根据图 2-31 所示的网络请求成功率来看,HTTP/3 的失败率明显高于 HTTP/2。笔者“猜测”有两方面的原因:
- 某些网络环境(如网络设备配置不当、防火墙规则限制)下,UDP 数据包更容易被丢弃或阻断。
- QUIC 作为较新的协议,虽然发展迅速,但其在一些边缘场景(如复杂的企业网络、旧版网络设备等)中的兼容性和适应性还是不够完善。
图 2-31 不同网络质量下,各协议失败率表现
综上所述,无论是在服务端还是客户端,集成 QUIC 协议并非一件易事:
- 服务端层面:不仅需要适配 QUIC 协议,还要确保与 TCP 协议兼容。此外,TCP 经过多年的深度优化,引发了一个问题:“QUIC 在实际应用中的效能表现是否能够与 TCP 相媲美?”。
- 客户端层面:面临适配与收益之间的成本权衡。采用 QUIC 协议的客户端需要具备降级容错能力,并做好准备在较长时间内同时维护新旧两种网络库。