nginx静态资源服务应避免cpu密集型操作,核心是启用sendfile实现零拷贝,并用gzip_static替代运行时gzip压缩,配合open_file_cache、tcp_nopush等调优项减少系统调用与上下文切换,确保高效传输。

静态资源服务本身不应该是CPU密集型任务,但配置不当会让Nginx在传输文件时频繁进出用户态,触发多次内存拷贝和系统调用,导致CPU占用异常升高。真正高效的方案不是“在sendfile和gzip之间做取舍”,而是让两者协同工作:用预压缩替代运行时压缩,让零拷贝路径保持畅通。
sendfile 是性能基线,必须开启且避免退化
sendfile 开启后,数据从磁盘到网卡全程在内核态完成,仅需2次拷贝;关闭则走 read+write 路径,需4次拷贝+4次上下文切换。但以下情况会让 sendfile 自动失效:
- 启用 gzip on(运行时压缩必须进用户态)
- 使用 etag 或 expires 指令(需动态计算响应头)
- 请求带 Range 头(如视频拖拽),或启用 gzip_static 但 .gz 文件不存在
- 静态文件存于 NFS/CIFS 等不支持 sendfile 的远程挂载点
确认生效方式:用 strace -p $(pgrep nginx) -e trace=sendfile 观察 worker 进程是否真实调用 sendfile 系统调用。
gzip_static 替代 gzip,实现压缩与零拷贝共存
想保留压缩收益又不牺牲 sendfile,核心是把压缩操作从运行时移到构建阶段:
- 提前为每个静态文件生成 .gz 副本(如 index.html → index.html.gz)
- 启用 gzip_static on;,Nginx 会自动检查同名 .gz 文件并返回它
- 同时设置 gzip off;,彻底禁用运行时压缩模块
- 确保 mime.types 中已定义对应类型(如 application/javascript),否则 .gz 不会被识别
注意:需确认 Nginx 编译时包含 ngx_http_gzip_static_module,否则会报 unknown directive 错误。
配套调优项,堵住其他CPU泄漏点
单靠 sendfile 和 gzip_static 不够,还需收敛其他干扰因素:
-
open_file_cache:缓存文件句柄和元数据,避免高并发下反复 open/stat,推荐配置:
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2; - 精简日志:access_log off; 或只记录关键字段;避免 log_format 包含 $body_bytes_sent 等需等待响应完成的变量
- 禁用正则 location:对静态资源用前缀匹配(location /img/)而非正则(location ~* \.png$),减少 PCRE 计算开销
- tcp_nopush on:配合 sendfile,攒够 TCP 包再发,降低网络小包数量
验证是否真正走零拷贝路径
不能只看配置开了没,要观察实际行为:
- 用 curl -I 请求一个静态资源,响应头中不应出现 Content-Encoding: gzip(那是运行时压缩);若启用了 gzip_static,应有该头且 Vary: Accept-Encoding(由 gzip_vary 控制)
- 对比开启前后 top 中 nginx worker 进程的 %CPU 占比,尤其在大文件并发下载场景
- 检查 dmesg 或 /proc/net/snmp,确认 TCPOutSegs 增速与 sendfile 调用量趋势一致











