nginx 通过 log_format 配合 $body_bytes_sent 可轻量可靠地实时统计各站点下行流量:定义含 $server_name 和 $body_bytes_sent 的日志格式,各 server 块启用该 access_log;再用 tail + awk 流式聚合,或 nginxlog-exporter 接入 prometheus 实现监控与告警。

Nginx 的 log_format 配合 $body_bytes_sent 是实时统计各站点下行流量最轻量、最可靠的方式之一,无需额外代理或埋点,直接从访问日志中聚合即可。
配置自定义日志格式,按 server_name 区分站点
在 http 块中定义带站点标识和字节数的日志格式:
log_format site_traffic '$server_name $remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
关键点:
-
$server_name能准确标识当前匹配的 server 块(注意:不是$host,后者可能被客户端篡改) -
$body_bytes_sent是响应体实际发出的字节数(不含响应头),真实反映下行流量 - 确保每个
server块都启用该格式,例如:access_log /var/log/nginx/example.com.access.log site_traffic;
用 tail + awk 实时汇总每秒/每分钟流量
对单个日志文件做流式统计(以每秒为粒度):
tail -f /var/log/nginx/*.access.log | \
awk '{bytes[$1] += $NF}
NR % 100 == 0 {
for (s in bytes) print strftime("%H:%M:%S"), s, bytes[s] "B";
delete bytes
}'
说明:
-
$1是$server_name,$NF是最后一列即$body_bytes_sent -
NR % 100 == 0表示每累计 100 行输出一次(可根据 QPS 调整频率) - 如需按分钟聚合,可用
date -d @$(date +%s) +%-M提取分钟字段再分组
接入 Prometheus + Grafana 做长期监控
用 nginxlog-exporter 解析日志并暴露指标:
logs:
- file: "/var/log/nginx/*.access.log"
format: "$server_name $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""
labels:
app: "nginx-site"
它会自动导出如 nginx_log_entry_body_bytes_sent_sum{server_name="api.example.com"} 这类指标,配合 PromQL 即可计算:
- 当前下行速率:
rate(nginx_log_entry_body_bytes_sent_sum[1m]) - 各站点占比:
nginx_log_entry_body_bytes_sent_sum by (server_name) - 异常突增告警:
increase(nginx_log_entry_body_bytes_sent_sum[5m]) > 10 * 1024 * 1024(5 分钟超 10MB)
注意事项与常见陷阱
几个容易导致统计失真的细节:
-
$body_bytes_sent不包含 304 响应的字节(为 0),但这类响应本就不下发 body,属正常 - 如果启用了 gzip 或 brotli 压缩,
$body_bytes_sent是压缩后大小,更贴近真实带宽消耗 - 避免在日志中混用
$host和$server_name—— 前者不可信,后者才代表 Nginx 实际路由到的站点 - 日志轮转时需确保
nginxlog-exporter或tail进程能平滑切换文件句柄(推荐用inotifywait或 exporter 自带轮转支持)










