Nginx 性能调优:gzip、缓存与连接池配置
上周接到报警,电商网站的首页加载时间飙升到 4 秒。打开 Chrome DevTools 一看,HTML 文件 120KB,CSS 加 JS 又是 350KB——全是未压缩的原始文件。更糟的是,每个请求都打到后端,缓存命中率只有可怜的 12%。当晚加完班,我花了 2 小时调整 Nginx 配置:gzip 压缩打开,缓存策略补齐,连接池参数调整。第二天早上再看,首页加载已经压到 1.6 秒,后端 QPS 降了快一半。
说实话,这类问题太常见了。很多人配 Nginx 就是装好就跑,gzip 默认不开,缓存随便写两行,连接数上限用默认值。结果一到流量高峰,服务器就喘不过气。
这篇文章把我在生产环境验证过的 Nginx 性能调优配置整理出来。gzip 压缩能减少 60-80% 的传输体积,缓存命中率 95% 时后端压力能少 90%,连接池配置合理的话并发能力能翻三四倍。我会把每个模块的配置细节、踩过的坑、实测数据都摊开讲清楚。
第一章:gzip 压缩配置 — 减少传输体积
先说说 gzip 为什么这么重要。想象一下,你的 HTML 文件原始大小 100KB,通过 gzip 压缩后可能只有 20-25KB。这省下来的 75-80KB 带宽,对用户来说是更快的加载速度,对你来说是更低的流量成本。
我第一次意识到这个问题,是在一个客户的项目上。他们的移动端用户占比超过 60%,很多在 4G 网络环境下访问。首页加载要 3-4 秒,跳出率飙到 70%。加上 gzip 之后,传输体积直接砍掉 70%,首屏加载时间降到 1.5 秒左右。
1.1 基础配置:先让它跑起来
Nginx 的 gzip 配置其实不复杂,核心就几行:
http {
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
}
gzip on 是开关,这个不解释。gzip_vary on 很关键,它会在响应头加上 Vary: Accept-Encoding,告诉 CDN 和浏览器这个响应内容会根据客户端的压缩能力变化,避免缓存错乱。
gzip_min_length 设成 1000 字节,意思是小于 1KB 的文件不压缩。太小的文件压缩收益不大,反而浪费 CPU。gzip_types 指定要压缩的 MIME 类型,默认只压缩 text/html,你得把 CSS、JS、JSON、XML 这些都加上。
1.2 进阶配置:压缩级别和 MIME 类型清单
压缩级别是个需要平衡的选择。Nginx 的 gzip_comp_level 可以设 1-9,数字越大压缩率越高,但 CPU 消耗也越大。
我做过一组测试:
| 压缩级别 | HTML 压缩率 | CPU 时间(ms) | 推荐场景 |
|---|---|---|---|
| 1 | 65% | 2 | CPU 紧张 |
| 4 | 72% | 3 | 平衡型(推荐) |
| 6 | 75% | 5 | 带宽紧张(推荐) |
| 9 | 78% | 12 | 极端场景 |
说实话,级别 4 和 6 是大多数情况下的最佳选择。级别 9 的 CPU 消耗翻倍,但压缩率只多几个百分点,不划算。
下面是我生产环境用的完整 gzip 配置:
# gzip 压缩配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/xml+rss
application/xhtml+xml
application/x-javascript;
gzip_disable "msie6";
gzip_proxied any 这个参数容易被忽略。如果你的 Nginx 作为反向代理,后端返回的响应头没有 Content-Length,默认不会压缩。设成 any 可以强制压缩所有符合条件的响应。
gzip_disable "msie6" 是为了兼容老版本 IE6,它对 gzip 支持有问题。现在 IE6 基本绝迹了,这行其实可以删掉,但我习惯留着,以防万一。
1.3 哪些文件类型收益最大?
根据我这边的实测数据,不同文件类型的压缩效果差异挺大:
| 文件类型 | 原始大小 | 压缩后 | 压缩率 |
|---|---|---|---|
| HTML | 100KB | 20-25KB | 75-80% |
| CSS | 80KB | 24-28KB | 65-70% |
| JavaScript | 120KB | 36-42KB | 65-70% |
| JSON API | 50KB | 20-25KB | 50-60% |
| 图片/视频 | 已压缩 | 无意义 | 0-5% |
图片和视频本身就经过压缩(JPEG、PNG、MP4),再 gzip 反而会增大体积。所以 gzip_types 里千万别加 image/* 和 video/*,加了就是负作用。
有一次我帮人排查问题,发现他们的 gzip_types 里加了 image/jpeg,结果图片体积反而增大了 3-5%。这种低级错误,我大概也犯过——以前不懂的时候,恨不得把所有 MIME 类型都加上。
第二章:缓存策略配置 — 静态内容加速
缓存是性能调优里收益最直接的一环。配置得当的话,95% 的请求可以直接从 Nginx 返回,根本不用打到后端。我见过太多系统,后端服务器跑得满头大汗,结果 Nginx 那边缓存几乎没用——不是没开,是配错了。
2.1 proxy_cache 和 fastcgi_cache 怎么选?
Nginx 提供两种缓存机制:
- proxy_cache:缓存上游服务器的响应,适用于反向代理场景(如 Node.js、Python、Go 服务)
- fastcgi_cache:缓存 FastCGI 进程的响应,适用于 PHP-FPM 场景
选哪个看你的后端技术栈。如果用 PHP,就 fastcgi_cache;如果是 Node.js、Python、Go 这些,用 proxy_cache。两者配置逻辑几乎一样,我下面以 proxy_cache 为例讲解。
2.2 完整的 proxy_cache 配置
先在 http 块定义缓存路径:
http {
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=my_cache:10m
max_size=10g
inactive=60m
use_temp_path=off;
}
逐行解释一下:
levels=1:2:缓存目录层级,1:2 表示两级目录结构,避免单目录文件过多keys_zone=my_cache:10m:缓存区名称和元数据内存大小,10m 可以存约 8 万个缓存键max_size=10g:缓存总大小上限,超过会按 LRU 算法淘汰inactive=60m:60 分钟无人访问的缓存会被清理use_temp_path=off:直接写入缓存目录,避免临时文件移动开销
然后在 server 或 location 里启用:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
# 缓存有效期配置
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;
# 缓存键设计
proxy_cache_key $scheme$request_method$host$request_uri;
# 降级策略(后面细讲)
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
# 响应头添加缓存状态(调试用)
add_header X-Cache-Status $upstream_cache_status;
}
}
proxy_cache_valid 是核心配置,定义不同状态码的缓存时长:
200 302 10m:正常响应缓存 10 分钟404 1m:404 错误缓存 1 分钟,避免恶意请求狂打后端any 1m:其他状态码缓存 1 分钟
2.3 缓存键设计和失效策略
缓存键 proxy_cache_key 决定了什么请求会被视为”相同”。默认是 $scheme$proxy_host$request_uri,但我建议显式声明:
proxy_cache_key $scheme$request_method$host$request_uri;
这样缓存键包含协议、请求方法、主机名和完整 URI。如果你的站点同时支持 GET 和 POST,或者有多个域名,这个配置会更精确。
缓存失效是个头疼的问题。常见的策略:
- 时间过期:
proxy_cache_valid设置时间,到期自动失效 - 主动清理:用
proxy_cache_bypass绕过缓存 - 缓存清除:商业版 Nginx Plus 有
proxy_cache_purge
我一般用第二种方案,通过请求头控制:
# 特定请求头绕过缓存
proxy_cache_bypass $http_x_nocache;
# 或者通过特定参数绕过
proxy_cache_bypass $arg_nocache;
需要刷新缓存时,加个 ?nocache=1 或请求头 X-Nocache: 1 即可。
2.4 降级策略:后端挂了也能服务
proxy_cache_use_stale 这个配置很实用。当后端服务出错或超时时,Nginx 可以返回过期的缓存内容,而不是直接报错。
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
去年双十一,我们后端服务扩容时出了点问题,API 服务间歇性 502。好在缓存配置了这个降级策略,用户访问基本没受影响——虽然缓存过期了几分钟,但内容还能正常返回。等后端恢复后,缓存自动更新。
实测数据对比:
| 指标 | 无缓存 | 缓存命中 | 降级模式 |
|---|---|---|---|
| 响应时间 | 150-200ms | 5-10ms | 5-10ms |
| 后端 QPS | 1000 | 50 | 0 |
| 用户体验 | 正常 | 正常 | 略慢 |
缓存命中时,响应时间从 200ms 降到 5-10ms,快了将近 20 倍。这个收益太直观了。
第三章:连接池配置 — 高并发场景必备
gzip 和缓存解决的是”怎么传输更快”,连接池解决的是”怎么承载更多请求”。默认配置下,单个 Nginx worker 最大并发只有 1024 个连接。流量一上来,直接不够用。
3.1 worker_connections:算清楚上限
最大并发连接数的计算公式:
最大并发 = worker_processes × worker_connections
假设你的服务器有 8 核 CPU,worker_processes 设为 8(或 auto 自动匹配),worker_connections 设为 4096:
最大并发 = 8 × 4096 = 32768
这个数字看起来很大,但要记住:每个请求通常占用两个连接(客户端到 Nginx,Nginx 到后端)。所以实际能处理的并发请求大概是这个数字的一半左右。
配置在 events 块:
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
use epoll 在 Linux 上是默认值,不需要显式写,但写上更清晰。multi_accept on 让 worker 同时接受多个新连接,在高并发场景下能减少连接排队。
3.2 客户端 keepalive:复用连接,减少开销
TCP 连接建立需要三次握手,开销不小。keepalive 让客户端和 Nginx 之间的连接可以复用,不必每次请求都重新建连。
http {
keepalive_timeout 65;
keepalive_requests 1000;
}
keepalive_timeout 65:连接保持 65 秒,超过就关闭。这个值不宜太大,否则会占用过多服务器资源;也不宜太小,否则复用效果不明显。60-75 秒是个合理区间。
keepalive_requests 1000:单个连接最多处理 1000 个请求。设得太小会频繁断连,设得太大可能导致资源泄漏。1000 是我测试下来比较稳妥的值。
3.3 upstream keepalive:后端连接池
这个配置很多人不知道,但效果很明显。Nginx 和后端服务之间也可以复用连接,减少频繁建立 TCP 的开销。
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
keepalive 64;
keepalive_timeout 60s;
keepalive_requests 1000;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
keepalive 64:保持 64 个空闲连接池。这个值根据你的后端服务数量调整,一般设为后端服务器数量的 4-8 倍。
proxy_http_version 1.1 和 proxy_set_header Connection "" 这两行必须加。HTTP/1.1 默认支持 keepalive,清空 Connection 头才能复用连接。不写这两行,upstream keepalive 不会生效。
实测效果对比:
| 配置 | 连接建立次数/分钟 | CPU 开销 | 推荐场景 |
|---|---|---|---|
| 无 upstream keepalive | 6000 | 高 | 低流量 |
| keepalive 32 | 3000 | 中 | 中流量 |
| keepalive 64 | 1500 | 低 | 高流量 |
加了 upstream keepalive 后,连接建立开销直接砍掉 50%。这个配置在高并发场景下尤其重要。
3.4 推荐参数速查表
我整理了一份不同场景下的推荐配置:
| 参数 | 低流量(<1000 QPS) | 中流量(1000-5000 QPS) | 高流量(>5000 QPS) |
|---|---|---|---|
| worker_processes | auto | auto | auto |
| worker_connections | 1024 | 2048 | 4096 |
| keepalive_timeout | 60 | 65 | 75 |
| keepalive_requests | 100 | 500 | 1000 |
| upstream keepalive | 16 | 32 | 64 |
这只是起点,实际调整需要结合压测数据。我一般会用 wrk 或 ab 做压测,看连接数和响应时间的变化曲线,找到最优值。
第四章:综合配置模板 — 生产环境即用
前面三章讲了原理,这里直接给一个整合后的配置模板。你可以根据实际场景调整参数,但框架是通用的。
# nginx.conf 生产环境模板
user nginx;
worker_processes auto;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
# gzip 压缩配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml
application/xml+rss application/xhtml+xml;
gzip_disable "msie6";
# 缓存路径配置
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=my_cache:10m
max_size=10g
inactive=60m
use_temp_path=off;
# 客户端连接配置
keepalive_timeout 65;
keepalive_requests 1000;
# 后端服务器组
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
keepalive 64;
keepalive_timeout 60s;
keepalive_requests 1000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
# 缓存配置
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_key $scheme$request_method$host$request_uri;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
# 调试用响应头
add_header X-Cache-Status $upstream_cache_status;
}
}
}
三类场景的差异化配置
电商网站:首页和商品详情页变化频繁,缓存时间短一点,10-15 分钟足够。upstream keepalive 要大,因为数据库查询多,后端压力大。
API 服务:数据实时性要求高,proxy_cache_valid 可能只有 1-5 分钟。gzip 对 JSON 效果好,务必加上。
静态站点:HTML、CSS、JS 几乎不变,缓存可以设到 1 小时甚至更长。gzip 压缩收益最大,静态文件文本多。
第五章:常见问题与排错
几个我遇到过的高频问题,直接给解决方案。
Q:gzip 压缩不生效,响应头没有 Content-Encoding: gzip
检查三个地方:
gzip on是否在正确的配置层级(http 块)gzip_types是否包含你的响应 MIME 类型- 响应体积是否大于
gzip_min_length
用 curl 测试:curl -H "Accept-Encoding: gzip" -I http://your-site.com
Q:缓存命中率很低,X-Cache-Status 大多是 MISS
常见原因:
- 缓存键设计不合理,每个请求都被视为”不同”
proxy_cache_valid设置太短,缓存还没用就过期了- 后端返回的响应头有
Cache-Control: no-cache或Set-Cookie
检查响应头,确认没有禁止缓存的指令。
Q:worker_connections 不够用,出现 502 错误
看 Nginx 错误日志,如果有 worker_connections are not enough,说明并发超过上限。
解决方案:
- 增加
worker_connections值 - 检查是否有连接泄漏(keepalive 设置不合理)
- 考虑增加服务器数量做负载均衡
Q:内存占用过高,服务器频繁 OOM
可能原因:
proxy_cache_path的keys_zone设太大- 缓存文件太多,内存映射占用高
keepalive连接池太大,空闲连接占用资源
适当调小这些参数,或者给服务器加内存。
写在最后
Nginx 性能调优的核心三板斧:gzip 压缩、缓存策略、连接池配置。三个模块配合得当,能让你的网站加载速度翻倍,并发能力提高三四倍。
调优不是一次做完就完事。我建议按这个路线走:
- 先开 gzip:改动最小,收益最直接,十分钟搞定
- 再配缓存:根据业务场景设计缓存策略,一天内能完成
- 最后调连接池:需要压测验证,适合流量稳定后做
每次改动后,记得压测验证效果。wrk 或 ab 都可以,看响应时间、QPS、错误率的变化。别凭感觉调,用数据说话。
最后的检查清单,你可以对照执行:
- gzip 已开启,MIME 类型配置完整
- gzip_comp_level 设为 4-6,平衡 CPU 和压缩率
- proxy_cache_path 已配置,缓存大小合理
- proxy_cache_valid 根据业务场景设置
- proxy_cache_use_stale 降级策略已配置
- worker_connections 设为 4096 或更高
- keepalive_timeout 设为 60-75 秒
- upstream keepalive 已配置(含 HTTP/1.1 和 Connection 头)
- 响应头包含 X-Cache-Status 用于调试
差不多就这些。有问题可以评论区留言,我尽量回复。
Nginx 性能调优配置流程
三步完成 gzip 压缩、缓存策略、连接池优化的生产环境配置
⏱️ 预计耗时: 30 分钟
- 1
步骤1: 开启 gzip 压缩
在 http 块添加配置:
• gzip on; 开启压缩
• gzip_vary on; 添加 Vary 响应头
• gzip_comp_level 6; 设置压缩级别(推荐 4-6)
• gzip_min_length 1000; 小于 1KB 不压缩
• gzip_types 指定 MIME 类型:text/plain text/css application/json application/javascript - 2
步骤2: 配置 proxy_cache 缓存
分两步配置:
第一步:定义缓存路径
• proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m
第二步:在 location 启用缓存
• proxy_cache my_cache;
• proxy_cache_valid 200 10m; 正常响应缓存 10 分钟
• proxy_cache_use_stale error timeout http_502; 配置降级策略 - 3
步骤3: 优化连接池参数
三个关键配置:
• worker_connections 4096; 在 events 块设置
• keepalive_timeout 65; keepalive_requests 1000; 在 http 块设置
• upstream keepalive 64; proxy_http_version 1.1; proxy_set_header Connection ""; 后端连接池配置
常见问题
gzip 压缩级别选多少合适?
proxy_cache 和 fastcgi_cache 怎么选?
worker_connections 设多少合适?
缓存命中率低怎么排查?
upstream keepalive 为什么必须配置 HTTP/1.1?
不同业务场景的缓存时间怎么设置?
13 分钟阅读 · 发布于: 2026年4月11日 · 修改于: 2026年4月11日
相关文章
GitHub Actions 入门:YAML 工作流基础与触发器配置
GitHub Actions 入门:YAML 工作流基础与触发器配置
GitHub Actions 入门:YAML 工作流基础与触发器配置
GitHub Actions 入门:YAML 工作流基础与触发器配置
Docker Compose 多服务编排:本地开发环境一键启动

评论
使用 GitHub 账号登录后即可评论