上周把手头一个跑在海外机房的小站整体切到了 HTTP/3,跑了一周之后看监控,最直观的变化不是服务器 CPU 降了多少,而是 4G 网络下用户首屏时间中位数从 2.9 秒掉到了 1.7 秒,省下 1.2 秒左右。这个站点是个纯静态博客加一个评论接口,资源请求不多,但图片和 JS 一共二十多个,弱网环境下差别就出来了。我一开始也以为是错觉,后来把同一套页面在 HTTP/2 下跑了同样的脚本做对照,才确认这不是玄学,是协议机制本身带来的收益。这篇就把我这次上线过程里踩过的坑和验证方法完整写下来,给同样想折腾 HTTP/3 的朋友当个参考。
如果你手上的服务器还是一台机器扛着几个站、还在纠结带宽和线路怎么配,可以先看看这两家的机器再做规划:RackNerd(全球VPS,特价常推)、狗云DOGYUN(高性价比云服务器,多机房可选),协议换代这事在带宽和线路靠谱的机器上才试得出真实效果,线路一抖动,再好的协议也测不出来。

一、先搞清楚 HTTP/3 到底解决了什么
很多人以为 HTTP/3 只是「HTTP/2 换个名字」,其实它底下换掉了整个传输层。HTTP/2 跑在 TCP 上,HTTP/3 跑在 QUIC 上,而 QUIC 是跑在 UDP 上的。要理解这次优化的收益,得先看 HTTP/2 留下的那个老问题TCP 层的队头阻塞。
举个很常见的场景:一个网页打开了二十个并发请求,HTTP/2 用多路复用把它们塞进同一条 TCP 连接里,这部分确实解决了 HTTP/1.1 那种「六个连接堵浏览器、后面请求排队的」问题。但问题在于,TCP 本身是严格有序的字节流。现在假设这条连接上正在传第 12 个包,它因为某种原因丢了,TCP 不会把第 13、14、15 个包先交出去,它会停下来等重传,哪怕后面临近的其他流数据完好无损。
结果就是:一条连接上,一个包的丢失会让这条连接里所有并发的请求一起停顿。对弱网环境来说,这是致命的丢包率从 0.1% 涨到 3%,页面加载时间可能直接翻倍,而且这个停顿时间往往比真正传输数据的时间还长。我这次切协议前后最大的体感差异就来自这里:移动网络下丢包抖动频繁,HTTP/2 的速度曲线像心电图一样剧烈起伏,HTTP/3 则平得多。

二、QUIC 的三个硬本事
1. 每个流独立重传。 QUIC 把可靠性放在了应用层,一条连接内部拆成多个独立的流,哪条流的数据丢了就只重传那条流,其他流照跑不误。上面那个「第 12 个包丢了全连接卡住」的场景,在 QUIC 里不存在。实测中我用 Chrome DevTools 的 Network 面板对比过同一个页面的请求瀑布图,HTTP/2 下几乎每次都有一个长条横跨在其他请求上方,HTTP/3 下这条横条基本消失。
2. 握手只要 1-RTT,还能 0-RTT。 TCP+TLS1.2 的老流程要 2 到 3 个来回才能建连,TLS1.3 降到 1 个来回,QUIC 把加密握手和传输握手合并,同样是 1-RTT,会话恢复时甚至可以 0-RTT 直接发数据。对一个冷启动的新访客来说,省下的这几百毫秒是白赚的。我用 curl 加 --http3 参数反复建连测试,平均节省在 180 毫秒左右,弱网下这个数字会翻倍。
3. 连接 ID 机制,切换网络不断连。 TCP 用四元组标识连接,手机从 4G 切到 5G、或者从 WiFi 切到蜂窝,IP 一变连接就断,所有请求要重连重传。QUIC 用连接 ID 标识,IP 变了连接还在,这才是移动场景下体验提升的另一半原因。

三、服务器端到底怎么开
我用的是 Nginx,1.25 之后的版本已经内置了 QUIC 模块,不用自己编译第三方补丁,配置也很简单。核心是这么几行:
server { listen 443 ssl; listen 443 quic reuseport; http3 on; ssl_certificate /path/fullchain.pem; ssl_certificate_key /path/privkey.pem; add_header Alt-Svc 'h3=":443"; ma=86400'; }
有两个地方特别容易翻车,我第一次就都踩了。
第一个坑是 UDP 端口没放行。 绝大多数云服务器和虚拟主机商的默认安全组模板只开了 TCP 443,UDP 443 是关着的。这种情况下配置写对了、curl 也支持 --http3,但握手就是超时失败,表现和「QUIC 没生效」一模一样。我排查了小半小时,最后在服务器本地用 curl 打自己的 443 端口才定位到是安全组的问题。所以要记得在云厂商控制台和服务器本地的防火墙里同时放行 UDP 443,用 ufw 的就执行 ufw allow 443/udp,用 firewalld 的就是 firewall-cmd --add-port=443/udp。
第二个坑是 certbot 没覆盖到 QUIC 的证书目录。 如果证书是 certbot 自动续期的,续期后只 reload 了默认 vhost,Alt-Svc 头虽然还在,但证书路径变了导致握手失败,浏览器直接报安全错误。老老实实执行一次 nginx -t && systemctl reload nginx 就行。
还有一个不是坑但值得提的细节:Alt-Svc 头是让浏览器知道「下次可以试试 h3」的。首次访问仍然是 HTTP/2,因为浏览器还不知道你支持 HTTP/3。你可以在浏览器里搜 chrome://net-internals/#quic 或者直接看 DevTools 的 Protocol 列,出现 h3 才算真的走通了。

四、怎么验证是不是真的在用 HTTP/3
我主要用三种方式交叉验证。第一种最简单,在服务器上跑 curl -I --http3 https://你的域名,看返回的 Alt-Svc 头,curl -V 里显示 HTTP3 支持就说明本地握手成功了。第二种是用 Chrome 的 DevTools,Network 面板的 Protocol 列,选中任意请求,如果显示 h3 就说明浏览器走了 QUIC。第三种最严谨,直接抓包看是否有 UDP 443 的 Initial 包和 0-RTT 加密数据。要做更细的时序分析,可以用 HTTP Debugger Pro 这类 HTTP 协议分析工具配合看握手过程,能把 TLS 扩展、Alt-Svc 协商这些细节看得清清楚楚。
顺便提一句,检测工具网上也有,但很多只支持简单探活,判断「这个站在哪个 CDN 节点上、有没有开 QUIC」这种信息,本地抓包是最靠谱的,至少你不会被一个过期的缓存结论误导。

五、这些情况下先别急着开
HTTP/3 不是万能药,有几类情况我建议先观望。第一是你的站点静态资源不多、页面本来就在 1 秒内加载完的,收益几乎看不出来,不值得折腾。第二是你的服务器厂商对 UDP 流量有限速或者 QoS 降级,UDP 走不通的话不如老老实实用 HTTP/2。第三是你的用户群体里有大量老旧安卓设备或者企业内网环境,这些客户端很可能根本不支持 QUIC。最后是你的站点挂在某些 CDN 后面,CDN 到源站这段还是 HTTP/2,只有浏览器到 CDN 这一段能用 HTTP/3,效果会打折这种情况下更应该看 CDN 支不支持 HTTP/3,而不是在源站折腾。
另外要提醒一句:HTTP/3 走 UDP 会不会被机房封?我的经验是主流的海外和国内大厂机房都不会封 443/UDP,但如果你的机器是小厂或者个人 IDC,被限速甚至被封的情况是存在的。开之前最好先问清楚服务商的政策,别自己默默开了一天发现全站访客都走了 TCP 回落还不知道原因。
说到底,HTTP/3 值得开的场景很明确:移动端访问占比高、页面资源多、弱网丢包明显。你对着自己的访问日志看一眼地域分布和设备分布,就知道这笔投入值不值了。我这个站切完之后一周,跳出率降了 3 个百分点,首屏时间的 P90 从 4.2 秒降到 2.6 秒,这个收益已经值回那半小时的折腾时间了。协议这东西永远是后端的活,用户只会在心里默默说一句「这网站好像变快了」,然后关掉就走,这大概就是运维最朴实无华的成就感吧。



喜欢
顶
难过
囧
围观
无聊



