QUIC 原理与 HTTP/3
QUIC 原理与 HTTP/3
一个 HTTP/2 网站在弱网下为什么越来越慢
某视频网站 2018 年部署 HTTP/2。技术团队很高兴:1 个 TCP 连接多路复用,50 个资源并发,理论加载时间砍半。
实际效果:PC 端 4G 网络下,网页加载时间从 1.5 秒降到 1.4 秒——几乎没变化。手机端 4G 弱网下反而变慢。
抓包分析:HTTP/2 多路复用是应用层多路,底层还是一个 TCP 连接。弱网下丢包 5%,TCP 重传阻塞整个连接——一个包丢,所有 HTTP/2 流都卡住。HTTP/2 的"多路复用"在弱网下失效。
解决方案:用 UDP 之上的可靠协议——QUIC。
QUIC 在 UDP 之上实现了"每个流独立可靠传输",单个流丢包不影响其他流。弱网下性能比 HTTP/2 提升 30%+。
这一章讲 QUIC 怎么解决 HTTP/2 的队头阻塞、QUIC 的关键创新、HTTP/3 怎么用 QUIC、真实部署的演进。
问题一:HTTP/2 的"假"多路复用
HTTP/2 把一个 TCP 连接上的多个 HTTP 请求/响应拆成二进制帧,每个帧带 Stream ID 标识属于哪个请求。多个请求的帧交错传输到对端——这就是多路复用。
问题:所有帧都跑在同一个 TCP 连接上。TCP 不知道应用层的流 ID,只看到一个字节流。
TCP 队头阻塞场景:
时刻 0: 服务器发出 Stream 1 的帧 1-50
时刻 1: 服务器发出 Stream 2 的帧 51-100
时刻 2: 服务器发出 Stream 3 的帧 101-150
时刻 3: 帧 75(Stream 2)丢失
后果:TCP 触发重传
→ 客户端必须等帧 75 重传到达
→ 即使帧 76-150(Stream 2、3 后续)已到达客户端也无法交给应用
→ Stream 1 后续的帧也被卡住
→ 整个连接的所有流都被阻塞根因:TCP 提供了"字节流"的可靠性,任何字节丢失都要重传,后续字节必须等。HTTP/2 的应用层多路复用无法绕开这个底层约束。
弱网下(5% 丢包率)HTTP/2 性能可能比 HTTP/1.1 还差——HTTP/1.1 至少能开 6 个 TCP 连接分散风险,HTTP/2 反而绑定到一个连接。
问题二:QUIC 怎么"真"多路复用
QUIC 的核心思想:用 UDP 替代 TCP,自己实现可靠传输。可靠性不是按"字节流",而是按"流"。
QUIC 协议栈:
图注:QUIC 在用户态实现,拥塞控制算法可热更新,不依赖内核。
QUIC 传输层的关键设计:
1. 独立的可靠流:
每个 QUIC 流是独立的可靠通道。流 A 丢包只阻塞流 A,不影响流 B、C、D。
图注:每个 Stream 独立可靠传输,Stream A 丢包不影响 Stream B。QUIC 流 ID 偶数给客户端发请求,奇数给服务器发响应。
2. 加密集成:
QUIC 把 TLS 1.3 集成进传输层。所有 QUIC 包都加密(连包头都加密,传统 TLS 只加密 payload)。防止中间人探测 QUIC 行为(比如统计 stream ID 推断流量模式)。
3. 灵活的拥塞控制:
QUIC 在用户态实现,拥塞控制算法可热更新。服务器可以同时支持多种拥塞控制(Cubic、BBR、Reno),按客户端能力协商。
4. 连接 ID 而非四元组:
传统 TCP 连接靠"源 IP + 源端口 + 目的 IP + 目的端口"四元组标识。客户端从 WiFi 切到 4G,IP 变了,TCP 连接必须重连。QUIC 用 Connection ID 标识连接,IP 变了连接不中断。
问题三:QUIC 握手为什么能 0-RTT
传统 HTTPS 握手:
传统 HTTPS 握手(3 RTT):
图注:TCP 建立 1 RTT + TLS 1.2 握手 2 RTT = 3 RTT 才能发第一个 HTTP 请求。
QUIC 握手:
QUIC 握手(1 RTT):
图注:QUIC 把 TCP + TLS 合并到 UDP 之上,握手 1 RTT。TLS 1.3 已集成在 QUIC 层,所有包均加密。
1 RTT 完成握手(不算 0-RTT)。0-RTT 模式下,客户端用之前连接缓存的密钥,第一个包就带 HTTP 请求——服务端验证通过就直接处理。
0-RTT 的风险:重放攻击。如果攻击者截获 0-RTT 包,可以重发——服务端会再次处理同样的请求。金融交易、POST 表单禁用 0-RTT。
实际性能提升:
- 强网(10ms 延迟):HTTP/3 vs HTTP/2 提升 5-10%(1 RTT 省 10ms)
- 弱网(200ms 延迟卫星):HTTP/3 提升 50%+(2 RTT 省 400ms)
- 高丢包(5%):HTTP/3 提升 30%+(多路独立流)
问题四:HTTP/3 怎么用 QUIC
HTTP/3 是 HTTP 协议的最新版本(RFC 9114),用 QUIC 替代 TCP+TLS。
HTTP/3 的帧结构:
HTTP/3 复用 HTTP/2 的帧类型(HEADERS、DATA、SETTINGS、PRIORITY 等),但承载在 QUIC 流上:
QUIC 包:
┌─────────────────────────────────────┐
│ UDP 头(端口 4791 等) │
├─────────────────────────────────────┤
│ QUIC 长头(Connection ID 等) │
├─────────────────────────────────────┤
│ STREAM 帧(QUIC 流 ID + HTTP/3 数据)│
│ CRYPTO 帧(TLS 1.3 握手) │
│ ACK 帧(确认) │
│ ... │
└─────────────────────────────────────┘HTTP/3 头部压缩(QPACK):
HTTP/2 用 HPACK 压缩 header,但 HPACK 依赖按序处理。HTTP/3 因为多路独立流,包可能乱序到达——HPACK 失效。HTTP/3 用 QPACK(RFC 9204):
- 静态表 + 动态表 + Huffman 编码
- 通过专用单向流(unidirectional stream)同步动态表
- 不依赖包序——乱序到达也能正确解码
服务器推送(HTTP/3 Server Push):
HTTP/2 的服务器推送因为缓存问题被 Chrome 弃用。HTTP/3 重新设计:推送通过专用 QUIC 流,且客户端可以取消(用 CANCEL_PUSH 帧)。效果比 HTTP/2 好。
问题五:QUIC 部署的真实状况
浏览器支持
- Chrome:2016 年起默认启用 QUIC(gQUIC 协议)。2020 年起支持 IETF QUIC + HTTP/3
- Firefox:2020 年默认启用 HTTP/3
- Safari:2020 年起支持
- Edge:跟随 Chromium
当前 HTTP/3 部署率(2024 年):
- 顶级网站(Alexa Top 1000):约 25% 支持 HTTP/3
- Cloudflare 所有边缘节点默认支持 HTTP/3
- Google 服务(YouTube、Gmail)默认 HTTP/3
服务端支持
| 服务器 | 支持 | 备注 |
|---|---|---|
| Nginx | 实验性(1.25.0+ 启用) | 需要 BoringSSL 或 OpenSSL 3.2+ |
| Cloudflare | 完整支持 | 默认启用 HTTP/3 |
| Caddy | 完整支持 | 默认启用 HTTP/3 |
| HAProxy | 1.8+ | 支持 |
| Envoy | 1.19+ | 支持 |
| LiteSpeed | 完整支持 | 商用 Web 服务器 |
CDN 支持
Cloudflare、Akamai、Fastly、CloudFront 都支持 HTTP/3 边缘节点。
问题六:QUIC 的争议
QUIC 不是银弹,它有争议:
争议 1:CPU 开销
QUIC 在用户态实现,加密所有包(连头都加密),CPU 比 TCP 高 20-30%。Cloudflare 公开数据显示 HTTP/3 边缘节点 CPU 消耗比 HTTP/2 多 15%。
争议 2:中间设备不友好
传统网络设备(防火墙、DPI 深度包检测)只能看到 UDP 头,看不到 HTTP 内容。运营商无法做内容审计。中国、俄罗斯、土耳其曾尝试阻断 QUIC。
争议 3:UDP 容易被限速
很多企业网络对 UDP 限速(视频会议、VoIP 占带宽)。QUIC 在这种网络下性能反而差——UDP 被限速了 50%。
争议 4:生态成熟度
QUIC 库(MsQuic、nghttp3、quant)还在演进,bug 多。某些 NAT 设备不支持 QUIC 的多 UDP 端口(连接迁移用)。
结论:QUIC/HTTP/3 是未来方向,但不是现在就用。建议 CDN 边缘 + 移动场景优先,PC + 企业内网可以继续用 HTTP/2。
思考题
- 弱网下 HTTP/2 性能差,HTTP/3 好。强网下(丢包 <0.1%、延迟 <10ms)HTTP/3 还能有明显优势吗?什么情况下 HTTP/2 反而更快?
- QUIC 用 Connection ID 而非四元组。WiFi 切到 4G 时,IP 变了,QUIC 连接保持。但这要求 Connection ID 不变——如果中间 NAT 设备会改 UDP 头(一些运营商 NAT 改源端口),Connection ID 还能用吗?QUIC 怎么防 NAT 改端口?
- 0-RTT 模式可能被重放攻击。设计一个带 0-RTT 但防重放的协议。提示:单次 nonce、服务器时间戳、服务器侧去重。
- 某 CDN 部署 HTTP/3 后发现 CPU 消耗比 HTTP/2 高 20%。但 CDN 边缘节点本来 CPU 就不满,HTTP/3 反而能用更少服务器支撑同样流量。是不是 HTTP/3 总是更好?什么时候 HTTP/3 是反优化?
- 假设你在设计下一代协议,QUIC 之后的 Q4(QUIC v4)会是什么?UDP 之上还是其他传输?加密策略会怎么变?多路复用粒度会变细还是变粗?
- 某企业内部应用(ERP、CRM)目前用 HTTPS 1.3(TCP+TLS 1.3)。要不要升级到 HTTP/3?需要考虑哪些因素:客户端分布、网络环境、安全合规、改造成本?
延伸阅读
- RFC 9000: QUIC - A UDP-Based Multiplexed and Secure Transport
- RFC 9114: HTTP/3
- RFC 9204: QPACK - Field Compression for HTTP/3
- 《Web 性能权威指南》(Ilya Grigorik)O'Reilly
- Cloudflare 博客:QUIC 和 HTTP/3 系列文章
- 动手实验:用
curl --http3-only -v https://cloudflare.com看 HTTP/3 握手过程 - 动手实验:用 Wireshark 抓 QUIC 流量(需要密钥日志,参考
SSLKEYLOGFILE配置) - 动手实验:用
nginx1.25+ 启用 HTTP/3,用nghttp3客户端测试