sendfile 是 Nginx 关键性能指令,启用后内核直传磁盘到网卡,绕过用户态拷贝,显著降 CPU/内存开销;需配 tcp_nopush on、禁用 gzip/sub_filter 等退化项,并验证 Content-Length 与 sendfile64 调用方可生效。

sendfile 是 Nginx 中一个关键的性能优化指令,它让内核直接在磁盘和网络套接字之间传输文件数据,绕过用户态内存拷贝,显著降低 CPU 和内存开销,特别适合静态文件(如图片、CSS、JS)的高效分发。
一、开启 sendfile 指令
只需在 Nginx 配置中启用 sendfile 并搭配推荐的辅助指令即可。通常修改 nginx.conf 或站点配置(如 /etc/nginx/conf.d/default.conf)中的 server 或 http 块:
- 添加或确认存在:
sendfile on; - 建议同时开启:
tcp_nopush on;(配合 sendfile,将多个小包合并为满包发送) - 可选但推荐:
tcp_nodelay on;(对非 sendfile 场景如 WebSocket/长连接更有效,与 sendfile 不冲突)
示例片段:
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 其他配置...
}
二、重载配置使生效
保存配置后,执行以下命令验证语法并重载:
-
sudo nginx -t—— 确认配置无语法错误 -
sudo nginx -s reload或sudo systemctl reload nginx—— 平滑重载配置
注意:仅重启(restart)不是必须的,reload 即可生效。
三、验证 sendfile 是否实际生效
单纯检查配置项是否为 on 不代表运行时一定启用——还需确认请求路径匹配、文件类型符合、且未被其他指令(如 etag off 或某些 proxy 设置)间接禁用。验证方法如下:
-
查看响应头 + 文件类型:用
curl -I请求一个静态文件(如/style.css),观察是否返回Content-Length且无Transfer-Encoding: chunked(sendfile 要求已知长度);同时确认 Nginx 正确识别 MIME 类型(如Content-Type: text/css) -
抓包确认零拷贝行为(进阶):用
tcpdump或 Wireshark 抓取响应流量,若看到单个 TCP 报文携带完整文件内容(尤其大文件),且服务端send()系统调用次数极少,说明 sendfile 很可能启用;也可结合strace -p $(pgrep nginx) -e trace=sendfile直接观测是否调用sendfile64()系统调用(需 worker 进程权限) -
检查 Nginx 日志(间接):开启
error_log /var/log/nginx/error.log debug;后,重启 Nginx,访问静态资源,日志中若出现sendfile: 1或类似提示(取决于版本),即表示该请求启用了 sendfile
四、常见失效原因及排查
-
文件不满足条件:sendfile 仅对真实磁盘文件生效,不适用于子请求(subrequest)、gzip_static 启用时的部分场景、或通过
alias映射但路径解析失败的情况 -
启用了不兼容指令:如
expires或add_header本身不阻止 sendfile,但若配合了sub_filter、echo模块或某些第三方模块修改响应体,则自动退回到常规 read/write 流程 -
文件太小或开启了 AIO:极小文件(如 aio on 且系统支持,Nginx 可能优先使用异步 I/O,此时
sendfile不触发 - 客户端不支持:极老客户端(如 HTTP/1.0 无 Keep-Alive)可能导致 Nginx 回退,但现代环境基本无需考虑


















