tcp_nopush在Linux 4.x下必须与sendfile协同生效,启用TCP_CORK攒包机制以减少小包;需满足sendfile on、Content-Length存在、gzip off等硬性条件,并限于静态文件location中精准启用。

tcp_nopush 在 Linux 4.x 内核下必须与 sendfile 协同使用,才能真正发挥减少小包、降低系统调用开销的作用;它不是独立生效的“加速开关”,而是一个依赖内核零拷贝路径的传输调度策略。
tcp_nopush 的真实作用机制
在 Linux 4.x 中,tcp_nopush 实际启用的是 TCP_CORK 选项,其行为是:当响应头已写入 socket、且后续待发数据(如文件起始块)能接近 MSS(通常 1448–1460 字节)时,内核会暂存这些数据,等待凑满一包再发出。这不是延迟发送,而是“攒包”——前提是数据走的是 sendfile 路径,不经过用户态缓冲区。
- 若 sendfile off,Nginx 先 read() 到用户空间再 write(),tcp_nopush 完全被忽略
- 若启用了 gzip、sub_filter、access_by_lua_block 等用户态处理模块,sendfile 自动禁用,tcp_nopush 同步失效
- 仅对常规静态文件(如 mp4、zip、iso)且未被 SELinux/AppArmor 拦截时才可能触发
Linux 4.x 下必须满足的协同条件
在 4.x 内核(如 4.4、4.15、4.19 等主流 LTS 版本)中,要让 tcp_nopush 生效,需同时满足以下硬性条件:
- 配置中明确开启:sendfile on; 和 tcp_nopush on;
- 对应 location 必须服务本地磁盘上的真实文件(root 或 alias 指向有效路径),不能是 proxy_pass 动态响应
- 后端响应必须含明确的 Content-Length(否则 Nginx 退化为 chunked 编码,无法预分配 sendfile 长度)
- tcp_nodelay 保持默认 off:设为 on 会强制立即发包,直接抵消 TCP_CORK 效果
精准启用:按资源类型限定作用域
全局开启 tcp_nopush 是低效且易出错的做法。应只在明确的大静态资源 location 中启用,例如视频、安装包等:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
location ~ \.(mp4|webm|mov|avi|zip|iso|dmg)$ {
root /data/assets;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
expires 30d;
add_header Cache-Control "public, immutable";
gzip off; # 防止 sendfile 失效
}
- 避免在 /api/、/admin/ 或含重写规则的 location 中启用,这些场景几乎不走 sendfile
- 搭配 gzip off 是关键安全项——Linux 4.x 内核下,即使 gzip_min_length 设为很大,只要 gzip on,sendfile 就不会启动
- 若需兼容 HLS 场景(如 m3u8 + ts),建议将 m3u8 单独剥离到不启用 tcp_nopush 的 location,避免首屏轻微延迟
验证是否真正生效
不能仅靠配置存在来判断效果。需结合运行时观测确认:
- 用 ss -i dst
查看连接状态,输出中出现 np 标记(表示 TCP_CORK 已启用) - Wireshark 抓包对比:开启后,HTTP 响应头与文件前 4–8 KB 数据大概率出现在同一 TCP 段中(SYN 后第一个 DATA 包即含 header+payload)
- 压测时观察 netstat -s | grep "segments sent" 中 “TCP data loss” 和 “retransmit” 是否下降,小包(










