sendfile对小文件重在减少系统调用与内存拷贝以提升响应灵敏度,对大文件则通过sendfile_max_chunk分块调度防worker阻塞;必须协同启用sendfile on、tcp_nopush on、gzip off,并按location精细配置才能生效。

sendfile 对小文件和大文件的优化逻辑完全不同:对小文件,它重在减少系统调用与内存拷贝,提升响应灵敏度;对大文件,它重在避免 worker 长期阻塞,保障整体并发能力——不是“提速”,而是“让资源不被独占”。
小文件:零拷贝 + 减少上下文切换
小文件(如图标、CSS、JS)频繁请求、体积小、响应要求快。sendfile 的价值在于跳过用户态,直接由内核完成磁盘页缓存到 socket 缓冲区的搬运:
- 省去 read() + write() 两次系统调用,降低 CPU 开销
- 避免两次内存拷贝(内核→用户→内核),减少带宽占用
- 配合 tcp_nopush on,可将响应头与首段数据合并发送,缩短 TTFB
- 但若启用 gzip 或 sub_filter 等改写模块,sendfile 自动失效,退回到低效的 read/write 模式
大文件:分块调度 + 防 worker 饱和
大文件(如视频、安装包)单次传输耗时长,容易“卡住”一个 worker 进程。sendfile_max_chunk 就是为此设计的调度杠杆:
- 设为 1M:500MB 文件拆成约 500 次 sendfile 调用,每次传输后 worker 主动让出 CPU,能及时处理新来的请求
- 设为 0(默认):内核可能一次搬运上百 MB,该 worker 在此期间无法响应任何其他事件,小请求排队、TTFB 明显升高
- 但 chunk 过小(如 64K)会引发副作用:系统调用次数剧增、上下文切换频繁,反而增加 CPU 压力
配置必须协同,不能单点生效
单独开 sendfile 或调 chunk 值效果有限,以下三项必须同步调整:
- sendfile on:前提条件,否则所有优化无效
- gzip off:压缩必须在用户态完成,开启即强制退回到 read/write
- 按 location 精细控制:例如 /static/ 下小文件多,可用 1M;/dl/ 下大文件为主,可设为 512K 或 2M,避免全局一刀切
验证是否真正生效
不能只看配置写了没,要确认运行时行为:
- 用 strace -e trace=sendfile64 -p $(pgrep nginx) 观察 worker 是否调用 sendfile64
- 对比开启前后 CPU 使用率(尤其是高并发小文件压测时)
- 检查 error log 是否出现 sendfile() failed,常见于 NFS、容器存储驱动不兼容场景











