tcp_nopush需与sendfile协同才能提升高带宽利用率:通过攒包填满MSS降低协议开销,但必须禁用gzip等用户态处理模块,并配对tcp_nodelay off以避免干扰零拷贝路径。

tcp_nopush 本身不提升带宽上限,但它能显著提升高带宽链路的利用率——核心是减少小包、填满 MSS、降低协议开销。要让它真正“压榨吞吐”,必须和静态缓存协同工作,形成从内存到网卡的高效通路。
必须开启 sendfile,否则 tcp_nopush 彻底失效
tcp_nopush 的作用机制是让内核把响应头(如 Content-Type、ETag)和文件开头数据“攒在一起”发出,但这仅在数据能一次性进入内核发送队列时才发生。sendfile 正是提供这个确定性的关键:
- 普通 read/write 模式:Nginx 多次从用户态读取再 write 到 socket,数据分段入队,tcp_nopush 无法识别“首块完整数据”
- sendfile 启用后:文件内容由内核直接从磁盘或页缓存复制到 socket 描述符,响应头 + 文件起始部分被视作逻辑连续流,tcp_nopush 才真正触发合并
- 若未启用 sendfile(如开了 gzip、proxy_buffering,或后端未返回 Content-Length),tcp_nopush 自动降级为无效,Nginx 日志会警告 “tcp_nopush is ignored”
静态缓存要确保“零拷贝路径全程畅通”
缓存本身不等于零拷贝。只有当缓存内容能以文件描述符形式被内核直接访问,sendfile 才能生效。常见有效路径包括:
- 本地磁盘缓存(如 proxy_cache_path + proxy_cache_valid):需配合 proxy_buffering off,避免 Nginx 把响应体先读进用户态缓冲区
- 内存缓存(如 open_file_cache):仅缓存文件元信息,实际仍走 sendfile,对小静态资源(图标、JS/CSS)很友好
- 对象存储直传(如 OSS/MinIO 回源):上游必须返回明确的 Content-Length 和 200 响应,且 Nginx 配置 proxy_buffering off;否则退化为 chunked 编码,绕过 sendfile
禁用所有干扰项:gzip off、sub_filter off、ssi off —— 任何需要用户态处理的模块都会强制走 read/write 路径,切断零拷贝链路。
tcp_nopush 与 tcp_nodelay 必须反向配对
两者不是可选项,而是策略组合:
- tcp_nopush on:让内核等一等,凑够一个 MSS(通常 1448 字节)再发,减少 TCP 包数量和 ACK 流量
- tcp_nodelay off:关闭 Nagle 算法,避免它在小数据场景下人为引入 200ms 等待;但在 sendfile + tcp_nopush 场景中,它反而会抢在“攒包”完成前强行发包,直接抵消优化效果
- 实测显示:tcp_nopush on + tcp_nodelay on 组合下,高清图片首包延迟可能增加 5–15ms,而吞吐下降 8–12%,因大量未填满的小包冲垮了 TCP 窗口效率
按资源类型精细化启用,避免误伤动态流量
全局配置风险高。推荐基于 MIME 类型或后缀,在 location 级控制:
- 匹配图片/视频/字体等大静态资源:location ~* \.(jpg|jpeg|png|webp|gif|svg|avif|mp4|webm|woff2)$
- 内部启用:sendfile on; tcp_nopush on; tcp_nodelay off;
- 同时关闭压缩:gzip off;(防止绕过 sendfile)
- 若使用 proxy_pass 中转缓存,追加:proxy_buffering off; proxy_http_version 1.1;
这样既保障 /api/、/ws/ 等路径不受影响,又让高带宽资源独享最优传输路径。










