CDN 压缩协商实测:为什么浏览器总是拿到 gzip

举报
yd_290338283 发表于 2026/11/05 00:15:44 2026/11/05
【摘要】 用 Accept-Encoding 矩阵实测两个 CDN 节点的压缩协商:一个只要声明 gzip 就回 gzip,br/zstd 变体形同虚设;另一个正确选中 br 且只用 q4 档。附解压吞吐实测、反推压缩档位的方法与 Vary 缓存坑。

结论先行

对两个不同 CDN 节点的压缩协商做了一轮矩阵实测,结果和直觉相反:

  1. 其中一个节点的协商是「gzip 优先」:客户端 Accept-Encoding 里只要出现 gzip,它就返回 gzip——哪怕同时声明了 br 和 zstd。而浏览器真实发送的头正是 gzip, deflate, br, zstd,所以永远只能拿到 gzip。只有客户端明确不支持 gzip 时,它才启用 br/zstd。
  2. 另一个节点的协商是对的:多编码声明下正确选中 br,且实际只用了 q4 质量档,实时压缩开销约 4.6 ms。但它不认 zstd,单独声明 zstd 会返回未压缩的 identity。
  3. brotli 解压并不比 gzip 慢:同一文件 br 解压 462 MB/s、gzip 391 MB/s,br 反而快约 15%。「br 慢」的印象来自 q11 档,而线上用的是 q4。

实测方法

  • 测量必须绕过本机代理,否则会污染国内 CDN 的结果,所有请求统一带 --noproxy '*'。
  • 手动指定 Accept-Encoding 时 curl 不会自动解压,size_download 就是压缩后的字节数;用 --compressed 反而测不到,因为它会自行改写请求头并自动解压。
  • 解压吞吐用 Python 的 brotli/gzip/zstandard 模块各跑 200 轮取中位数。
  • 反推质量档的办法:先把响应体解压出原始数据,再在本地按 q1/q4/q5/q9/q11 重压,比对字节数落在哪一档。

一、编码协商矩阵

站点 A(原始 JS 1,784,216 B)

客户端 Accept-Encoding实际返回传输字节
gzip, deflate, br, zstd(浏览器真实头)gzip517,208
gzip, deflate, brgzip517,208
gzip, zstdgzip517,208
br, gzipgzip517,208
zstd, gzipgzip517,208
zstd, brzstd422,435
br, zstdzstd422,247
brbr420,954
zstdzstd416,099

规律很清楚:请求头含 gzip 就回 gzip;不含 gzip 时才在 br/zstd 之间挑选,且 zstd 优先于 br,与声明顺序无关。

站点 B(原始 JSON 438,775 B)

客户端 Accept-Encoding实际返回传输字节
gzip, deflate, br, zstd(浏览器真实头)br90,306
zstd, brbr90,306
br, zstdbr90,306
brbr90,306
zstdidentity(未压缩)438,775
gzipgzip96,653

这个节点的逻辑是「支持 br 就选 br」,完全不识别 zstd。

二、代价:正确的那一方把客户端锁在了最差的一档

同一个 1.78 MB 的 JS,三种编码分别落盘实测:

编码传输大小相对 gzip解压耗时解压吞吐
gzip517,208 B—4,953 μs360 MB/s
br420,954 B−18.6%3,843 μs464 MB/s
zstd416,099 B−19.5%1,680 μs1,062 MB/s

站点 A 明明有 zstd 能力——单独声明时能拿到,缓存里也有该变体——却因为协商顺序把它锁在门外。对访客来说,这是每次都多传 20% 字节、多花 3 倍解压时间。

三、br 并不慢:反推线上用的质量档

把站点 B 的原始 JSON 在本地按各质量重压,和线上实际传输的 90,306 B 对比:

质量档产出压缩耗时
q1101,650 B2.7 ms
q490,381 B4.6 ms
q581,088 B5.9 ms
q976,951 B16.3 ms
q1170,427 B377 ms

线上传的 90,306 B 正好落在 q4 的 90,381 B 附近,说明它用的是 q4,而不是很多人印象里「慢得要死」的 q11。4.6 ms 的实时压缩成本基本可以忽略。

四、几个容易踩的坑

  • 变体缓存要预热。CDN 按 Vary: Accept-Encoding 把各编码变体分开缓存,首次请求某个变体是 MISS,要回源现压,首测耗时能到 4.8 秒。预热之后三个变体都稳定 HIT。别用「第一次访问」的印象评判某个编码。
  • 有的节点不返回 Vary,却按编码返回不同内容。它自己维护了变体缓存,但缺少 Vary 头理论上存在缓存投毒隐患,本轮没有观测到实际问题。
  • 反推质量档要控制 lgwin。窗口大小不同,字节数不能直接对标。
  • zstd 帧头可能不写 content size。部分实现解压时会报「无法从帧头确定大小」,需要改用 max_output_size 或流式解压。

五、建议

对协商有问题的节点,建议先去控制台确认「智能压缩 / Brotli」里有没有算法优先级或 gzip 开关;如果控制台没有这个选项,值得提单——「只要声明了 gzip 就不选 br/zstd」并不符合按 q 值择优的协商精神。对已经正确选 br 且使用 q4 的节点,无需改动,这已经是这条链路的最优解。

本文基于本人真实环境的抓包与压测数据整理,AI辅助撰写与排版;文中站点做了匿名处理,结论均可复现。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。