直接启用 sendfile on 不能自动提升性能,必须配套 tcp_nopush on、tcp_nodelay off,并避开 gzip、代理、内容改写、非本地存储、Range 请求等退化场景,才能真正触发内核零拷贝。

直接启用 sendfile on 并不能自动提升性能,必须配合关键指令、避开退化路径,并确保运行环境满足前提条件,才能真正触发内核零拷贝。
核心配置三要素缺一不可
单独开启 sendfile 无效,必须成套配置:
- sendfile on;:激活内核直传能力,跳过用户态内存拷贝
- tcp_nopush on;:让 Nginx 等待响应头和文件数据填满 TCP 缓冲区再发包,减少小包数量,发挥 sendfile 批量传输优势
-
tcp_nodelay off;:关闭 Nagle 算法;若设为
on,会强制立即发包,与tcp_nopush冲突,导致优化失效
必须避开的退化场景
以下任一情况都会让 Nginx 自动回退到传统的 read() + write() 模式,sendfile 彻底失效:
- 启用了
gzip on或gunzip on:压缩/解压必须在用户态完成 - 使用了
proxy_pass、fastcgi_pass等代理指令 - 配置了
sub_filter、add_before_body等内容改写功能 - 静态文件不在本地真实磁盘(如挂载的 NFSv3、FUSE、某些容器存储驱动)
- 客户端发起 Range 请求(如视频拖拽),Nginx 需切片处理,无法整块直传
推荐补充的协同优化项
这些不改变零拷贝路径,但能显著降低干扰、释放性能潜力:
-
gzip_static on; gzip off;:提前生成
.gz文件(如app.js.gz),Nginx 直接返回,仍走 sendfile 路径 -
open_file_cache max=10000 inactive=60s;:缓存文件句柄、修改时间等元信息,避免高并发下反复
stat()和open() - access_log off;:纯静态资源 location 中关闭访问日志,大幅减轻 I/O 与 CPU 压力
- sendfile_max_chunk 512k;:限制单次 sendfile 数据量,防止单个大文件阻塞事件循环,适合图片、JS、短视频首段加载
验证是否真实生效
不能只看配置是否写对,要确认运行时走的是零拷贝路径:
- 用
strace -p $(pgrep nginx) -e trace=sendfile64观察 worker 进程是否持续调用sendfile64系统调用 - 若同时大量出现
read和write,说明已退化,需排查上述退化条件 - 压测对比:1MB 文件、1000 并发下,开启后 CPU sy 占比应下降 35%–50%,QPS 提升约 2 倍



















