sendfile 与 tcp_nopush 必须成对启用且仅用于真实静态文件路径,需关闭 gzip、tcp_nodelay,确保 content-length 存在,并通过 strace 和 wireshark 验证生效。

要让 sendfile 和 tcp_nopush 在 Linux + Nginx 生产环境中真正起效,不能只写“开了”,必须满足路径、条件、协同三重约束。核心是:它们不是独立优化项,而是一套内核级传输调度机制的开关组合。
必须成对启用且作用域精准
这两个指令必须同时出现在同一个 location 块中,且仅用于明确服务真实磁盘静态文件的路径:
-
sendfile on;是零拷贝的启动开关,但仅当请求命中本地文件(root或alias指向物理路径)、不经过proxy_pass、FastCGI、Lua 等中间处理时才生效 -
tcp_nopush on;完全依赖sendfile提供的数据流;若sendfile退化为read/write模式(比如开了gzip或响应是 chunked),tcp_nopush直接被忽略,日志中会提示 “tcp_nopush is ignored” - 不要在
http或server块全局开启——容易误伤 API、WebSocket、HLS 的 m3u8 等需要低延迟的场景
配套指令缺一不可
仅配前两者仍可能失效,还需同步关闭干扰项:
-
tcp_nodelay off;:Linux 下tcp_nopush实际启用TCP_CORK,而tcp_nodelay on强制立即发包,二者互斥;显式设为off可避免被上级配置继承覆盖 -
gzip off;:压缩必须在用户态完成,一开就禁用sendfile,整套机制退化 - 确保响应含
Content-Length:Nginx 需预知文件大小才能调用sendfile()系统调用;若后端流式返回或缺失该头,自动回退
按文件类型精细化配置示例
推荐只对大体积静态资源启用,例如视频、安装包、高清图:
location ~ \.(mp4|webm|avi|mov|zip|iso|tar\.gz|dmg|pdf)$ {
root /var/www/static;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
gzip off;
expires 7d;
add_header Cache-Control "public, immutable" always;
}
这种写法避开常见陷阱:不走代理、不压缩、不加动态 header、有明确长度、作用域收敛。
验证是否真生效的实操方法
不能只看配置是否存在,得看运行时行为:
- 用
strace -e trace=sendfile -p $(pgrep nginx)观察 worker 进程是否实际调用了sendfile系统调用 - 用 Wireshark 抓包:开启后,HTTP 状态行、响应头与文件开头几 KB 数据应出现在同一个 TCP 报文段里,而不是拆成多个小包(如 40–60 字节的纯 header 包)
- 检查 Nginx error log:若出现 “tcp_nopush is ignored”,说明当前响应已退化,需排查是否触发了 gzip、proxy_pass、缺失 Content-Length 等条件











