必须同时启用sendfile on、tcp_nopush on和tcp_nodelay off,且避开gzip、sub_filter、代理及非本地文件等失效条件,才能真正触发内核零拷贝;仅配置sendfile on无效。

要让 Nginx 真正用上 sendfile 零拷贝加速静态文件传输,关键不是只写 sendfile on;,而是让内核能“直通搬运”——数据从磁盘页缓存直接送到网卡,不进用户态、不拷贝、不切换上下文。
必须同时启用的三个指令
这三项缺一不可,且必须成套出现在同一作用域(推荐放在 http 块或具体 location 中):
- sendfile on;:开启零拷贝能力,是整条路径的启动开关
- tcp_nopush on;:配合 sendfile,让内核攒满 TCP 包再发,减少小包数量,提升吞吐
- tcp_nodelay off;:关闭 Nagle 算法,避免它与 tcp_nopush 冲突;设为 on 会强制立即发包,直接废掉攒包效果
确保文件满足零拷贝前提
即使配置全对,只要文件不“够格”,Nginx 就会自动退回到低效的 read()+write() 模式:
- 文件必须是本地真实磁盘文件(ext4/xfs 推荐),不能是 NFS、CIFS、FUSE 或容器卷挂载点
- 不能启用 gzip、gunzip、gzip_static(压缩必须在用户态做,会绕过零拷贝)——若需压缩,改用预压缩的
.gz文件 +gzip_static on;+gzip off; - 不能有内容改写行为:如
sub_filter、add_before_body、Lua 脚本修改响应体 - 不能走代理:禁用
proxy_pass、fastcgi_pass等,必须由root或alias直接提供文件 - 响应需带
Content-Length头(即不能是 chunked 编码)
按资源类型精准配置更稳妥
不建议在全局 http 块盲目开启,而是针对不同后缀做细粒度控制:
- 图片类:
location ~* \.(jpg|png|webp|gif|svg)$ { sendfile on; tcp_nopush on; tcp_nodelay off; gzip off; access_log off; } - 大文件类:
location ~ \.(mp4|zip|iso)$ { sendfile on; tcp_nopush on; tcp_nodelay off; sendfile_max_chunk 512k; expires 7d; }(sendfile_max_chunk防止单次调用阻塞事件循环)
配套优化进一步释放性能
这些不改变零拷贝路径,但能减少干扰、提升稳定性:
-
open_file_cache max=10000 inactive=60s;:缓存文件句柄和元信息,降低重复stat()和open()开销 -
access_log off;:纯静态资源 location 中关闭日志,避免高并发下 I/O 成瓶颈 -
expires或Cache-Control:配合浏览器缓存,从源头减少请求数量
验证是否生效,别只看配置是否加载成功。可用 strace -p $(pgrep nginx) -e trace=sendfile64 观察 worker 进程是否持续调用 sendfile64 系统调用;同时对比开启前后 CPU 的 sy(系统态)占比和 QPS 变化,效果通常明显。











