nginx动态启用gzip或brotli压缩会禁用sendfile零拷贝,因压缩需在用户态处理数据;改用gzip_static或brotli_static预压缩可恢复零拷贝,提升qps 20%–50%。

会失效。Nginx 的 sendfile 零拷贝机制与 Gzip 或 Brotli 动态压缩互斥——只要启用 gzip on 或 brotli on,Nginx 就会自动禁用 sendfile,退回到传统的 read() + write() 路径。
为什么压缩会导致零拷贝失效
零拷贝的核心前提是“数据不经过用户态”。而 Gzip/Brotli 压缩必须在用户空间完成:Nginx 需先读取原始文件内容到内存缓冲区,调用压缩库处理,再把压缩后数据写入 socket。这个过程强制绕过内核的 sendfile() 系统调用,无法实现磁盘→网卡的内核直通。
- 即使只对部分 MIME 类型(如
text/css)启用压缩,只要该请求命中压缩规则,sendfile就不会触发 -
gzip_vary on或brotli_vary on不影响此逻辑,它们只控制响应头和缓存行为,不改变传输路径
静态预压缩是可行的折中方案
若需兼顾压缩率与零拷贝,应使用 gzip_static on 或 brotli_static on,而非动态压缩:
- 提前用工具生成
.gz或.br文件(如main.js.br),确保与源文件同目录、同名 - Nginx 在匹配到 Accept-Encoding 后,直接通过
sendfile发送已压缩文件,全程仍走零拷贝 - 此时
gzip on和brotli on必须关闭,仅保留_static指令
如何验证是否真的走了零拷贝
不能依赖配置是否存在,要观察运行时行为:
- 用
strace -p $(pgrep nginx | head -1) -e trace=sendfile64,read,write抓取 worker 进程系统调用:看到大量sendfile64且几乎无read,说明生效 - 对比开启前后 CPU 使用率:零拷贝启用后,
sy(系统态)占比上升,us(用户态)明显下降,QPS 通常提升 20%–50% - 注意检查文件本身:必须是本地 ext4/xfs 普通文件、大小 ≥4KB、未被锁、未用
directio
不复杂但容易忽略:零拷贝不是“开了就有效”,而是“关掉所有干扰项后才真正启动”。











