$gzip_ratio不能实时监控各资源压缩比,因其仅为日志专用变量,仅在access_log写入时计算并填充,不可在if、set或Lua中读取或参与逻辑判断,生命周期限于日志渲染阶段。

Nginx 的 $gzip_ratio 变量本身**不能直接用于实时监控各资源的压缩比**,因为它只在响应被 gzip 压缩后才存在,且仅在日志格式中可用——它不是运行时可读取的变量,也不能在 if、set 或 Lua 脚本中动态获取或参与逻辑判断。
为什么 $gzip_ratio 无法“实时监控”
$gzip_ratio 是一个“日志专用变量”,Nginx 仅在写入 access log 时计算并填充该值(格式为 a.b,例如 3.24),表示原始响应体字节数与压缩后字节数的比值。它的生命周期仅限于日志格式字符串渲染阶段:
- 它不参与请求处理流程,不能用在
location、rewrite或return中 - 它在未启用 gzip 或响应未被压缩时为空字符串(日志中显示为 “-”)
- OpenResty 的
ngx.var.gzip_ratio也始终为nil,不可读取
真正可行的压缩比观测方式:通过 access_log + 日志分析
将 $gzip_ratio 写入定制化日志,再结合外部工具(如 awk / Prometheus + nginx-lua-prometheus / ELK)做聚合分析,是唯一官方支持的路径:
- 在
http块中定义日志格式:log_format gziplog '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $gzip_ratio $request_length $bytes_sent'; - 在 server 或 location 中启用:
access_log /var/log/nginx/gzip-access.log gziplog; - 重启 Nginx 后,日志行末尾会出现类似
2.84的值(若启用 gzip 且成功压缩)
进阶:按资源路径统计平均压缩比(示例 awk 脚本)
假设你想知道 /api/v1/users 和 /static/js/app.js 的平均压缩效果,可对日志做离线分析:
- 提取含有效压缩比的行(排除 “-”):
awk '$13 != "-" {print $7, $13}' /var/log/nginx/gzip-access.log - 按 URI 分组求平均(需先用 $request 字段提取 path,推荐用 Python 或 logstash 更可靠)
- 注意:$body_bytes_sent 是压缩后大小,$bytes_sent 是网络发送总字节数(含 header),二者差值≈header 大小,不可直接用于算压缩比
替代方案:用 OpenResty + header 注入近似比(需权衡精度)
若需在响应头中暴露压缩比供前端或 APM 工具采集,可借助 header_filter_by_lua_block 估算(非精确,但实用):
- 在响应体生成后、发送前,用
ngx.header注入自定义头:header_filter_by_lua_block {<br> if ngx.var.gzip_ratio and ngx.var.gzip_ratio ~= "-" then<br> ngx.header["X-Gzip-Ratio"] = ngx.var.gzip_ratio<br> end<br>} - ⚠️ 注意:此写法依赖 Nginx 日志模块内部机制,实际在 header filter 阶段
ngx.var.gzip_ratio仍为nil—— 真实可行做法是改用body_filter_by_lua_block缓存原始体长度(需开启subrequest或提前读取 body),但会显著增加内存与延迟,生产环境慎用
不复杂但容易忽略:$gzip_ratio 是日志世界的“快照”,不是运行时的仪表盘指标。想监控,就把它写进日志,再交给日志系统去算。











