应使用 $bytes_sent 统计带宽,它表示发送给客户端的响应体字节数(不含响应头),真实反映网络层带宽占用,且不受 gzip 压缩影响;需结合时间、IP 等维度分析,并注意 limit_rate、HTTP/2 等场景偏差。

在 Nginx 中,要评估服务器带宽消耗,关键就是准确记录每个请求响应体的实际传输字节数。Nginx 默认日志变量 $bytes_sent 正是为此设计的——它表示**已发送给客户端的响应体字节数(不含响应头)**,是统计带宽最可靠的基础指标。
使用 $bytes_sent 记录真实传输量
$bytes_sent 是 Nginx 内置变量,包含 HTTP 响应体(body)的原始字节大小。它不受 gzip 压缩影响(记录的是压缩后实际发出的字节数),也不包含响应头、TCP/IP 包开销或 SSL/TLS 开销,因此能较真实反映网络层带宽占用。
- 确保日志格式中包含该变量,例如:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $bytes_sent "$http_referer" "$http_user_agent"'; - 该值在请求完成(包括所有 chunked 分块发送完毕)后才最终确定,所以可用于完整请求统计
- 对空响应(如 304、204)或仅含响应头的请求,
$bytes_sent为 0
区分 $bytes_sent 和 $body_bytes_sent
$body_bytes_sent 是一个容易混淆的变量:它只记录**响应体中由后端应用(如 PHP、FastCGI)生成并写入的原始字节数**,不包含 Nginx 自己添加的内容(如错误页、重定向 Location 头对应的 body、add_header 添加的 body 片段等)。
- 若用 proxy_pass 或 fastcgi_pass,且后端返回非空 body,两者通常接近;但遇到 Nginx 自行生成响应(如 404 页面、rewrite 后内部跳转、limit_rate 触发的截断),
$bytes_sent更全面 - 带宽评估应优先用
$bytes_sent,它是“线缆上真正跑出去的响应体字节数”
结合时间与客户端维度做带宽分析
单看字节数不够,需关联时间窗口和访问来源才能定位带宽压力点:
- 按小时聚合:
awk '{sum+=$10} /2024:14:/ {print sum; sum=0}' access.log(假设 $10 是 $bytes_sent 字段) - 按 IP 统计 Top 10 流量用户:
awk '{ip[$1]+=$10} END{for (i in ip) print ip[i], i}' access.log | sort -nr | head -10 - 过滤大文件下载(如 >1MB):
awk '$10 > 1048576 {print $0}' access.log
注意常见偏差场景
以下情况会导致 $bytes_sent 不能完全代表“客户端收到的全部数据”,需结合业务理解:
- 启用 gzip:$bytes_sent 是压缩后大小,更贴近真实带宽;如需原始内容体积,可配合 $sent_http_content_length(但该值可能为空或不准确)
- 使用 limit_rate:$bytes_sent 反映实际发出字节数,可用于验证限速是否生效
- HTTP/2 多路复用:$bytes_sent 仍按请求粒度统计,不体现帧开销;整体带宽需看系统级 netstat 或 eBPF 工具
- 长连接 + 多请求:每个请求单独记录,总带宽 = 所有 $bytes_sent 之和


















