Nginx 性能调优实战:gzip、缓存与连接池配置
上周接到报警,电商网站的首页加载时间飙升到 4 秒。打开 Chrome DevTools 一看,HTML 文件 120KB,CSS 加 JS 又是 350KB——全是未压缩的原始文件。更糟的是,每个请求都打到后端,缓存命中率只有可怜的 12%。当晚加完班,我花了 2 小时调整 Nginx 配置:gzip 压缩打开,缓存策略补齐,连接池参数调整。第二天早上再看,首页加载已经压到 1.6 秒,后端 QPS 降了快一半。
说实话,这类问题太常见了。很多人配 Nginx 就是装好就跑,gzip 默认不开,缓存随便写两行,连接数上限用默认值。结果一到流量高峰,服务器就喘不过气。
这篇文章把我在生产环境验证过的 Nginx 性能调优配置整理出来。gzip 压缩能减少 60-80% 的传输体积,换成 Brotli 还能再省 15-25%;缓存命中率 95% 时后端压力能少 90%;连接池配置合理的话并发能力能翻三四倍;再加上 Thread Pools 和 reuseport 这些进阶手段,单机 RPS 能冲到 50K-80K。我会把每个模块的配置细节、踩过的坑、实测数据都摊开讲清楚。
第一章:gzip/Brotli 压缩配置 — 减少传输体积
先说说 gzip 为什么这么重要。想象一下,你的 HTML 文件原始大小 100KB,通过 gzip 压缩后可能只有 20-25KB。这省下来的 75-80KB 带宽,对用户来说是更快的加载速度,对你来说是更低的流量成本。
我第一次意识到这个问题,是在一个客户的项目上。他们的移动端用户占比超过 60%,很多在 4G 网络环境下访问。首页加载要 3-4 秒,跳出率飙到 70%。加上 gzip 之后,传输体积直接砍掉 70%,首屏加载时间降到 1.5 秒左右。
1.1 gzip 基础配置:先让它跑起来
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 gzip 进阶配置:压缩级别和 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 类型都加上。
1.4 Brotli:比 gzip 再省 15-25%
如果你想更进一步,Brotli 是个更好的选择。这是 Google 开发的压缩算法,在相同压缩级别下,比 gzip 压缩率高出 15-25%。特别适合静态资源,因为浏览器对 Brotli 的支持已经很广泛了。
不过有个坑:Brotli 不是 Nginx 默认模块,需要额外编译或安装动态模块。我用的官方动态模块方式,不用重新编译 Nginx:
# 需要先加载模块(如果用动态模块)
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
http {
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json;
brotli_min_length 256;
}
Brotli 的压缩级别也是 1-11,但我建议设 6。级别太高(比如 11)压缩时间会明显增加,对于动态生成的内容不太合适。静态文件可以提前用 Brotli 最高级别压缩,Nginx 直接返回预压缩的 .br 文件。
实测对比数据:
| 压缩方式 | 100KB HTML 压缩后 | 压缩耗时 | 浏览器支持 |
|---|---|---|---|
| gzip (level 6) | 25KB | 5ms | 几乎全部 |
| Brotli (level 6) | 18KB | 15ms | 95%+ |
| Brotli (预压缩 level 11) | 15KB | 0 | 95%+ |
我的建议是:动态内容用 Brotli level 4-6,静态资源用预压缩方式。如果 Nginx 编译太麻烦,gzip 也够用了,毕竟 75% 的压缩率已经很可观。
第二章:缓存策略配置 — 静态内容加速
缓存是性能调优里收益最直接的一环。配置得当的话,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 倍。这个收益太直观了。
2.5 微缓存模式:动态内容也能加速
很多人以为动态内容不能缓存,其实可以用微缓存(microcaching)。就是把动态页面缓存 1-5 秒,在高并发瞬间也能大幅减轻后端压力。
我在一个电商首页上试过这个方案。首页有实时推荐、库存显示,完全动态化。但大促期间流量暴增,后端扛不住。我加了 5 秒微缓存:
proxy_cache_path /var/cache/nginx/micro levels=1:2 keys_zone=micro:10m max_size=1g;
location / {
proxy_cache micro;
proxy_cache_valid 200 5s; # 只缓存 5 秒
proxy_cache_lock on; # 防止缓存更新时并发请求穿透
proxy_cache_background_update on; # 后台异步更新缓存
}
proxy_cache_lock on 很关键。当缓存过期时,第一个请求去后端取新数据,其他请求等着用旧缓存。这样就不会出现”缓存失效瞬间,大量请求同时打到后端”的情况。
效果惊人。首页 TTFB 从 800ms 降到 5ms 左右,后端 QPS 从 2000 降到 400。5 秒的缓存延迟用户几乎感知不到,但服务器压力减轻了一大截。
2.6 条件请求:省带宽的技巧
proxy_cache_revalidate 让 Nginx 用条件请求(If-Modified-Since / If-None-Match)去后端验证缓存是否过期。如果后端返回 304 Not Modified,就不用重新传输完整内容,只更新缓存元数据。
proxy_cache_revalidate on;
这个配置对带宽敏感的场景特别有用。比如你的后端返回大文件,但内容变化不频繁,用条件请求能省掉大量数据传输。
第三章:连接池配置 — 高并发场景必备
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 是我测试下来比较稳妥的值。
还有个新参数 keepalive_time,控制单个连接的总存活时间(不管处理了多少请求)。如果你的服务器长时间运行,连接累积可能导致资源问题,可以加上:
keepalive_time 1h; # 单个连接最多存活 1 小时
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 文件描述符限制:别忘了系统层
Nginx 的连接数受限于系统的文件描述符上限。如果你的 worker_connections 设成 4096,但系统只允许每个进程打开 1024 个文件,那还是不够用。
检查当前限制:
ulimit -n
如果返回值小于 65536,需要在系统配置中提升。编辑 /etc/security/limits.conf:
* soft nofile 65536
* hard nofile 65536
然后在 Nginx 配置中也声明一下:
worker_rlimit_nofile 65536;
这个配置放在 main 块(worker_processes 同级),让 Nginx 启动时就申请足够的文件描述符。
3.5 推荐参数速查表
我整理了一份不同场景下的推荐配置:
| 参数 | 低流量(<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 |
| worker_rlimit_nofile | 4096 | 8192 | 65536 |
这只是起点,实际调整需要结合压测数据。我一般会用 wrk 或 ab 做压测,看连接数和响应时间的变化曲线,找到最优值。
第四章:进阶优化 — Thread Pools 与 reuseport
前三章覆盖了大多数场景的优化。如果你的流量特别大(单机 RPS 目标超过 50K),或者对延迟特别敏感,这里还有两个高级配置可以尝试。
4.1 Thread Pools:突破 sendfile 的瓶颈
Nginx 默认是单线程事件驱动模型,这对大多数场景足够高效。但在高并发静态文件服务时,有个隐藏瓶颈:sendfile 虽然是零拷贝,但文件读取和 socket 写入都在同一个 worker 线程里完成。当磁盘 IO 慢时,会阻塞整个 worker。
Thread Pools 就是解决这个问题的。它把文件读取和发送拆到独立线程池,worker 只负责调度,不阻塞在 IO 上。
Nginx 官方博客有个测试案例:单机 9 倍性能提升。测试场景是 1MB 文件下载,原本受磁盘 IO 限制,加 Thread Pools 后直接突破瓶颈。
配置方法:
http {
thread_pool default threads=32 max_queue=65536;
aio threads=default;
sendfile_max_chunk 512k;
}
threads=32 表示线程池 32 个线程,max_queue=65536 是最大排队任务数。aio threads=default 启用异步 IO 并指定用哪个线程池。sendfile_max_chunk 512k 控制每次发送的数据块大小,避免大文件占用太久。
不过 Thread Pools 不是万能药。如果你的后端是动态内容为主(API 服务),磁盘 IO 不是瓶颈,加了反而可能增加上下文切换开销。我的建议是:静态文件服务、大文件下载场景才考虑开启。
4.2 Socket Sharding (reuseport):降低连接延迟
Nginx 1.9.1 引入了 reuseport 参数,让多个 worker 可以独立监听同一个端口,避免 worker 之间争抢锁。
传统模式下,所有 worker 共享一个监听 socket,新连接来时要争抢 accept mutex。这在高并发时会有明显的锁竞争开销,延迟抖动。
加了 reuseport 后:
server {
listen 80 reuseport;
}
每个 worker 有独立的监听 socket,内核自动把新连接分配给不同 worker。完全去掉了锁竞争。
实测数据(来源 Nginx 官方博客):
| 指标 | 无 reuseport | 有 reuseport |
|---|---|---|
| 平均延迟 | 15.65ms | 12.35ms |
| 延迟标准差 | 3.5ms | 1.2ms |
| 连接分布 | 不均匀 | 均匀 |
延迟降低 21%,更重要的是延迟抖动明显减少。这个配置在高并发场景(QPS 超过 20K)效果最明显,低流量场景可能感知不强。
4.3 open_file_cache:文件描述符缓存
静态文件服务场景,可以用 open_file_cache 缓存文件描述符和元数据,避免每次请求都去查磁盘:
http {
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
max=10000:最多缓存 10000 个文件信息inactive=30s:30 秒无人访问就清理open_file_cache_valid 60s:每 60 秒校验一次缓存是否过期open_file_cache_errors on:也缓存文件不存在等错误状态
这个配置对静态站点效果明显。但动态内容场景不建议用,因为文件可能频繁变化,缓存反而导致内容不更新。
第五章:综合配置模板 — 生产环境即用
前面四章讲了原理,这里直接给一个整合后的配置模板。你可以根据实际场景调整参数,但框架是通用的。
# nginx.conf 生产环境模板(高流量场景)
user nginx;
worker_processes auto;
worker_rlimit_nofile 65536;
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;
keepalive_time 1h;
# 文件缓存(静态站点可选)
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
# 后端服务器组
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 reuseport;
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;
proxy_cache_revalidate on;
# 调试用响应头
add_header X-Cache-Status $upstream_cache_status;
}
}
}
三类场景的差异化配置
电商网站:首页和商品详情页变化频繁,缓存时间短一点,10-15 分钟足够。upstream keepalive 要大,因为数据库查询多,后端压力大。微缓存在大促期间可以开启,缓存 1-3 秒。
API 服务:数据实时性要求高,proxy_cache_valid 可能只有 1-5 分钟。gzip 对 JSON 效果好,务必加上。Brotli 如果能装就装,API 响应体积小但请求频繁,压缩收益可观。
静态站点:HTML、CSS、JS 几乎不变,缓存可以设到 1 小时甚至更长。gzip 压缩收益最大,静态文件文本多。open_file_cache 和 Thread Pools 可以开启,文件描述符缓存和异步 IO 对静态内容有明显帮助。
性能提升对比(更新版)
| 配置项 | 优化前 | 优化后 | 提升比例 |
|---|---|---|---|
| HTML 传输体积 (gzip) | 100KB | 25KB | 75% ↓ |
| HTML 传输体积 (Brotli) | 100KB | 18KB | 82% ↓ |
| API 响应时间(缓存命中) | 200ms | 8ms | 96% ↓ |
| 并发连接能力 | 1000 | 4000 | 4x ↑ |
| RPS (单机优化后) | 10K | 50K-80K | 5-8x ↑ |
| TTFB (reuseport) | 15.65ms | 12.35ms | 21% ↓ |
这些数据是我实测和官方文档综合的结果。实际效果取决于你的服务器配置、网络环境和业务特点,压测验证很重要。
第六章:常见问题与排错
几个我遇到过的高频问题,直接给解决方案。
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:gzip 和 sendfile 冲突?
不会冲突。gzip 压缩的是响应内容,sendfile 处理的是文件传输方式。两者可以同时启用。唯一要注意的是:gzip 对动态内容需要在内存中压缩,不走 sendfile;静态预压缩文件可以直接 sendfile。
Q:upstream keepalive 不生效?
两个常见原因:
- 漏了
proxy_http_version 1.1,HTTP/1.0 默认不支持 keepalive - 漏了
proxy_set_header Connection "",不清空这个头,连接会被关闭
这两行必须加在 location 块里,不是 upstream 块。
Q:reuseport 报错 “duplicate listen options”?
reuseport 只能在 listen 行声明一次,不能在其他地方重复。确保每个 server 块的 listen 行最多出现一次 reuseport。如果多个 server 监听同一端口,每个都要独立加 reuseport。
Q:内存占用过高,服务器频繁 OOM
可能原因:
proxy_cache_path的keys_zone设太大- 缓存文件太多,内存映射占用高
keepalive连接池太大,空闲连接占用资源
适当调小这些参数,或者给服务器加内存。
写在最后
说了这么多,其实 Nginx 性能调优的核心就是三件事:压缩、缓存、连接池。再加几个进阶手段(Brotli、微缓存、Thread Pools、reuseport),就能把单机 RPS 从 10K 提到 50K-80K。
调优不是一次做完就完事。我建议按这个路线走:
- 先开 gzip:改动最小,收益最直接,十分钟搞定
- 再配缓存:根据业务场景设计缓存策略,一天内能完成
- 然后调连接池:需要压测验证,适合流量稳定后做
- 最后试进阶优化:Thread Pools 和 reuseport,流量特别大才考虑
每次改动后,记得压测验证效果。wrk 或 ab 都可以,看响应时间、QPS、错误率的变化。别凭感觉调,用数据说话。
最后的检查清单,你可以对照执行:
- gzip 已开启,MIME 类型配置完整
- gzip_comp_level 设为 4-6,平衡 CPU 和压缩率
- Brotli 已配置(如果可用)
- proxy_cache_path 已配置,缓存大小合理
- proxy_cache_valid 根据业务场景设置
- 微缓存已开启(高并发动态内容场景)
- proxy_cache_use_stale 降级策略已配置
- worker_connections 设为 4096 或更高
- keepalive_timeout 设为 60-75 秒
- upstream keepalive 已配置(含 HTTP/1.1 和 Connection 头)
- reuseport 已开启(高流量场景)
- 文件描述符限制已提升(65536)
- 响应头包含 X-Cache-Status 用于调试
差不多就这些。有问题可以评论区留言,我尽量回复。
常见问题
gzip 压缩不生效,响应头没有 Content-Encoding: gzip 怎么办?
缓存命中率很低,X-Cache-Status 大多是 MISS 怎么排查?
worker_connections 不够用,出现 502 错误如何解决?
upstream keepalive 不生效的常见原因是什么?
Brotli 和 gzip 如何选择?
不同流量场景的推荐配置参数是什么?
18 分钟阅读 · 发布于: 2026年5月15日 · 修改于: 2026年5月15日
评论
使用 GitHub 账号登录后即可评论