Nginx 真正启用 sendfile 零拷贝需同时配置 sendfile on、tcp_nopush on、tcp_nodelay off,且文件必须为本地磁盘文件、禁用 gzip/sub_filter/代理、响应带 Content-Length,否则退化为 read()+write() 模式。

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


















