Nginx访问日志统计带宽需同时记录$body_bytes_sent和$request_time,通过后端计算比值得到字节/秒速率;推荐使用tab分隔的bandwidth_rate格式,并用awk解析过滤无效值。

要在 Nginx 访问日志中统计带宽消耗,核心不是直接记录“带宽”,而是记录两个基础指标:响应内容长度(即实际发出去的字节数)和整个请求耗时,再在日志分析阶段做除法估算平均传输速率(字节/秒)。Nginx 本身不支持日志格式里写表达式(比如 $body_bytes_sent / $request_time),所以必须分开记录、后端计算。
关键变量必须同时启用
要还原单次请求的下行吞吐表现,日志中至少得包含以下两项:
- $body_bytes_sent:只计响应体(body)字节数,不含响应头。适合评估大文件、API 返回体等“有效载荷”的传输效率;
-
$request_time:从接收到第一个请求字节,到发送完最后一个响应字节的总耗时(单位:秒,精度毫秒,如
0.187)。它覆盖了 Nginx 自身处理、上游等待、响应发送全过程。
二者缺一不可。如果只记 $upstream_response_time,会漏掉 Nginx 发送响应头/体的时间;如果用 $bytes_sent,它含响应头,对小响应(如 304、204)更全面,但和纯 body 的带宽语义略有差异。
推荐的日志格式配置
在 http 块中定义清晰、易解析的格式,建议用制表符分隔避免字段错位:
log_format bandwidth_rate '$time_iso8601\t$uri\t$status\t$body_bytes_sent\t$request_time';<br>access_log /var/log/nginx/bandwidth.log bandwidth_rate buffer=64k flush=2s;
说明:
-
$time_iso8601时间格式统一,便于按小时/分钟聚合; -
\t分隔符比空格更可靠,尤其当$uri含空格或特殊字符时; -
buffer和flush提升 I/O 效率,2 秒延迟对带宽趋势分析无实质影响。
日志解析时计算带宽(bytes/sec)
拿到日志后,用命令行工具逐行计算并过滤无效值(比如传输 0 字节或耗时 ≤0):
awk -F'\t' '$4 > 0 && $5 > 0 { printf "%s\t%s\t%.0f\n", $1, $2, $4/$5 }' /var/log/nginx/bandwidth.log输出示例:
2026-09-04T20:15:22+00:00 /download/bigfile.zip 200 14200000该值单位是字节/秒(B/s)。如需 KB/s,除以 1024;如需 Mbps(兆比特每秒),用 ($4/$5 * 8) / 1000000。
注意适用边界与常见误判
这个比值反映的是服务端视角的平均下行速率,并非客户端真实物理带宽:
- 对小响应(如 JSON 接口,body 只有几百字节),
$request_time中的固定开销(SSL 握手、TCP 建连、Nginx 路由)占比高,算出的“带宽”会严重失真,建议按路径过滤(如只分析/download/或/stream/); - 若大量请求
$request_time很长但$body_bytes_sent很小,问题大概率不在网络,而在后端处理慢或 Nginx 配置阻塞(如正则重写复杂、limit_rate 限制); - 304、204 等无 body 响应,
$body_bytes_sent = 0,此时该比值无意义,应改用$bytes_sent统计含 header 的总发送量。


















