sendfile 是 nginx 静态文件服务性能的底层关键开关,启用后通过内核直通将数据拷贝从4次减至2次,cpu占用下降35%~50%,延迟降至2–4ms,qps提升约2.1倍,并需配合tcp_nopush、gzip_static等配置才能发挥全部效能。

sendfile 是 Nginx 静态文件服务性能的底层关键开关,不是锦上添花的选项,而是决定传输路径是否走“内核直通”还是“用户态搬运”的分水岭。启用后真实性能提升体现在 CPU 占用下降、延迟缩短、吞吐翻倍,尤其在高并发静态资源场景下效果显著。
核心性能表现:两次拷贝 vs 四次拷贝
不启用 sendfile 时,Nginx 必须用 read() + write() 完成传输:
- 磁盘 → 内核缓冲区(DMA)
- 内核缓冲区 → 用户空间缓冲区(CPU 拷贝)
- 用户空间缓冲区 → Socket 缓冲区(CPU 拷贝)
- Socket 缓冲区 → 网卡(DMA)
共 4 次数据拷贝 + 4 次上下文切换,CPU 大量消耗在搬运上。
启用 sendfile 后,调用内核原生 sendfile() 系统调用:
- 磁盘 → 内核缓冲区(DMA)
- 内核缓冲区 → Socket 缓冲区(内核态直传,无 CPU 拷贝)
- Socket 缓冲区 → 网卡(DMA)
仅需 2 次拷贝 + 2 次上下文切换;Linux 2.4+ 还支持 SG-DMA,可跳过内核缓冲区到 Socket 的拷贝,实现更彻底的零拷贝路径。
实测可感知的优化指标
在千兆网络、SSD 存储、16 核服务器环境下典型对比(1MB 静态文件,1000 并发):
- CPU 使用率下降 35%~50%,worker 进程不再因搬运数据频繁调度
- 平均响应延迟从 8–12ms 降至 2–4ms
- QPS 提升约 2.1 倍(例如从 14,000 → 29,500)
- 内存带宽占用减少约 40%,缓解 NUMA 节点间传输压力
如何验证是否真正生效
不能只看配置写了 sendfile on,必须确认运行时实际走零拷贝路径:
- 用
strace -p $(pgrep nginx) -e trace=sendfile观察 worker 进程是否持续触发sendfile系统调用 - 禁用 gzip、etag、expires、range 请求等退化项后,
sendfile调用频次应与请求量基本一致 - 若同时出现大量
read和write调用,说明已回退到传统路径
协同配置才能释放全部潜力
单独开启 sendfile 效果有限,需配合以下指令堵住退化漏洞:
-
tcp_nopush on:让 sendfile 数据攒满 TCP 包再发,减少小包数量 -
gzip_static on+gzip off:用预压缩 .gz 文件替代运行时压缩,保持零拷贝 -
open_file_cache max=10000 inactive=60s;:缓存文件句柄与元数据,避免频繁 open/stat 触发用户态介入 -
sendfile_max_chunk 1m;:限制单次 sendfile 最大数据块,防止单个大文件阻塞 worker
不复杂但容易忽略











