tcp_nopush必须与sendfile协同生效:前者依赖后者提供的内核零拷贝路径,将响应头与文件首段合并发送以减少小包;单独启用无效,且需关闭gzip、确保content-length、按文件类型精准配置。

tcp_nopush 本身不直接“合并数据包”,它依赖 sendfile 提供的内核零拷贝路径,让响应头和文件开头数据尽可能塞进同一个 TCP 报文段发出。真正起效的前提是两者协同,且配置精准。
必须和 sendfile 配合使用
单独开启 tcp_nopush 没有效果。Nginx 只有在启用 sendfile on 时,才能跳过用户态内存拷贝,把 HTTP 响应头和磁盘文件的起始部分视为连续数据流,此时 tcp_nopush 才有机会触发内核的 TCP_CORK(Linux)或 TCP_NOPUSH(FreeBSD)机制,实现“攒包”。
- 若 sendfile off,Nginx 走 read/write 流程,数据分段进入内核发送缓冲区,tcp_nopush 完全被忽略
- 若启用了 gzip、sub_filter、Lua 处理等用户态操作,sendfile 自动禁用,tcp_nopush 同步失效
- 配置中需在具体 location 块内显式写 sendfile on; 和 tcp_nopush on;,不能仅靠 http 块继承
只对真实静态文件生效
该优化仅在 Nginx 直接服务本地磁盘文件时触发,例如用 root 或 alias 指向 /data/videos/ 并匹配 .mp4、.zip 等后缀。以下场景不走此路径:
- proxy_pass 代理后端服务(除非配合 proxy_buffering off + 后端返回明确 Content-Length)
- FastCGI、uWSGI、PHP 等动态生成内容
- 通过 access_by_lua_block 或 body_filter_by_lua 修改响应
关键配套参数必须对齐
tcp_nopush 的“攒包”行为需要内核有等待空间,而 tcp_nodelay 控制是否绕过 Nagle 算法。二者逻辑互斥,必须协调:
- tcp_nodelay 必须设为 off(默认即为 off),否则强制立即发包,直接抵消 tcp_nopush 效果
- gzip 必须关闭:gzip off;压缩必须在用户态完成,开启即禁用 sendfile
- 响应头必须含明确的 Content-Length:Nginx 需预知文件大小才能调用 sendfile();若后端返回 chunked 编码或无长度头,自动回退到常规模式
- output_buffers 推荐设为 2 128k:默认 2×32k 对大文件常不够,避免过早冲刷导致无法合并
按文件类型精细化启用
不建议全局开启,应限定在明确的大体积静态资源路径中,例如:
- 视频类:location ~ \.(mp4|webm|avi|mov|ogg)$
- 安装包类:location ~ \.(zip|iso|tar\.gz|dmg)$
- 高清图片类:location ~* \.(jpg|jpeg|png|webp|avif|gif)$
每个 location 内应包含:sendfile on; tcp_nopush on; tcp_nodelay off; gzip off;,并可叠加 expires 和 Cache-Control 提升缓存效率。










