HTTP/3 与 QUIC 边缘节点部署实践
QUIC 把传输层从内核搬到了用户态,听起来美好却带来调度、拥塞、CPU 的全新挑战。本文分享一个真实 CDN 边缘节点的 HTTP/3 灰度过程,包括配置细节、回滚预案、性能收益。
为什么我们需要 HTTP/3
2024 年初我们做了一个小调研:在 4G 网络下首屏图片资源的平均加载时间。HTTP/1.1 是 1.9s,HTTP/2 是 1.5s,HTTP/3 是 1.0s。差距不算夸张,但对于「弱网用户的第一印象」却极为关键。
HTTP/3 的核心是 QUIC。它建立在 UDP 之上,把 TCP 的可靠性、拥塞控制、TLS 都搬进协议内部。这带来的实际收益是:
- 握手快:0-RTT 或 1-RTT 完成 TLS + QUIC。
- 队头阻塞:单一连接上的流之间互不阻塞。
- 连接迁移:从 4G 切到 Wi-Fi 不重连。
HTTP/3 不是性能银弹。它在弱网与小文件场景收益显著,在强网大文件下与 HTTP/2 差异很小。
HTTP/3 不是「换个库」的事
决定升级前我们梳理了三种实现路径:
| 方案 | 改动点 | 代价 |
|---|---|---|
| Cloudflare / Fastly 等 SaaS | 零 | 绑定 |
| NGINX + quic module | 中(编译 + 内核 UDP 调优) | 需要维护 |
| Envoy + QUIC listener | 高 | 可塑性强 |
我们的边缘网关跑在 NGINX 自研 fork 上,最终选择路线二:自己升级 quic 模块,灰度发布。
内核与 UDP 调优,先做这一步
HTTP/3 跑在 UDP 上,高并发下 UDP 的内核缓冲区成为瓶颈。务必在边缘节点上提前调:
# 增加 socket 缓冲区上限
sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.wmem_max=26214400
sysctl -w net.core.rmem_default=1048576
sysctl -w net.core.wmem_default=1048576
# 高并发 UDP 端口范围
sysctl -w net.ipv4.ip_local_port_range="1024 65000"
# UDP hash 表大小
sysctl -w net.core.udp_mem="102400 873800 16777216"
sysctl -w net.core.udp_rmem_min=8192
sysctl -w net.core.udp_wmem_min=8192
有研究显示,没做这一步的 HTTP/3 在 25 万并发下会出现 1–2% 的丢包,而调整后可以压到几乎为零。
0-RTT 的双刃剑
QUIC 支持 0-RTT——客户端在第一次握手时就带数据。好处是延迟降低,坏处是「重放攻击」。如果服务器开启 0-RTT,必须保证这些「早期数据」是幂等的,否则可能被攻击者重发。我们在网关把 0-RTT 限制为只对静态 GET 开放(这些天然幂等)。
http3:
listen 443 http3 reuseport;
ssl_early_data on;
ssl_protocols TLSv1.3;
ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256;
# 标记 0-RTT 请求的 header
proxy_set_header Early-Data $ssl_early_data;
location /api/ {
if ($ssl_early_data) { return 403; } # 拒绝 0-RTT 的写操作
proxy_pass http://upstream;
}
灰度策略与回滚预案
我们没有直接全量切。灰度策略是:
- 5% 流量切 HTTP/3,按 client IP 抽样。
- 观察 24 小时:连接成功率、握手时长、CPU 利用率。
- 扩大到 30% → 50% → 100%。
- 每阶段在 Prometheus 里设独立指标视图,发现恶化立刻缩容。
关键的回滚条件:CPU 利用率突破 75%、握手 P99 突破 1.2s、UDP 丢包突破 0.5%。任何一条触发,自动切回 HTTP/2 并报警。
真实收益与真实坑
线上 30 天后总结:
| 指标 | HTTP/2 | HTTP/3 | 提升 |
|---|---|---|---|
| 4G 弱网首字 TTFB | 300ms | 180ms | 40% |
| 看图请求平均加载 | 1.5s | 1.0s | 33% |
| 边缘 CPU 利用率 | 55% | 62% | -7pt |
| 连接建立 QPS 容量 | 25 万 | 30 万 | 20% |
但也踩过几个坑:
- 某些企业 NAT 不友好,会把 UDP 强行 throttle;后来用 alt-svc hint,让客户端自己降级。
- 部分 SDK(比如老版本 OkHttp)QUIC 实现不完整,会随机断连;需要客户端版本兼容矩阵。
- QUIC 在不同 CPU 上的加密性能差距大,启用 BoringSSL 后才稳定下来。
监控体系:HTTP/3 独有的指标
HTTP/3 的指标和 HTTP/2 完全不同。我们专门新增了:
http3_handshake_total:握手次数。http3_handshake_seconds:握手时长直方图。http3_stream_count:单连接流数量。http3_0rtt_accepted_total:0-RTT 接受数。
把这些指标与告警阈值绑定,再做一层「连接迁移失败率」的看板,确保我们时刻知道新协议的健康度。
关于边缘计算的几个想法
HTTP/3 真正的价值在于它让边缘节点之间的通信更高效。当我们在边缘写一段 JavaScript(或 WASM)并希望相邻节点进行通信时,QUIC 的连接迁移与多路复用是天然契合的。这也是为什么 Cloudflare Workers、Vercel Edge Functions 这些产品近年开始主推 HTTP/3。
下一代边缘计算的「网络层」很可能是 HTTP/3,而不是 HTTP/2。这意味着我们对协议栈的取舍要从一两年后再看一次。
一些不那么技术的小经验
升级一个核心协议,最难的不是配置,是「团队认知」。我们做过的几件事:
- 把「HTTP/3 不要直接全量上」这一条写进所有 runbook。
- 给一线运维同学做过一次 hands-on 培训,演示一次灰度切换的过程。
- 每次升级协议都拉一个 5 人的工作组,确保不依赖任何一个人的「记得」。
这听起来不那么性感,但它是真实的工程。