Nginx 不记录 sendfile 零拷贝的字节数与耗时,因其为内核态操作,日志模块仅记录用户态元信息;$request_time 和 $bytes_sent 均不区分传输路径。

Nginx 本身不直接记录 sendfile 零拷贝传输的字节数与耗时,无法通过标准 access_log 或 error_log 直接统计。这是因为 sendfile() 是内核态操作,Nginx 日志模块只记录用户态可见的请求/响应元信息(如 $bytes_sent、$request_time),并不感知底层是否走零拷贝路径,也不测量其内核执行时间。
为什么 Nginx 日志里没有 sendfile 耗时和零拷贝字节数
Nginx 的 $request_time 是从接收首字节到发送完响应头的时间(含 upstream 等待),不区分内核 sendfile 还是用户态 read+write;$bytes_sent 是最终发出的总字节数,不管是否经由 sendfile。即使启用了 sendfile on,Nginx 也只在满足条件时(如文件未被 proxy_buffering 缓存、非 chunked、无 header filter 修改等)才调用 sendfile(),且该决策和执行过程不暴露给日志模块。
间接判断 sendfile 是否生效的方法
- 检查 Nginx 配置:
sendfile on;、tcp_nopush on;(配合 sendfile 提升效率)、directio 4m;(慎用,可能禁用 sendfile) - 确认请求命中静态文件服务路径,且未被 proxy_pass / sub_filter / gzip_vary 等模块干预
- 用
strace -e trace=sendfile64 -p $(pidof nginx)抓取 worker 进程系统调用,观察是否出现sendfile64(…)调用及返回值(成功时返回实际拷贝字节数) - 结合
/proc/net/snmp或ss -i观察 TCP 发送队列行为,高吞吐低 CPU 通常是 sendfile 起效的佐证
替代方案:用 eBPF 工具精确观测 sendfile 行为
若需真实统计零拷贝传输字节数与内核耗时,需绕过 Nginx 日志,直接在内核层面观测:
- 推荐 bpftrace:运行以下脚本可统计每个 sendfile64 调用的字节数与延迟(纳秒级)
bpftrace -e '
kprobe:sys_sendfile64 {
@start[tid] = nsecs;
}
kretprobe:sys_sendfile64 /@start[tid]/ {
$duration = nsecs - @start[tid];
$bytes = retval;
@bytes_total = sum($bytes);
@count = count();
@latency_us = hist($duration / 1000);
delete(@start[tid]);
}'
- 输出包含:
@bytes_total(总零拷贝字节数)、@count(调用次数)、@latency_us(微秒级延迟分布) - 配合
nginx -t和kill -USR2控制测试窗口,避免干扰生产流量
实用建议:用 Nginx 指标 + 系统指标交叉验证
- 开启
stub_status,监控Active connections和Reading/Writing/Waiting状态变化趋势 - 用
pidstat -d -p $(pidof nginx) 1查看 Nginx 进程 I/O wait 和磁盘读字节数 —— 若sendfile高效,Blk_read/s应显著低于Bytes_sent/s(因内核直接 DMA 送网卡,不经过用户态缓冲) - 对比关闭/开启
sendfile时的 CPU 使用率(top -p $(pidof nginx))和 QPS:通常开启后 sys CPU 下降、QPS 上升,即零拷贝起效


















