sendfile指令是nginx静态文件零拷贝传输的分水岭,必须与tcp_nopush on和tcp_nodelay off协同配置,避开gzip、内容改写、非本地文件等失效条件,才能实现两次拷贝、降低cpu与上下文切换。

sendfile 指令是 Nginx 静态文件传输性能的关键开关,不是锦上添花的选项,而是决定是否走内核零拷贝路径的分水岭。启用得当,能将传统四次拷贝减为两次,大幅降低 CPU 占用、减少上下文切换、提升吞吐——尤其在图片、视频、JS/CSS 等静态资源分发场景下效果显著。
核心配置必须成套生效
单独写 sendfile on; 不足以触发优化,需与以下两项协同工作:
- tcp_nopush on;:让响应头和文件数据尽可能合并进同一个 TCP 包发送,减少小包数量,尤其利于首屏加载和高延迟链路
- tcp_nodelay off;:关闭 Nagle 算法,避免与 tcp_nopush 冲突;二者同时为 on 会相互抵消
常见失效场景必须避开
即使配置正确,只要出现以下任一情况,Nginx 就会自动退化为 read()+write() 模式,零拷贝失效:
- 启用了 gzip on 或 gunzip on(压缩必须进用户态)
- 使用了 sub_filter、add_before_body 等内容改写指令
- 文件不在本地真实磁盘路径(如 NFSv3、FUSE、Docker overlay2 默认驱动、符号链接指向非 ext4/XFS 文件系统)
- 响应缺失 Content-Length(例如代理后端未返回长度,或启用 chunked encoding)
- 客户端发起 Range 请求(如视频拖拽),Nginx 需切片处理
推荐搭配策略提升稳定性
这些设置不改变零拷贝路径,但能减少干扰、释放性能潜力:
- gzip_static on; + gzip off;:用预压缩的 .gz 文件替代运行时压缩,仍可走 sendfile
- sendfile_max_chunk 512k;:防止单次大文件传输阻塞事件循环,适合多数静态资源大小
- open_file_cache max=10000 inactive=60s;:缓存文件句柄与元信息,降低高并发下的 open/stat 开销
- access_log off;:纯静态 location 中关闭日志,避免 I/O 成瓶颈
验证是否真正生效
不能只看配置语法,要确认运行时行为:
- 用 strace -p $(pgrep nginx | head -1) -e trace=sendfile64 观察 worker 进程是否持续调用 sendfile64 系统调用
- 压测对比:开启前后,CPU 的 sy(系统态)占比应明显下降,QPS 提升通常达 20%–50%
- 检查错误日志是否有 sendfile() failed 类报错,提示底层文件系统或权限问题











