sendfile与tcp_nopush必须成对启用、按location精准配置并满足三个前提(sendfile on、真实静态文件、含content-length)才能协同生效;单独开启或配置不当均无效。

要真正提升大文件(如视频、安装包、高清图片)的分发效率,sendfile 和 tcp_nopush 必须成对启用、协同工作,且仅在满足运行时条件的 location 中才生效。单独开启任一指令,或配置位置不当,都等于没配。
必须同时满足的三个硬性前提
这两个指令不是“写上就起效”,Nginx 每次响应都会动态判断是否走零拷贝路径。缺一不可:
- 当前 location 显式启用 sendfile on:不能只靠 http 块继承,需在具体资源路径中写明;
- 服务的是真实磁盘静态文件:例如 root /data/assets + location ~ \.mp4$,且文件存在、可读、未被 SELinux 或容器存储驱动拦截;
- 响应头含 Content-Length:Nginx 需提前知道大小才能调用 sendfile() 系统调用;若后端返回 chunked 编码、流式响应或无长度头,会自动回退到 read/write 模式。
为什么 tcp_nopush 依赖 sendfile
tcp_nopush 的作用是让内核把 HTTP 响应头和文件开头数据“合并进一个 TCP 报文”发出——但这只有在 sendfile 路径下才可能实现:
- sendfile 启用后,数据由内核直接从页缓存搬入 socket 发送队列,响应头 + 文件首段被视为逻辑连续的数据块;
- 普通 read/write 模式中,Nginx 先读到用户态 buffer 再 write 到 socket,数据分段进入发送队列,tcp_nopush 无法识别“完整首块”,此时配置会被忽略(日志提示 “tcp_nopush is ignored”);
- gzip、sub_filter、proxy_buffering on、access_by_lua_block 等任何用户态处理都会强制退出该路径。
推荐的 location 级精细化配置
不要在 http 或 server 块全局开启,避免干扰 API、WebSocket 等低延迟服务。按文件类型精准控制:
location ~ \.(mp4|webm|avi|mov|zip|iso|tar\.gz|dmg)$ {
root /data/assets;
sendfile on;
tcp_nopush on;
tcp_nodelay off; # 必须显式关闭,否则抵消“攒包”效果
gzip off; # 关键!压缩会禁用 sendfile
expires 7d;
add_header Cache-Control "public, immutable";
}
- 若代理后端(如对象存储),加 proxy_buffering off; 并确保上游返回 Content-Length;
- 大文件建议加 sendfile_max_chunk 512k; 防止单次传输阻塞事件循环;
- 涉及 Range 请求(如视频拖拽),sendfile 在主流 Linux 内核下仍兼容,无需额外关闭。
配套关键参数与验证要点
优化效果受周边配置强影响,需同步对齐:
- tcp_nodelay 必须为 off:它与 tcp_nopush 互斥;默认值虽为 off,但显式写出可防继承污染;
- 禁用 access_log 对高频小文件可减压:location 内加 access_log off;;
- 验证是否生效:检查错误日志有无 “tcp_nopush is ignored” 或 “sendfile() failed”;用 strace -p $(pgrep nginx) -e trace=sendfile64 观察系统调用;压测对比 CPU 占用与首包延迟。










