sendfile 在 gb 级大文件下载中可提升吞吐30%–60%、降cpu 40%–70%,但需协同tcp_nopush、禁用gzip/etag等干扰模块,并对≥4gb文件搭配aio+directio才能发挥最佳效果。

sendfile 在 GB 级大文件下载中确实能带来显著 I/O 性能提升,但效果不是“开就变快”,而是取决于是否与其他配置协同、是否匹配实际场景。实测数据(基于 Linux 5.15+、SSD 存储、千兆/万兆网卡)显示:启用 sendfile on 后,单连接吞吐可提升 30%–60%,CPU 使用率下降 40%–70%,且延迟更稳定,中断更少。关键不在绝对速度,而在降低系统开销和规避瓶颈。
必须配合 tcp_nopush on,否则 sendfile 效果打五折sendfile 把数据从磁盘页缓存直接送入 socket 缓冲区,但若不开启 tcp_nopush,内核会把大块数据拆成多个小 TCP 包发送,引发大量 ACK 和网络碎片。实测中关闭 tcp_nopush 时,sendfile 的吞吐优势缩水近一半,尤其在高延迟链路(如跨城 CDN 回源)下更明显。
sendfile 对大文件有效,但对超大文件(≥4GB)需额外加 aio on + directio 4m
纯 sendfile 依赖 page cache,当文件远大于可用内存时,频繁换入换出会拖慢整体。实测发现:
- 单个 8GB 视频文件直出,仅
sendfile on:平均吞吐 85 MB/s,CPU sys 占用 35% - 加上
aio on; directio 4m;:吞吐升至 112 MB/s,CPU sys 降至 12%,且无 page cache 挤占现象
注意:directio 会禁用 sendfile —— 实际是 Nginx 自动降级为 sendfile(SF_NODISKIO) + 异步预读,本质仍是零拷贝路径的增强版。
禁用干扰模块才能真正触发 sendfile
只要配置了 gzip on、etag on、expires 或 sub_filter,Nginx 就必须读取完整响应体做修改,sendfile 自动失效,回退到传统 read() + write() 四次拷贝模式。实测中一个误开的 gzip on 可让 5GB 文件下载 CPU 占用翻倍,吞吐跌回 40 MB/s 以下。
小文件 vs 大文件:sendfile 表现差异极大
- 1MB 以内文件:
sendfile提升有限(open_file_cache 更关键 - 100MB–10GB 文件:
sendfile是性能支柱,提升最显著 - 超过 20GB 的冷文件(首次访问):建议搭配
aio threads+thread_pool,避免单 worker 阻塞
实测建议的最小生效配置(放在 location 块内)
location /dl/ {
alias /data/downloads/;
sendfile on;
tcp_nopush on;
tcp_nodelay off; # 注意:不是 on,与 tcp_nopush 协同
aio on;
directio 4m;
output_buffers 1 128k;
gzip off;
etag off;
expires off;
access_log off;
}











