Apache 代理缓存通常指 Apache Traffic Server(ATS)或者基于 mod_proxy 配置的反向代理。要让它们支持 HTTP/3,不能只改端口,因为 HTTP/3 底层是 QUIC,QUIC 跑在 UDP 上,证书协商、连接迁移、流控都与 TCP 时代的 HTTP/1.1、HTTP/2 不同。Mojo quic 是一个专门为高性能代理场景设计的 QUIC 协议栈,它把 UDP 事件循环、TLS 1.3 握手和流管理封装成模块,编译进 ATS 后可以直接承载 HTTP/3 请求。下面先从编译整合说起。

编译期整合 Mojo quic
ATS 的插件和协议栈扩展依赖编译选项。启用 Mojo quic 前,需要确认系统 OpenSSL 版本不低于 1.1.1,因为 QUIC 的密钥更新和 0-RTT 依赖 TLS 1.3 的 API。以 Ubuntu 22.04 为例,先安装依赖:
sudo apt update sudo apt install -y cmake ninja-build libssl-dev libevent-dev zlib1g-dev pkg-config
接着获取 ATS 源码和 Mojo quic 源码。Mojo quic 可以通过 git 拉取,编译时使用 CMake 的 ENABLE_MOJO_QUIC 选项开启。这个选项会同时编译 UDP 监听线程和 QUIC 连接管理代码,不额外引入 ngtcp2 或 quiche 依赖。编译命令大致如下:
git clone https://github.com/apache/trafficserver.git cd trafficserver git clone https://github.com/mojo/quic.git plugins/mojo_quic cmake -B build -G Ninja -DENABLE_MOJO_QUIC=ON ninja -C build sudo ninja -C build install
这里把 Mojo quic 放在 plugins 目录只是为了组织方便,实际安装路径不影响运行。编译完成后,可以用 traffic_server -V 查看版本信息,确认输出中包含 mojo_quic 字样。如果编译失败,常见原因是 OpenSSL 头文件缺失,或者 CMake 没找到 Mojo quic 的依赖库,可以在 CMake 参数中补充 -DOPENSSL_ROOT_DIR=/usr/local/ssl 这样的路径。对于生产环境,建议先在一台独立构建机上完成编译,再通过包管理工具分发,避免线上机器安装完整编译链带来的安全风险。
TLS 与监听配置要点
HTTP/3 只能在加密连接上工作,所以必须为 ATS 配置一套证书。证书可以是自签的,但客户端需要信任。生成自签证书的命令:
openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
-keyout server.key -out server.crt \
-subj "/CN=proxy.ipipp.com"
把证书路径写入 ssl_multicert.config,格式为 ssl_cert_name=server.crt ssl_key_name=server.key。对于 QUIC 监听,ATS 需要单独的 UDP 端口,并且要在 records.config 中显式声明。关键配置项如下:
proxy.config.http.server_ports: 80 443:ssl proxy.config.http.quic_ports: 443:quic proxy.config.udp.threads: 2 proxy.config.ssl.server.cert.path: /etc/trafficserver proxy.config.ssl.server.private_key.path: /etc/trafficserver
其中 443:quic 表示 UDP 443 端口启用 QUIC,TCP 443 仍然保留给 HTTP/2 和 HTTP/1.1,这样旧客户端可以回退。要注意 QUIC 端口不能只在防火墙放行 TCP,必须在云安全组或 iptables 中同时放行 UDP。很多部署失败就是因为只开了 TCP 443,UDP 包被丢弃导致客户端一直超时。
Mojo quic 默认启用 0-RTT,但需要客户端缓存会话票据。ATS 端通过 proxy.config.ssl.session_cache 控制会话缓存大小。如果源站响应头包含 Set-Cookie 且缓存策略不谨慎,0-RTT 重放可能造成安全问题,因此建议对带 Cookie 的请求禁用 0-RTT,或者至少在反向代理层按 Cookie 前缀拆分缓存键。此外,QUIC 连接迁移会带来新的源 IP 校验需求,如果代理前面还有四层负载均衡,需要确保 UDP 会话保持策略使用四元组哈希,否则握手包和后继数据包可能落到不同后端。
缓存策略和高并发调优
HTTP/3 解决了队头阻塞问题,但缓存策略如果不匹配,提升会被磁盘 IO 拖平。ATS 默认会把可缓存的响应写入磁盘,下次请求直接命中。要让 HTTP/3 连接上的请求命中缓存,缓存键必须与源站 URL 解耦,只保留协议无关部分。通常做法是启用 proxy.config.http.cache.ignore_client_abort 和 proxy.config.http.cache.required_headers,并设置合理的对象大小上限。
proxy.config.http.cache.ignore_client_abort: 1 proxy.config.http.cache.required_headers: 1 proxy.config.cache.max_doc_size: 64M proxy.config.http.cache.heuristic_min_lifetime: 3600
这里 heuristic_min_lifetime 指定无明确过期时间对象的最小缓存寿命,避免所有动态页面都被当成不可缓存。对于 REST API 或个性化内容,可以结合 Cache-Control: no-store 让 ATS 跳过写入。缓存命中率可以通过 traffic_ctl metric get proxy.process.http.cache.hit_fresh 查看,观察 HTTP/3 流量与 HTTP/2 流量的命中率差异。如果命中率低于预期,不要急着调大缓存空间,先检查响应头中是否缺少 Last-Modified 或 ETag,因为 ATS 对这类响应默认不会缓存。
QUIC 连接建立比 TCP 多一次握手流程,但因为支持 0-RTT,实际弱网下首字节时间反而更短。为了发挥这个优势,ATS 的 UDP 线程数不要设置过多,通常 2 到 4 个足够,线程太少会导致单核处理不过来,太多会引入锁竞争。可以在压测时用 ss -lunp | grep 443 查看 UDP 队列是否积压,如果 Recv-Q 持续非零,需要增加 UDP 线程或检查 CPU 亲和性。另一个容易被忽略的参数是 proxy.config.udp.max_packet_size,默认值在多数互联网路径上可以工作,但如果客户端频繁报告 QUIC_HANDSHAKE_TIMEOUT,可以尝试下调到 1200 以下,牺牲少量吞吐换取更高的握手成功率。
验证与故障排查
部署完成后,可以用 curl 的 HTTP/3 支持来验证。curl 8.0 及以上版本默认开启 HTTP/3,命令如下:
curl --http3 -I https://proxy.ipipp.com/test.jpg \
--resolve proxy.ipipp.com:443:127.0.0.1
输出中看到 HTTP/3 200 说明 QUIC 握手和请求转发都成功。如果返回 curl: (56) QUIC connection failed,先检查 UDP 443 是否可达,再用 tcpdump -i any udp port 443 -nn 抓包看是否有 Initial 包交换。证书问题通常表现为 SSL certificate problem,此时需要把自签 CA 加入客户端信任链。如果只想快速验证功能,可以在 curl 命令后追加 --insecure,但生产环境不建议保留。
另一个容易忽略的坑是 MTU。QUIC 对分片很敏感,如果路径 MTU 低于 1280,连接会退回 TCP,性能下降明显。可以在网卡上开启 UDP GSO,或者调整 proxy.config.udp.max_packet_size 为 1200 以下。ATS 的 traffic.out 日志中会记录 QUIC 连接迁移和路径验证事件,出现 quic_path_validation_failed 时优先排查网络设备是否过滤 ICMPv6 Too Big 消息。对于大规模并发场景,还需要关注文件描述符上限,ATS 的 proxy.config.net.connections_throttle 默认值可能不足以支撑大量 QUIC 短连接,建议根据实际压测结果调高,并配合 ulimit -n 设置更大的进程限制。
综合来看,Apache 代理缓存借助 Mojo quic 实现 HTTP/3 的关键在于编译期集成、UDP 监听与 TLS 配置的耐心调优,以及缓存键在 QUIC 连接下的行为确认。把这三块做扎实,弱网环境下的加速效果会非常明显。即便暂时无法全量切换,也可以先让部分客户端通过 HTTP/3 访问,收集连接失败率和缓存命中率数据,再逐步扩大范围。
HTTP/3QUICApache代理缓存修改时间:2026-10-02 10:22:22