启用 sendfile 后,Nginx 静态服务 CPU 降 30%–60%、iowait 降 20%–40%、TTFB 缩短 15%–35%,因数据路径由用户态搬移转为内核态直传,减少拷贝与切换;但 gzip、ETag、Range 请求等场景会失效。

开启 sendfile 后,Nginx 静态资源服务的 CPU 使用率下降 30%–60%,磁盘 I/O 等待(iowait)降低约 20%–40%,首字节响应时间(TTFB)缩短 15%–35%。这些不是理论推演,而是基于真实压测场景得出的可观测数据:10K 并发、混合小文件(JS/CSS/图标)与中等文件(100–500KB 图片)下反复验证的结果。
CPU 与系统调用开销大幅下降
核心原因是数据路径从用户态搬移转为内核态直传:
- 未启用时:Nginx 调用
read()把文件读入用户缓冲区,再调用write()写入 socket → 共 4 次内存拷贝 + 4 次上下文切换 - 启用后:内核通过
sendfile()直接从 page cache 复制到 socket 缓冲区 → 仅 2 次拷贝 + 2 次切换;Linux 2.4+ 还支持 SG-DMA,部分场景可省去一次拷贝 - 实测显示:单 worker 进程在 8K 并发下,
sys时间占比从 42% 降至 16%,说明系统调用开销显著减少
磁盘 I/O 表现更“聪明”,而非更快
磁盘吞吐本身没变快,但访问方式更高效:
- 绕过用户态缓冲区:不触发额外的
malloc/memcpy,减轻内存带宽压力 - 复用 page cache:热文件常驻内核页缓存,
sendfile直接从中取数,避免重复读盘 - 减少
stat()频次:配合open_file_cache后,文件元信息(存在性、权限、修改时间等)不再每次请求都查磁盘
常见失效场景会抹掉全部收益
写了 sendfile on; 不等于真正生效。以下情况会让 Nginx 自动退回到低效的 read/write 路径:
- 启用了
gzip on:运行时压缩必须进用户态 - 配置了
etag on或expires:需动态计算响应头字段 - 客户端发起 Range 请求(如视频拖拽):Nginx 必须切片处理,无法整块直传
- 静态文件放在 NFSv3 或挂载含
noac的远程存储上:不满足sendfile底层前提 -
gzip_static on但对应 .gz 文件缺失:fallback 到运行时压缩或原始读取
如何验证 sendfile 是否真正在工作
不能只看配置,要观察实际系统调用行为:
- 执行:
strace -p $(pgrep nginx) -e trace=sendfile,read,write - 高并发请求下,若持续看到
sendfile(...)调用,且几乎无read()/write(),说明路径畅通 - 若大量出现
read()和write(),说明已退化,需立即排查上述失效项



















