sendfile 的核心作用是实现磁盘到网卡的内核态零拷贝传输,显著降低静态文件响应延迟;它省去用户态内存拷贝与上下文切换,需配合 tcp_nopush、禁用 gzip 等修改响应体的模块,并满足路径真实、content-length 准确等条件才能生效。

sendfile 的核心作用是把静态文件从磁盘直接送入网络发送队列,跳过用户态内存拷贝,从而显著降低响应延迟——尤其对图片、JS、CSS、视频等常见静态资源,首字节时间(TTFB)和整体传输耗时都能明显缩短。
为什么能压低延迟
传统文件传输需经历两次数据拷贝:先由内核读入用户态缓冲区,再由应用写入 socket。sendfile 让内核在内部完成“磁盘 → 网卡”的直达路径,省掉一次内存拷贝、一次上下文切换和一次用户态 CPU 调度。这对高频小文件(如 1–50 KB 的图标、样式表)效果尤为突出,CPU 占用下降 20%–40%,延迟抖动也更平稳。
真正起效的必要条件
- 请求必须命中真实静态文件路径(root 或 alias 指向本地磁盘),不能是 proxy_pass、FastCGI 或动态生成内容
- 响应头中必须有准确的 Content-Length(Nginx 需预知大小才能启用零拷贝路径)
- 该 location 下不能启用 gzip、sub_filter、add_before_body 等需修改响应体的模块
- 客户端使用 HTTP/1.1(或带 keep-alive 的 HTTP/1.0),且未主动禁用
搭配 tcp_nopush 才完整生效
sendfile 单独开启只能减少拷贝,但若不配合 tcp_nopush,HTTP 响应头和文件开头数据可能被拆成两个 TCP 包发出,影响首包到达时间。只有两者同时启用,且满足上述条件时,内核才能把响应头与文件起始内容“合并进一个 TCP 报文”,实现真正的低延迟首字节交付。配置示例:
location ~ \.(jpg|png|js|css|woff2)$ {
sendfile on;
tcp_nopush on;
gzip off; # 避免冲突
}
注意默认已开,但容易被覆盖
Nginx 安装后 http 块默认含 sendfile on,但很多用户在 server 或 location 块里显式写了 sendfile off,或启用了 gzip、PHP 处理等模块,导致它实际失效。建议用 curl -I 查看响应头是否含 Content-Length,并确认 access.log 中无 “tcp_nopush is ignored” 类提示,来验证是否真正在工作。











