切换语言
切换主题

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)推荐场景
165%2CPU 紧张
472%3平衡型(推荐)
675%5带宽紧张(推荐)
978%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 哪些文件类型收益最大?

根据我这边的实测数据,不同文件类型的压缩效果差异挺大:

文件类型原始大小压缩后压缩率
HTML100KB20-25KB75-80%
CSS80KB24-28KB65-70%
JavaScript120KB36-42KB65-70%
JSON API50KB20-25KB50-60%
图片/视频已压缩无意义0-5%
75-80%
HTML 文件压缩率
来源: 生产环境实测数据

图片和视频本身就经过压缩(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,或者有多个域名,这个配置会更精确。

缓存失效是个头疼的问题。常见的策略:

  1. 时间过期proxy_cache_valid 设置时间,到期自动失效
  2. 主动清理:用 proxy_cache_bypass 绕过缓存
  3. 缓存清除:商业版 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-200ms5-10ms5-10ms
后端 QPS1000500
用户体验正常正常略慢
95%
缓存命中率
来源: 生产环境实测

缓存命中时,响应时间从 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.1proxy_set_header Connection "" 这两行必须加。HTTP/1.1 默认支持 keepalive,清空 Connection 头才能复用连接。不写这两行,upstream keepalive 不会生效。

实测效果对比:

配置连接建立次数/分钟CPU 开销推荐场景
无 upstream keepalive6000低流量
keepalive 323000中流量
keepalive 641500高流量

加了 upstream keepalive 后,连接建立开销直接砍掉 50%。这个配置在高并发场景下尤其重要。

3.4 推荐参数速查表

我整理了一份不同场景下的推荐配置:

参数低流量(<1000 QPS)中流量(1000-5000 QPS)高流量(>5000 QPS)
worker_processesautoautoauto
worker_connections102420484096
keepalive_timeout606575
keepalive_requests1005001000
upstream keepalive163264

这只是起点,实际调整需要结合压测数据。我一般会用 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

检查三个地方:

  1. gzip on 是否在正确的配置层级(http 块)
  2. gzip_types 是否包含你的响应 MIME 类型
  3. 响应体积是否大于 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-cacheSet-Cookie

检查响应头,确认没有禁止缓存的指令。

Q:worker_connections 不够用,出现 502 错误

看 Nginx 错误日志,如果有 worker_connections are not enough,说明并发超过上限。

解决方案:

  1. 增加 worker_connections
  2. 检查是否有连接泄漏(keepalive 设置不合理)
  3. 考虑增加服务器数量做负载均衡

Q:内存占用过高,服务器频繁 OOM

可能原因:

  • proxy_cache_pathkeys_zone 设太大
  • 缓存文件太多,内存映射占用高
  • keepalive 连接池太大,空闲连接占用资源

适当调小这些参数,或者给服务器加内存。

写在最后

Nginx 性能调优的核心三板斧:gzip 压缩、缓存策略、连接池配置。三个模块配合得当,能让你的网站加载速度翻倍,并发能力提高三四倍。

调优不是一次做完就完事。我建议按这个路线走:

  1. 先开 gzip:改动最小,收益最直接,十分钟搞定
  2. 再配缓存:根据业务场景设计缓存策略,一天内能完成
  3. 最后调连接池:需要压测验证,适合流量稳定后做

每次改动后,记得压测验证效果。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

    步骤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

    步骤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

    步骤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 压缩级别选多少合适?
推荐 4-6 级。级别 4 压缩率 72%、CPU 消耗低,适合 CPU 紧张场景;级别 6 压缩率 75%、带宽节省更多,适合带宽紧张场景。级别 9 CPU 消耗翻倍但压缩率提升有限,不推荐。
proxy_cache 和 fastcgi_cache 怎么选?
看后端技术栈:Node.js、Python、Go 等应用服务器用 proxy_cache;PHP-FPM 用 fastcgi_cache。两者配置逻辑几乎一样,核心参数都是缓存路径、有效期、缓存键设计。
worker_connections 设多少合适?
根据 CPU 核心数和流量预估:低流量(&lt;1000 QPS)设 1024;中流量(1000-5000 QPS)设 2048;高流量(&gt;5000 QPS)设 4096。实际并发能力 = worker_processes × worker_connections ÷ 2。
缓存命中率低怎么排查?
三步排查:1. 检查缓存键是否合理,避免每个请求都不同;2. 检查 proxy_cache_valid 时长是否太短;3. 检查后端响应头是否有 Cache-Control: no-cache 或 Set-Cookie 禁止缓存。
upstream keepalive 为什么必须配置 HTTP/1.1?
HTTP/1.0 默认不支持 keepalive,必须用 HTTP/1.1 才能复用后端连接。同时需要 proxy_set_header Connection "" 清空 Connection 头,否则 Nginx 会关闭连接,upstream keepalive 不生效。
不同业务场景的缓存时间怎么设置?
电商网站首页和商品详情页变化频繁,缓存 10-15 分钟;API 服务实时性要求高,缓存 1-5 分钟;静态站点 HTML/CSS/JS 几乎不变,缓存 1 小时以上。核心原则:业务变化越快,缓存时间越短。

13 分钟阅读 · 发布于: 2026年4月11日 · 修改于: 2026年4月11日

评论

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

相关文章