sendfile on 可将1Gbps场景CPU占用从60%~90%降至5%~15%,因其绕过用户态实现零拷贝;而gzip on、Range请求、NFS存储等会导致退化,需配合gzip_static、tcp_nopush、open_file_cache等配置保障实效。

在1Gbps网卡满载场景下,sendfile on 与 sendfile off 的 CPU 占用率差异非常显著——前者通常仅需 5%~15% 的单核 CPU,后者则可能飙升至 60%~90%,甚至触发多核争抢。这不是配置“开不开”的问题,而是数据路径是否绕过用户态的关键分水岭。
为什么1Gbps下CPU占用差距这么大?
1Gbps ≈ 125MB/s,看似不高,但传统 read/write 模式每秒要搬运 125MB × 2 次(内核→用户→socket),并伴随同等次数的上下文切换。以典型 x86 服务器为例:
- 每次内存拷贝消耗约 100–300 纳秒 CPU 时间,叠加频繁中断,累积开销巨大
- 每秒数万次上下文切换会显著拉高调度负载,尤其在高并发短连接场景
- sendfile 启用后,CPU 主要只做控制流调度,数据搬运由 DMA 和内核零拷贝通路完成
真实压测中必须避开的“伪启用”陷阱
即使配置了 sendfile on;,以下情况会让 Nginx 回退到低效路径,CPU 占用瞬间回归高位:
- 启用了
gzip on:运行时压缩强制进用户态,彻底破坏零拷贝链路 - 响应头含
ETag或Last-Modified且未缓存元数据:Nginx 需 stat 文件并计算哈希,触发用户态介入 - 客户端发起
Range: bytes=100-199请求:无法整块直传,必须读取+切片+构造响应体 - 静态文件放在 NFS 或 CIFS 共享存储上:多数网络文件系统不支持 sendfile 系统调用
让 sendfile 在1Gbps下稳定发挥的硬性配套
单开 sendfile on 不足以守住性能底线,必须组合以下配置堵住退化漏洞:
- 用
gzip_static on;替代gzip on:提前生成.gz文件(如app.js.gz),Nginx 直接 sendfile 返回,全程不进用户态 - 显式关闭运行时压缩:
gzip off;,避免模块隐式干扰 - 开启
tcp_nopush on;:让 sendfile 数据攒够 TCP MSS 再发,减少小包数量,降低协议栈处理压力 - 启用
open_file_cache max=10000 inactive=60s;:缓存文件句柄和 inode、mtime 等元数据,避免每次请求都触发 open/stat 系统调用
如何验证 sendfile 是否真正在跑?
不能只看配置文件,得看内核实际行为:
- 用
strace -p $(pgrep -f "nginx: worker") -e trace=sendfile,read,write实时跟踪 worker 进程 - 持续看到
sendfile(…)调用,且几乎无read(…)/write(…),说明路径畅通 - 若大量出现
read(…)+write(…)成对调用,说明已退化,需立即检查上述失效条件



















