必须同时启用sendfile on、tcp_nopush on且tcp_nodelay off,并避开gzip、代理、内容改写及非本地文件等退化条件,才能真正触发内核零拷贝;单独配置任一指令均无效,且仅对真实静态文件生效。

开启 sendfile 后,真正提升大文件传输效率的关键不是“开了就行”,而是让零拷贝路径稳定跑通,并配合内核网络栈协同发力。单开 sendfile on 只是起点,必须成对启用、按需配置、避开退化条件,才能把性能拉满。
必须成对启用 sendfile 和 tcp_nopush
tcp_nopush 不是独立优化项,它只在 sendfile 路径下生效:Nginx 把响应头和文件开头数据合并进同一个 TCP 报文发出,减少首包往返延迟(RTT)和小包数量。若没开 sendfile,tcp_nopush 实际被忽略,日志中会提示 “tcp_nopush is ignored”。
- 两者必须同时出现在同一 location 块中,不能只靠 http 或 server 块继承
- tcp_nodelay 必须显式设为 off——它和 tcp_nopush 逻辑冲突,开启会强制立即发包,直接抵消攒包效果
只在匹配大静态文件的 location 中启用
全局开启容易误伤 API、WebSocket、动态接口等低延迟服务。应按后缀精准控制,例如:
location ~ \.(mp4|webm|zip|iso|tar\.gz|dmg)$-
root /data/assets;(确保路径真实、可读、非 NFSv3/FUSE 等不支持 sendfile 的挂载点) - 避免用 alias 指向非 root 下的路径,旧版本 Nginx 对 alias + sendfile 兼容性不稳定
堵住 sendfile 自动退化的所有漏洞
哪怕配置全对,只要触发以下任一条件,Nginx 就会悄悄回退到 read/write 模式,失去零拷贝优势:
- 响应头缺失
Content-Length:Nginx 无法预知大小,不敢调用 sendfile();代理后端必须返回该头,禁用proxy_buffering on - 启用了 gzip、sub_filter、access_by_lua_block、X-Accel-Redirect(非本地路径)等用户态处理模块
- 文件被 mmap 锁定、或位于 SELinux 限制目录、容器默认 overlay2 存储驱动下(可用
strace -e trace=sendfile64验证是否调用)
补充调优提升稳定性与吞吐
在核心指令到位基础上,加几项轻量配置能进一步释放性能:
-
sendfile_max_chunk 512k:防止单次 sendfile 阻塞事件循环,适合高清视频首段加载 -
gzip off:必须关闭运行时压缩;如需压缩,改用gzip_static on提前提供 .gz 文件 -
open_file_cache max=10000 inactive=60s;:缓存文件句柄和元信息,减少高并发下的 open/stat 系统调用 -
expires 7d; add_header Cache-Control "public, immutable";:降低重复请求压力,间接减轻 sendfile 负载











