sendfile 实现零拷贝需同时启用 sendfile on、tcp_nopush on、tcp_nodelay off 三项指令,避开 gzip、内容改写、非本地文件等失效条件,并通过 strace 和 cpu sy 占比验证生效。

sendfile 是 Linux 下 Nginx 实现零拷贝传输的核心机制,但开个 sendfile on; 远不够——它必须和配套参数协同、避开失效条件,才能真正走内核直传路径。
✅ 必须配置的三项基础指令(缺一不可)
这三项建议统一写在 http { ... } 块顶层,确保全局生效:
sendfile on;
启用内核级文件传输,跳过用户空间拷贝。tcp_nopush on;
让 Nginx 等待响应头 + 文件数据填满 TCP 缓冲区再发包,避免小包泛滥;它只在sendfile路径下起作用。tcp_nodelay off;
关闭 Nagle 算法,防止与tcp_nopush冲突;二者不能同时为on。
⚠️ 注意:
tcp_nopush on和tcp_nodelay on同时启用会互相抵消,Nginx 日志中会出现tcp_nopush is ignored警告。
? 常见导致 sendfile 失效的配置(务必避开)
只要触发以下任一情况,Nginx 就会自动退化为 read() + write() 模式,零拷贝失效:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 启用了
gzip on;或gunzip on;(压缩必须进用户态) - 使用了
sub_filter、add_before_body、access_by_lua_block等内容改写或注入指令 - 文件不在本地真实磁盘(如 NFS、CIFS、Docker overlay2 默认层、FUSE、符号链接指向非 ext4/XFS 文件系统)
- 响应未带准确
Content-Length(比如后端代理返回 chunked、或文件被其他进程锁住) - 客户端发起
Range请求(如视频拖拽),且未适配支持 sendfile 的内核版本
? 替代方案:用
gzip_static on;配合gzip off;,提供预压缩.gz文件,仍可走 sendfile。
? 推荐补充优化项(不破坏零拷贝,但提升稳定性)
sendfile_max_chunk 512k;
限制单次 sendfile 调用的数据量,防止单个大文件阻塞事件循环,适合图片/JS/CSS 等常见静态资源大小。open_file_cache max=10000 inactive=60s;
缓存文件句柄和元信息,大幅减少高并发下的open()/stat()系统调用。access_log off;
在纯静态资源 location 中关闭访问日志,避免 I/O 成瓶颈(若需日志,建议异步写入或单独归档)。
? 怎么确认 sendfile 真正在工作?
配置正确 ≠ 运行生效。验证必须看实际行为:
- 用
strace -p $(pgrep nginx | head -1) -e trace=sendfile64观察 worker 进程是否持续调用sendfile64系统调用 - 对比压测前后 CPU 的
sy(系统态)占比:真实生效时应明显下降,QPS 通常提升 20%–50% - 查看
error.log是否出现sendfile() failed类报错(常见于权限不足、SELinux 限制、NFS 不支持等)
? 提示:Windows 下
sendfile on;实际无效,仅降级为普通读写;生产环境务必部署在 Linux。
不复杂但容易忽略。










