tcp_nopush 与 tcp_nodelay 是协同而非互斥策略:前者需配合 sendfile on 用于静态资源合并发送以减少小包,后者保障动态接口低延迟;二者应按 location 分路径精细化配置。

开启 tcp_nopush 可显著减少大体积静态报文(如 JS、CSS、图片等)在代理转发场景下的网络小包数量,提升传输效率和首字节时间(TTFB),但需配合 Nginx 的缓冲与发送策略协同生效。
理解 tcp_nopush 的实际作用
tcp_nopush 是 Nginx 的一个 socket 选项开关(对应 Linux 的 TCP_NOPUSH 或 TCP_CORK),它不会立即发送数据,而是等待以下任一条件满足再一次性推送:缓冲区填满、HTTP 响应头+响应体全部就绪、或超时触发强制发送。它不是“禁用 Nagle 算法”(那是 tcp_nodelay 干的事),而是为“整块发”做准备——尤其适合已知长度、无需实时交互的静态资源。
必须搭配 sendfile 和 output_buffers 使用
单独开 tcp_nopush on 没效果。它只在启用 sendfile on 且响应体由内核零拷贝直接读取文件时才真正起作用。同时建议配置:
-
sendfile on;—— 启用内核态文件传输,避免用户态拷贝 -
tcp_nopush on;—— 允许内核暂存并合并 TCP 包 -
output_buffers 2 128k;—— 提供足够缓冲空间,避免过早冲刷(默认 2×32k 常不够大文件) -
tcp_nodelay off;—— 关闭 Nagle,避免与 nopush 冲突(二者逻辑相反,不共存)
代理转发中需确保后端响应可缓存且长度明确
若 Nginx 作为反向代理转发静态资源(例如从内部对象存储或另一台静态服务拉取),要让 tcp_nopush 生效,后端响应必须满足:
- 包含明确的
Content-Length(非 chunked 编码) - 响应体不被流式生成(如不带
Transfer-Encoding: chunked) - Nginx 需缓存完整响应后再发(即
proxy_buffering on,且proxy_buffer_size+proxy_buffers足够容纳 header + body)
否则 Nginx 无法预判长度,tcp_nopush 将退化为无效状态,转而按 tcp_nodelay 行为发送小包。
验证是否生效的简单方法
用 tcpdump 抓包观察关键字段:
- 对比开启/关闭
tcp_nopush时,同一 1MB 图片的 TCP 报文数量(理想情况从数百个 MSS=1448 的小包 → 减至几十个满载包) - 检查 TCP 标志位:生效时,多个 HTTP 数据段会聚合进单个 PSH+ACK 包;未生效则频繁出现小尺寸、带 PSH 的碎片包
- 用
ss -i查看连接的retrans和unacked数值变化,明显降低说明吞吐更稳
注意:该优化对小文件(64KB 的静态资源重点调优。










