sendfile 是静态文件传输中降低 CPU 占用的核心机制,通过绕过用户态、减少数据拷贝与上下文切换,使 CPU 使用率下降 30%–70%;需满足文件类型、连接状态、文件系统及响应头等前提条件,否则自动退化;配合 gzip_static 等调优可进一步释放 CPU 压力。

sendfile 优化对减轻服务器 CPU 压力的作用非常直接且显著——它不是“辅助手段”,而是静态文件传输场景下降低 CPU 占用的核心机制。
绕过用户态,省掉两次 CPU 拷贝
默认 read+write 路径中,一个文件从磁盘到客户端需经历:磁盘→内核页缓存→用户空间缓冲区→内核 socket 缓冲区→网卡。这涉及 4 次数据拷贝 + 4 次上下文切换,CPU 全程参与搬运。
启用 sendfile 后,路径缩短为:磁盘→内核页缓存→socket 缓冲区→网卡。数据全程在内核空间流转,跳过用户空间,仅需 1 次 DMA 拷贝 + 1 次内核内拷贝,CPU 不再负责内存复制任务。
- 对 MB 级文件(如视频、安装包),单次请求可减少数万次 CPU 指令执行
- 高并发下,worker 进程不再因频繁 read/write syscall 阻塞或陷入调度竞争
- 实测常见静态服务场景,CPU 使用率可下降 30%–70%,尤其在机械盘或高 QPS 下更明显
必须满足前提,否则自动退化
sendfile 不是“开关一开就生效”的功能,它只在全部条件满足时才走零拷贝路径;任一不满足,Nginx 就悄悄回落到低效的 read/write 模式,CPU 压力照旧。
- 源文件必须是真实磁盘文件(不能是管道、socket、/proc 或 tmpfs)
- 目标连接必须已建立(非监听 socket,而是 accept 后的 client fd)
- 文件系统支持 mmap 语义(ext4/xfs 没问题,NFSv3 或 noac 挂载易失效)
- 响应头不能含需动态生成的内容(gzip on、etag on、expires、Range 请求都会导致退化)
配合 gzip_static 实现压缩与零拷贝共存
很多人误以为“要压缩就得牺牲 sendfile”,其实关键在于把压缩移到构建阶段:
- 提前生成
style.css.gz,并启用gzip_static on; - 同时关闭运行时压缩:
gzip off; - Nginx 发现 .gz 文件存在,直接 sendfile 发送压缩体,全程零拷贝
- 既节省带宽,又不增加 CPU 开销——比运行时 gzip 降低 50%+ CPU 负载
配套调优堵住其他 CPU 泄漏点
即使 sendfile 生效,若其他环节设计不当,CPU 仍可能被拖累:
-
open_file_cache缓存文件句柄和 stat 结果,避免高频 open/stat 系统调用 -
tcp_nopush on配合 sendfile,攒够 TCP 包再发,减少软中断和小包处理压力 - 禁用正则 location(如
location ~ \.js$),改用前缀匹配(location /js/),省掉 PCRE 解析开销 - 精简 access_log,避免记录
$body_bytes_sent等需等待响应结束的变量


















