Skip to content

HTTP/3:QUIC 替代 TCP

2022 年,HTTP/3 正式成为 RFC,这意味着它已经从实验性协议变成了标准。

HTTP/3 的最大改变是:它不再基于 TCP,而是基于 QUIC(一个基于 UDP 的协议)。

这个改变解决了 HTTP/2 的一些根本性问题。

为什么需要 HTTP/3?

HTTP/2 的遗留问题

HTTP/2 虽然解决了 HTTP/1.1 的很多问题,但仍然有一个根本缺陷:TCP 的队头阻塞

HTTP/2 多路复用:

Stream 1 ──────────────────────────> 完成
Stream 2 ─────────> 丢包 ──> 重传 ──> 完成
Stream 3 ──> 丢包 ──> 重传 ──────────────> 完成

TCP 层的问题:丢包会影响所有 Stream

虽然每个 HTTP/2 Stream 是独立的,但它们共享同一个 TCP 连接。TCP 必须按顺序交付数据,一个包的丢失会导致所有后续包被卡住。

解决方案:QUIC

QUIC 是一个新的传输层协议,构建在 UDP 之上:

QUIC 的设计目标:
1. 解决 TCP 队头阻塞
2. 0-RTT 或 1-RTT 连接建立
3. 连接迁移
4. 可插拔的拥塞控制

QUIC 核心机制

Stream 级别的可靠性和有序性

TCP 的可靠性:整个连接有序
QUIC 的可靠性:每个 Stream 有序

TCP:
包 1 ───> 包 2 ───> 包 3 ───> 包 4 ───>

      包 2 丢失
      包 3 和包 4 都要等

QUIC(Stream 1):
帧 1 ───> 帧 2 ───> 帧 3 ───> 完成

      Stream 1 的帧 2 丢失
      只影响 Stream 1

QUIC(Stream 2):
帧 A ───> 帧 B ───> 帧 C ───> 完成
(Stream 2 不受影响,继续传输)

连接建立

TCP + TLS 1.3(理想情况):
1. TCP 三次握手(1 RTT)
2. TLS 握手(1 RTT)
总计:2 RTT

TCP + TLS 1.2:
1. TCP 三次握手(1 RTT)
2. TLS 握手(2 RTT)
总计:3 RTT

QUIC + TLS 1.3:
1. 握手和密钥交换同时进行(1 RTT)
总计:1 RTT

QUIC 0-RTT(重连时):
0 RTT(使用缓存的密钥)

连接迁移

TCP 连接基于四元组(源 IP, 源端口, 目标 IP, 目标端口)

手机从 WiFi 切换到 4G:
- IP 地址变了
- TCP 连接断开
- 需要重新建立连接

QUIC 使用 Connection ID:
- 连接与 IP 地址无关
- 切换网络时,只要 Connection ID 不变,连接保持

HTTP/3 帧类型

┌─────────────────────────────────────────────────────────────┐
│                    HTTP/3 帧类型                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  SETTINGS          帧 ── 连接参数                         │
│  HEADERS           帧 ── HTTP 头部                         │
│  DATA              帧 ── HTTP 消息体                       │
│  CANCEL_PUSH       帧 ── 取消推送                         │
│  PING              帧 ── 心跳检测                         │
│  GOAWAY            帧 ── 优雅关闭                         │
│  MAX_PUSH_ID       帧 ── 最大推送 ID                      │
│  ...                                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

与 HTTP/2 帧的对比

HTTP/2 帧 vs HTTP/3 帧:

HTTP/2:
├─ HEADERS(压缩的头部)
├─ DATA(数据)
├─ SETTINGS(参数)
├─ PUSH_PROMISE(服务器推送)
├─ PING
├─ WINDOW_UPDATE(流控制)
└─ GOAWAY

HTTP/3:
├─ HEADERS(未压缩,直接用 QPACK)
├─ DATA(数据)
├─ CANCEL_PUSH(取消推送,替代 PUSH_PROMISE)
├─ PING
└─ GOAWAY

注意:HTTP/3 没有 WINDOW_UPDATE!
      QUIC 本身已经有流控制机制,不需要 HTTP 层再做

QPACK:HTTP/3 的头部压缩

HPACK 的局限

HTTP/2 使用 HPACK 压缩头部,但 HPACK 依赖 TCP 的有序传输。

如果 TCP 包丢失,HPACK 的动态表更新会被卡住,影响后续帧的解析。

QPACK 的解决方案

QPACK 使用两个单向流(Unidirectional Streams):
1. 请求流:发送 HEADERS 帧
2. 动态表流:发送动态表更新

动态表更新和 HEADERS 可以独立传输,不互相阻塞。

QPACK 编码示例

HEADERS 帧编码:
┌─────────────────────────────────────────────────────────────┐
│ QPACK 编码                                                  │
├─────────────────────────────────────────────────────────────┤
│  Static Table Reference  │  Dynamic Table Reference         │
│  (预定义索引)           │  (动态索引)                       │
│                                                             │
│  03                   │  c0                                │
│  (= :method GET)      │  (= 动态表索引 0)                 │
└─────────────────────────────────────────────────────────────┘

HTTP/3 的握手过程

1-RTT 握手

客户端                                              服务器
   │                                                   │
   │  ┌─────────────────────────────────────────┐   │
   │  │  QUIC Initial (CRYPTO/CH)               │   │
   │  │  - DCID (目标连接 ID)                   │   │
   │  │  - SCID (源连接 ID)                     │   │
   │  │  - TLS ClientHello                      │   │
   │  └─────────────────────────────────────────┘   │
   │ ─────────────────────────────────────────────────> │
   │                                                   │
   │  ┌─────────────────────────────────────────┐   │
   │  │  QUIC Initial (CRYPTO/SH)               │   │
   │  │  - TLS ServerHello                      │   │
   │  │  - TLS 证书                              │   │
   │  │  - TLS Finished                          │   │
   │  └─────────────────────────────────────────┘   │
   │ <──────────────────────────────────────────────── │
   │                                                   │
   │  握手完成,密钥已协商                              │
   │                                                   │
   │  ┌─────────────────────────────────────────┐   │
   │  │  HTTP/3 HEADERS (GET /)                 │   │
   │  │  + 加密                                 │   │
   │  └─────────────────────────────────────────┘   │
   │ ─────────────────────────────────────────────────> │
   │                                                   │
   │  ┌─────────────────────────────────────────┐   │
   │  │  HTTP/3 HEADERS (200 OK)                 │   │
   │  │  + 加密                                 │   │
   │  └─────────────────────────────────────────┘   │
   │ <──────────────────────────────────────────────── │

0-RTT 握手

前提:客户端和服务器之前建立过连接

客户端                                              服务器
   │                                                   │
   │  ┌─────────────────────────────────────────┐   │
   │  │  QUIC Initial                            │   │
   │  │  + Early Data (0-RTT)                    │   │
   │  │  + 加密(使用上次保存的密钥)              │   │
   │  └─────────────────────────────────────────┘   │
   │ ─────────────────────────────────────────────────> │
   │                                                   │
   │  ┌─────────────────────────────────────────┐   │
   │  │  QUIC Initial                            │   │
   │  │  + 新密钥(可能拒绝 0-RTT 数据)          │   │
   │  └─────────────────────────────────────────┘   │
   │ <──────────────────────────────────────────────── │

HTTP/3 的优势

1. 更低的延迟

场景:首次访问网站
TCP + TLS 1.3 = 2 RTT
QUIC + TLS 1.3 = 1 RTT

节省 1 个 RTT ≈ 节省 20-100ms(取决于网络)

2. 无 TCP 队头阻塞

在丢包率 2% 的网络下:
HTTP/2:有效吞吐量下降 50%+
HTTP/3:有效吞吐量下降 < 10%

3. 更好的移动网络支持

场景:地铁上从 4G 切换到 5G
TCP:连接断开,重新握手
QUIC:Connection ID 不变,无缝切换

4. 更好的拥塞控制

TCP 拥塞控制在内核中,更新困难
QUIC 拥塞控制在用户空间,更新像更新 App 一样简单

这意味着:
- 新的拥塞控制算法可以更快部署
- 可以针对不同应用使用不同算法
- 可以根据网络状况动态调整

部署现状

浏览器支持

Chrome: 支持(2020 年默认启用)
Firefox: 支持
Safari: 支持(iOS 14+)
Edge: 支持

服务器支持

Nginx: 1.25+(实验性支持)
Caddy: 默认支持
Apache: mod_h2(第三方模块)
Cloudflare: 支持
Fastly: 支持

如何启用

nginx
# Nginx 配置
server {
    listen 443 quic reuseport;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    # 声明 HTTP/3 可用
    add_header Alt-Svc 'h3=":443"; ma=86400';
}
bash
# curl 测试
curl -I --http3 https://example.com

# Chrome 开发者工具
# 查看协议:Protocol 列会显示 h3-29 或 http/3

HTTP/3 vs HTTP/2 vs HTTP/1.1

特性HTTP/1.1HTTP/2HTTP/3
传输层TCPTCPQUIC/UDP
多路复用StreamStream(更完善)
头部压缩HPACKQPACK
服务器推送支持支持
队头阻塞TCP 层TCP 层Stream 级别
握手延迟3 RTT2-3 RTT0-1 RTT
连接迁移支持
拥塞控制内核内核用户空间
TLS可选可选必需

面试追问方向

  • HTTP/3 相比 HTTP/2 最大的改进是什么?
  • 为什么 HTTP/3 基于 UDP 而不是 TCP?
  • 什么是 QUIC?它的核心特性是什么?
  • HTTP/3 如何解决 TCP 队头阻塞问题?
  • 什么是 0-RTT 和 1-RTT?它们有什么区别?
  • 什么是 QPACK?和 HPACK 有什么区别?
  • HTTP/3 的连接迁移是如何工作的?
  • HTTP/3 部署现状如何?
  • 如何在 Nginx 中启用 HTTP/3?
  • HTTP/3 的 0-RTT 有什么安全风险?

基于 VitePress 构建