tcp_nopush本身不直接优化大文件传输,仅在配合sendfile、服务真实静态大文件、响应含Content-Length三前提下生效,核心是合并响应头与文件开头数据进同一TCP包以减少小包、提升载荷率。

tcp_nopush 本身不直接“优化大文件传输”,它只在特定路径下起作用:必须配合 sendfile,且仅对静态大文件(如视频、安装包)的内核零拷贝发送阶段生效。它的核心价值是让响应头和文件开头数据尽可能塞进同一个 TCP 包,减少小包数量、提升单包载荷率。
必须满足的三个硬性条件
tcp_nopush 对大文件起效不是“开了就行”,而是依赖底层数据路径是否走通:
- sendfile 必须开启:这是前提中的前提。只有启用 sendfile,Nginx 才跳过用户态内存拷贝,让内核直接从页缓存推数据到 socket;否则 tcp_nopush 被完全忽略,日志中会出现 “tcp_nopush is ignored”
- 响应必须含明确 Content-Length:Nginx 需预知文件长度才能启动 sendfile。动态生成内容、chunked 编码或 proxy_pass 响应都会退回到 read/write 模式,绕过整个优化链路
- 禁用所有用户态处理模块:gzip、sub_filter、ssi、lua 模块等任意一个启用,都会切断零拷贝路径,使 tcp_nopush 失效
精准配置在大文件 location 中
不要在 http 或 server 块全局开启 tcp_nopush。它只应在已知为纯静态、无逻辑干预的大文件路径中启用:
- 匹配典型大文件后缀,例如:
location ~ \.(mp4|webm|avi|mov|zip|iso|tar\.gz)$ - 该 location 内必须显式配置:
sendfile on;、tcp_nopush on;、tcp_nodelay off; - 建议关闭 gzip:
gzip off;,避免因压缩触发用户态处理而自动禁用 sendfile
tcp_nodelay 必须设为 off
很多人误以为“大文件也要低延迟”,于是保留默认的 tcp_nodelay on,这反而会破坏 tcp_nopush 效果:
- tcp_nodelay on 强制内核立即发送未满 MSS 的数据包,导致首包可能只有 HTTP 头(约 200 字节),后续再发文件数据,白白增加小包数量
- tcp_nopush on + tcp_nodelay off 允许内核等待,把响应头与文件起始段(通常前 1–2KB)合并进一个 TCP 段发出,实测可降低小包占比 60% 以上
- 注意:tcp_nodelay 是 listen 级指令,若在 listen 行中写了
tcp_nodelay,需在对应 location 中显式覆盖为tcp_nodelay off
配套调优确保零拷贝通路稳定
光配指令不够,还需保障系统层面能高效支撑 sendfile 路径:
- 设置
sendfile_max_chunk 512k;:限制单次 sendfile 传输量,防止大文件阻塞事件循环 - 启用
open_file_cache:缓存文件 inode 和 mtime,加快 open 系统调用,缩短 sendfile 启动前延迟 - 关闭该 location 的访问日志:
access_log off;,避免高频大文件请求时日志写入成为瓶颈 - Linux 内核参数可微调:
net.ipv4.tcp_fin_timeout(缩短 TIME_WAIT)、fs.file-max(提高文件描述符上限)










