tcp_nopush必须与sendfile协同生效,仅对静态文件零拷贝传输有效;需禁用gzip、显式配置tcp_nodelay off、output_buffers和sendfile_max_chunk,并按文件类型精细化启用。

tcp_nopush 不是独立生效的“开关”,它必须和 sendfile 协同工作,才能真正合并 TCP 数据包、减少小包数量和网络拥塞。单独开启 tcp_nopush on 没有效果,反而可能因配置冲突导致行为不可控。
必须满足的三个基础条件
只有同时满足以下三点,tcp_nopush 才会进入实际生效路径:
- 显式启用 sendfile on:必须在具体 location 块中写明,不能仅靠 http 块继承;只有走内核零拷贝路径(如直接从磁盘页缓存读文件),tcp_nopush 才能控制内核 TCP_CORK 行为。
- 响应必须含明确 Content-Length:Nginx 需提前知道整个响应体大小,才能决定何时“攒够”一整块发出去;若后端返回 chunked 编码、流式响应或缺失该头,自动退回到 read/write 模式,tcp_nopush 失效。
- 服务真实静态文件:root 或 alias 指向本地磁盘路径,且请求命中如 .mp4、.zip、.iso 等大文件;proxy_pass、FastCGI、Lua 或 gzip 压缩等都会绕过 sendfile 路径,使 tcp_nopush 彻底无效。
配套参数必须对齐
tcp_nopush 的行为依赖一组协同参数,缺一不可:
- gzip off:压缩在用户态完成,强制禁用 sendfile,连带让 tcp_nopush 失效;大文件下载场景务必关闭。
- tcp_nodelay off:二者逻辑相反——tcp_nodelay 强制立即发包,tcp_nopush 则等待合并;显式设为 off 可避免被上级配置继承干扰。
- output_buffers 2 128k:默认缓冲区(2×32k)对 >1MB 文件常不够用,易触发提前冲刷;增大缓冲有助于内核更完整地组装大包。
- sendfile_max_chunk 512k:限制单次 sendfile 系统调用最大长度,防止阻塞 worker 进程,也利于分段合并传输。
按资源类型精细化启用
全局开启容易误伤 API、WebSocket、HLS 清单等低延迟场景。推荐下沉到 location 级,只对已知大体积静态资源启用:
- 匹配常见大文件后缀:location ~ \.(mp4|webm|avi|mov|zip|iso|tar\.gz|dmg)$
- 内部明确声明:sendfile on; tcp_nopush on; tcp_nodelay off; gzip off;
- 可叠加缓存策略:expires 7d; add_header Cache-Control "public, immutable";
验证是否真正生效
不能只看配置是否存在,要观察运行时行为:
- 用 ss -i 查看活跃连接,确认输出中有 np 标记(表示 TCP_CORK 已启用);
- 用 Wireshark 抓包,对比开启前后:理想情况是 HTTP 响应头 + 文件前几 KB 数据落在同一个 TCP 段中,而非拆成数十个 1448 字节的小包;
- 压测时统计“小于 1500 字节的 TCP 包占比”,下降明显且重传率稳定,说明优化起效。











