必须同时启用sendfile on、tcp_nopush on和tcp_nodelay off,且避开gzip、代理、内容改写及非本地文件等退化条件,才能真正触发内核零拷贝;单独配置任一指令均无效,且仅对真实静态文件生效。

要在 Nginx 的 server 块中真正启用高效的 sendfile 传输,不能只写 sendfile on,必须成套配置、精准限定场景,并避开所有常见退化路径。
必须同时启用的三个指令
这三项需写在同一个 server(或更细粒度的 location)块内,缺一不可:
- sendfile on;:激活内核零拷贝能力,让文件数据直接从页缓存送入 socket 缓冲区
- tcp_nopush on;:依赖 sendfile 生效,启用 TCP_CORK,把响应头和文件开头合并进一个 TCP 报文段,减少小包
-
tcp_nodelay off;:显式关闭 Nagle 算法;若设为
on,会强制立即发包,直接破坏tcp_nopush的攒包逻辑
必须避开的失效条件
哪怕配置全对,只要出现以下任一情况,Nginx 就自动回退到低效的 read()+write() 模式:
- 启用了
gzip on、gzip_static on或gunzip on - 使用了
proxy_pass、fastcgi_pass、grpc_pass等代理指令 - 配置了
sub_filter、add_before_body、add_after_body等内容改写功能 - 文件不在本地 ext4/xfs 文件系统上(如挂载的 NFSv3、FUSE、部分容器卷)
- 响应未带
Content-Length头(Nginx 需预知大小才能走 sendfile)
推荐的 server 块配置示例
不建议在全局 http 块盲目开启,而是针对静态服务明确声明:
server {
listen 80;
server_name static.example.com;
root /var/www/static;
<pre class="brush:php;toolbar:false;"># 关键三件套(仅对本 server 生效)
sendfile on;
tcp_nopush on;
tcp_nodelay off;
# 精准匹配静态资源,避免干扰
location ~* \.(jpg|jpeg|png|webp|gif|svg|avif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
gzip off; # 必须关掉,否则 sendfile 失效
}
location ~ \.(mp4|avi|zip|iso|tar\.gz|dmg)$ {
sendfile_max_chunk 512k; # 防止单次传输阻塞 worker
expires 7d;
access_log off; # 大文件访问日志可关闭,减 I/O 压力
gzip off;
}}
为什么不能只配 sendfile?
单独开启 sendfile on 只是打开了门,但没铺路、没清障:
- 没有
tcp_nopush,响应头和文件数据可能分两个小包发出,网络碎片增多 - 若
tcp_nodelay on与tcp_nopush on并存,内核行为不可控,多数版本下后者被覆盖 - 只要开了 gzip 或用了 proxy,Nginx 内部会自动绕过 sendfile 路径,配置形同虚设











