Nginx 中 sendfile 真正生效需同时启用 sendfile on、tcp_nopush on、tcp_nodelay off 三指令,并避开 gzip、内容改写、非本地文件等失效条件,否则自动退化为 read()+write() 模式。

在 Nginx 配置文件中开启 sendfile 不是加一行就完事,而是要成套配置、避开失效条件,才能真正走内核零拷贝路径。
核心三指令必须同时启用
这三项需统一写在 http 块顶层(全局生效),缺一不可:
-
sendfile on;—— 启用零拷贝基础能力,让数据绕过用户态直接从磁盘送入 socket 缓冲区 -
tcp_nopush on;—— 让响应头和文件数据尽量合并进同一个 TCP 包发送,减少小包数量 -
tcp_nodelay off;—— 关闭 Nagle 算法,避免与tcp_nopush冲突;二者同时为on会互相抵消
关键失效场景必须避开
哪怕配置全对,只要出现以下任一情况,Nginx 就自动退化为 read() + write() 模式,sendfile 形同虚设:
- 启用了
gzip on或gunzip on(压缩必须进用户态) - 使用了
sub_filter、add_before_body等内容改写指令 - 文件不在本地真实磁盘(如 NFS、Docker overlay2 默认驱动、符号链接指向非 ext4/XFS 文件系统)
- 响应缺失
Content-Length(例如后端未返回长度,或启用 chunked encoding) - 客户端发起
Range请求(如视频拖拽)
推荐补充配置提升稳定性
这些不改变零拷贝路径,但能减少干扰、释放性能潜力:
-
sendfile_max_chunk 512k;—— 防止单次大文件传输阻塞事件循环,适合图片/JS/CSS 平均大小 -
open_file_cache max=10000 inactive=60s;—— 缓存文件句柄与元信息,降低高并发下open/stat开销 -
access_log off;—— 纯静态资源 location 中关闭日志,避免 I/O 成瓶颈 -
gzip_static on; gzip off;—— 用预压缩的.gz文件替代运行时压缩,仍可走sendfile
如何验证是否真正生效
不能只看配置写了 sendfile on,要确认运行时行为:
- 用
strace -p $(pgrep nginx) -e trace=sendfile64观察 worker 进程是否持续调用sendfile64系统调用 - 压测对比:开启前后,CPU 的
sy(系统态)占比应明显下降,QPS 提升通常达 20%–50% - 若同时看到大量
read和write调用,说明已回退到传统路径,需排查上述失效项



















