5.2 Gzip压缩:省下的是真金白银


5.2 Gzip压缩:省下的是真金白银

本节摘要:Gzip 在传输前压缩文本响应,典型压缩比 3 到 5 倍,直接换算成出口带宽与页面加载时间。本节算一笔带宽账,确定压什么、压到几级、以及哪些坑会让压缩悄悄失效。

一笔带宽账

站点日均 2 亿次文本请求,平均响应 30KB:

不压缩:2亿 × 30KB = 6000 GB/日 出口 压缩比4:1:2亿 × 7.5KB = 1500 GB/日 出口 差额:4500 GB/日 —— 按带宽计费这就是每月真金白银 用户侧:首屏资源从 210KB 降到 52KB,弱网加载时间减半

CPU 代价呢?现代 CPU 上 level 4 压缩 30KB 文本的耗时不足 1ms,而 worker 是事件驱动的,压缩与其他连接的处理交错进行。这笔账几乎稳赚不赔。

生产配置

http { gzip on; gzip_min_length 1k; # 小于1K不压:压不动还添乱 gzip_comp_level 4; # 4是性价比甜点 gzip_types text/css application/javascript application/json text/plain application/xml image/svg+xml; gzip_vary on; # 响应头标注支持压缩,供代理链识别 gzip_disable "MSIE [1-6]\."; # 古董浏览器禁用 # 静态内容预先压缩好,运行时零CPU gzip_static on; }

两个决策的依据:

  • level 4 到 6 之间收益急剧递减:6 比 4 多耗一倍 CPU 只多省 2% 字节。4 是甜点,静态资源走 gzip_static 连这点 CPU 都省掉。
  • gzip_types 默认只有 text/html。忘了把 application/json 加进去,API 响应全部裸传——这是最常见的"配了没生效"。

压缩失效排查清单

上线后用 curl -I -H "Accept-Encoding: gzip" 检查响应头有没有 Content-Encoding: gzip。没有时按序检查:

1. 响应是否 < gzip_min_length? 2. Content-Type 是否在 gzip_types 里? 3. 是不是 proxy 链上的上游已压缩或标了不可压缩? 4. gzip_vary 没开导致中间层缓存了未压缩版本?

第 4 条最隐蔽:缓存层存了未压缩版本,所有命中者都拿大文件。gzip_vary on 让缓存的键包含压缩维度。

不该压的东西

图片与视频已是压缩格式,再压是纯耗 CPU,字节几乎不减——gzip_types 里永远不要出现 png/jpg/woff2。加密后的随机字节同理。真正值得压的是文本家族:HTML、CSS、JS、JSON、XML、SVG。

图:压缩收益矩阵

图:压缩收益矩阵

与缓存、HTTP2 的配合

顺序值得想清楚:缓存存什么版本,压缩在缓存之后做——Nginx 的 proxy_cache 默认存未压缩的后端响应,命中后按客户端 Accept-Encoding 现场压缩。这样一份缓存服务所有编码。HTTP2 时代同域名请求挤一条连接,请求之间不再互相排队建连,压缩省下的传输时间收益被进一步放大。

压缩级别实测:用数据代替甜点口诀

level 4 是甜点是经验值,自己环境的正确答案要实测出来。方法是对代表性响应做离线压缩,对比各级别的字节与耗时:

# 对同一个 500KB 的 JSON 响应逐级压缩,记录大小与耗时 for lv in 1 4 6 9; do echo -n "level $lv: " gzip -$lv -c response.json | wc -c done # 典型结果:1 → 96KB,4 → 74KB,6 → 72KB,9 → 71KB # 4 到 9 只多省 4%,CPU 却翻倍以上——甜点区间可见

文本类型不同甜点也不同:JSON 这类结构重复度高的内容低级别就压得动;已经过 minify 的 JS 收益整体偏低。API 为主的服务值得对 JSON 单独测一轮,因为它的响应占比最大。这个十分钟的实验能给出有数据支撑的 gzip_comp_level,汇报时也站得住。

gzip_static 的配套工作流

运行时零 CPU 的前提是磁盘上提前放好同名 gz 文件。构建流水线的改造:产物打包阶段对文本产物生成 gz 副本随版本一起发布。验证它生效的方式是看响应头之外的时间特征:

# 先生成 .gz 副本 gzip -9 -k /data/www/static/app.3f2a1b.js # 请求时 Nginx 直接发 .gz,观察 CPU 与响应大小 curl -I -H "Accept-Encoding: gzip" https://static.example.com/app.3f2a1b.js # Content-Encoding: gzip 且 Nginx CPU 无波动即命中静态压缩

注意两个坑:gz 副本与源文件必须同批生成,发布脚本漏了 gz 就会静默回退运行时压缩(不算故障但 CPU 白花);清理旧版本时把 gz 一并清掉,磁盘会被双份文件慢慢吃掉。

再往前一步是 brotli:同级别下压缩率比 gzip 约高一到两成,且现代浏览器全部支持。它不是 Nginx 自带能力,需要第三方模块——于是回到第四章的决策框架:收益明确(文本流量再省百分之十几)但要背模块维护成本。我的建议是流量以文本为主、带宽成本敏感的站点值得上,并优先采用"预压缩"用法(构建期生成 br 文件),把运行时 CPU 与模块复杂度同时绕开。gzip 与 brotli 可以共存,按客户端 Accept-Encoding 协商分发,互不干扰。

压缩与安全的交叉点也值得一提:已经过 TLS 加密的流量,压缩依旧生效——压缩发生在加密之前的明文阶段,所以带宽收益不受 HTTPS 影响。反过来,压缩曾经带来过一类侧信道风险(攻击者借助压缩比例推断加密内容),现代浏览器与服务器已通过禁用特定头部的压缩来规避,Nginx 的默认行为同样安全。了解这段背景的价值在于:看到安全扫描器对 gzip 配置的某条告警时,能分清它是历史遗留建议还是真实风险,而不是条件反射地关压缩。

本节要点回顾

  • level 4 是甜点,静态资源上 gzip_static 做到零运行时 CPU;
  • gzip_types 必须显式加 JSON,默认只有 HTML;
  • gzip_vary on 防止缓存层存错版本
  • 图片视频永远不压,负收益;
  • 验证靠 curl 看 Content-Encoding 头,别凭感觉。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U