sendfile 是现代静态资源服务的关键性能机制,通过零拷贝减少 cpu 开销和上下文切换,在小文件高并发场景下显著降低 cpu 使用率并提升吞吐;需配合 tcp_nopush 才能发挥最大效能,且易因 gzip、range 等配置退化。

sendfile 指令在现代网络环境中仍是静态资源服务性能的关键支点,不是过时的“老功能”,而是高吞吐、低延迟场景下不可替代的底层加速机制。
它解决的是真实瓶颈:CPU 和内核路径开销
即便在千兆/万兆网卡和 SSD 普及的今天,大量小文件(如图标、字体、JS/CSS)并发请求仍会让 CPU 被反复的 read/write 拷贝拖垮。sendfile 将原本 4 次数据搬运(2 次 CPU 拷贝 + 4 次上下文切换)压缩为 2 次(0 次 CPU 拷贝 + 2 次切换),直接缓解 CPU 成为瓶颈的问题。实测显示,在 10K QPS 下传输 64KB 文件,开启 sendfile 后 CPU 使用率可下降 35%–50%。
- 对小文件(
- 对大文件(>1MB):DMA 链路更稳定,带宽利用率提升,尤其在长连接复用场景中
- 在容器或云主机环境:只要底层存储是本地块设备(如 AWS EBS、阿里云云盘),仍能生效;但 NFS、CIFS 或 overlayfs 等不支持 sendfile 的文件系统会自动退化
它必须配合 tcp_nopush 才能发挥最大价值
单独开 sendfile 只完成了“内核直传”,但若 TCP 包太小,网络层效率仍受限。tcp_nopush on 让 Nginx 把 sendfile 读出的数据攒满一个 MSS(通常 1448 字节)再发,避免大量小包导致的 Nagle 算法延迟和 ACK 拥塞。两者组合后,静态资源首字节时间(TTFB)平均降低 15%–25%,吞吐提升常达 30%+。
- tcp_nopush 是 sendfile 的“搭档”,不是可选项
- tcp_nodelay 在静态文件场景中作用有限,甚至可能因禁用 Nagle 而增加小包数量,一般无需开启
- 搭配 open_file_cache 可进一步减少 stat/open 系统调用,堵住用户态介入漏洞
它在现代架构中容易被悄悄绕过
很多团队开了 sendfile on 就以为万事大吉,却忽略了常见退化条件:gzip on、etag 开启、Range 请求、.gz 文件缺失导致 gzip_static fallback、使用 X-Accel-Redirect 但后端未返回真实文件路径等。这些都会让 Nginx 回退到 read/write 模式,性能断崖下跌。
- 用 strace -p $(pgrep nginx) -e trace=sendfile64 实时观察 worker 是否真在调用该系统调用
- 优先用 gzip_static on + 预压缩文件,而非运行时 gzip
- 对需 Range 支持的视频/音频资源,考虑分离静态 CDN 域名,让纯 sendfile 路径专注无分片资源
它不适用于所有流量,但适用的那部分非常关键
sendfile 对反向代理、FastCGI、gRPC 等动态响应完全无效——它只作用于 Nginx 直接从磁盘读取的真实静态文件。但在典型 Web 应用中,静态资源请求数常占总请求量 60%–80%,这部分的效率直接决定整体服务能力上限。
- CDN 边缘节点、内部静态资源服务器、下载中心等场景,sendfile 是默认且必须启用的核心配置
- 现代前端打包产物(如 .js、.css、.woff2)天然适配 sendfile,无需额外改造
- 配合 modern 指令(如 http_v2 on)和 TLS 优化,它仍是 HTTP/2 静态流传输的底层基石
不复杂但容易忽略:它不是锦上添花,而是把本该由内核高效完成的事,还给内核去做。











