开启 sendfile 后,nginx 静态文件传输路径从 4 次拷贝+4 次上下文切换缩减为 2 次拷贝+2 次上下文切换,cpu 使用率下降 30%~50%,qps 提升 1.5~2.3 倍,但需配套 tcp_nopush on、gzip off 等配置并避开代理、压缩等退化场景才能生效。

开启 sendfile 后,Nginx 处理静态文件请求的效率通常有明显提升,尤其在高并发、大文件或 CPU 受限场景下。核心差异不在“是否能返回文件”,而在于数据搬运路径和资源消耗方式。
数据拷贝与上下文切换次数减半
未启用 sendfile 时,Nginx 必须用 read() + write() 完成传输,整个过程涉及:
- 磁盘 → 内核缓冲区(DMA)
- 内核缓冲区 → 用户空间缓冲区(CPU 拷贝)
- 用户空间缓冲区 → Socket 缓冲区(CPU 拷贝)
- Socket 缓冲区 → 网卡(DMA)
共 4 次数据拷贝 + 4 次上下文切换,CPU 被大量用于内存搬运。
启用 sendfile 后,调用内核原生 sendfile64() 系统调用,路径简化为:
- 磁盘 → 内核缓冲区(DMA)
- 内核缓冲区 → Socket 缓冲区(内核态直传,零 CPU 拷贝)
- Socket 缓冲区 → 网卡(DMA)
仅需 2 次拷贝 + 2 次上下文切换;Linux 2.4+ 还支持 SG-DMA,可进一步跳过中间缓冲,逼近真正“零拷贝”。
CPU 占用率与吞吐量变化显著
实测中(如用 wrk 压测 1MB 静态文件):
- CPU 使用率通常下降 30%~50%,尤其在千级并发时更明显
- QPS(每秒请求数)可提升 1.5~2 倍,部分环境达 2.3 倍
- 平均响应延迟降低 20%~40%,抖动更小
这种差距不是线性叠加,而是随并发增长呈放大趋势——因为用户态拷贝会成为 CPU 调度瓶颈,而 sendfile 把压力转移到更高效的内核路径。
实际生效依赖协同配置
仅写 sendfile on; 不等于性能自动翻倍。必须避开常见退化点:
- 禁用运行时 gzip:设
gzip off;,改用gzip_static on;配合预压缩文件(如app.js.gz) - 确保文件来自真实磁盘路径(
root或alias指向本地 ext4/XFS 文件系统) - 搭配
tcp_nopush on;,让响应头与文件体合并发送,减少 TCP 小包 - 避免使用
sub_filter、add_after_body等修改响应体的模块
若启用了 gzip 或处理 Range 请求(如视频拖拽),Nginx 会自动回退到 read/write 模式,此时性能回落至未开启 sendfile 的水平。
验证是否真正在工作
不能只看配置,要确认内核是否实际调用了 sendfile64:
- 用
strace -p $(pgrep nginx) -e trace=sendfile64,read,write观察 worker 进程——正常应高频出现sendfile64,几乎无read/write - 对比开启前后
pidstat -u 1输出的 CPU 使用率,以及iostat -x 1中的 %util 和 r/s、w/s 变化 - 检查错误日志是否有
sendfile() failed,多见于 NFS 或权限异常
不复杂但容易忽略。











