Nginx 缓存配置详解:proxy_cache 页面缓存、缓存清除、命中率调优与防击穿实战


网站后台慢、数据库扛不住、CPU 动不动 100%?同样的页面每次访问都要重新生成一次,太浪费了。Nginx 缓存(proxy_cache)可以把动态页面(PHP、Java、Python 生成的结果)缓存成静态文件,第二次访问直接返回缓存,后端压力骤降、响应速度翻倍。这篇文章把 Nginx 缓存的配置、命中率查看、缓存清除和常见坑一次讲透。

一、Nginx 缓存是什么?解决什么问题

Nginx 作为反向代理在网站最前面,用户请求先到 Nginx,再由 Nginx 转发给后端(如 PHP-FPM、Tomcat)。开启 proxy_cache 后,Nginx 会把后端返回的页面存一份到磁盘,相同请求直接返回缓存,不再访问后端。

用户 --> Nginx(有缓存就直接返回)
            |
            +---> 后端 PHP/Java(第一次生成,之后不再打扰)

适合缓存:文章页、商品页、列表页等动态但内容相对固定的页面。不适合:购物车、用户个人中心、评论区等强个性化内容。

二、基础配置:启用 proxy_cache

第 1 步:在 http 块定义缓存路径(nginx.conf 中 http {} 里)

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:100m
                     max_size=10g inactive=60m use_temp_path=off;
}

参数说明:

参数 作用
/var/cache/nginx 缓存文件存放目录
levels=1:2 缓存目录层级,分散文件,1:2 最常用
keys_zone=my_cache:100m 缓存索引放内存,100m 约可存 800 万 key
max_size=10g 磁盘缓存上限,超出按 LRU 淘汰
inactive=60m 60 分钟没人访问的缓存自动删除
use_temp_path=off 避免缓存写入临时目录再拷贝,提升性能

第 2 步:在 server/location 块启用缓存

server {
    location / {
        proxy_cache my_cache;                    # 启用缓存
        proxy_cache_valid 200 60m;               # 200 状态缓存 60 分钟
        proxy_cache_valid 404 1m;                # 404 只缓存 1 分钟
        proxy_cache_key "$host$request_uri";     # 缓存 key
        add_header X-Cache-Status $upstream_cache_status;  # 调试:看命中情况

        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
    }
}

配置好后重载:

nginx -t && nginx -s reload

三、怎么确认缓存生效(命中率)

配置里加了 add_header X-Cache-Status,用 curl 就能看到命中状态:

curl -I https://yourdomain.com/post/1

看响应头:

X-Cache-Status: MISS    # 第一次访问,未命中,已写入缓存
X-Cache-Status: HIT     # 命中缓存,直接从缓存返回
X-Cache-Status: EXPIRED # 缓存过期,重新向后端请求
X-Cache-Status: BYPASS  # 被强制绕过缓存

连续访问两次,第二次应该是 HIT,说明缓存生效。查看缓存目录占用:

du -sh /var/cache/nginx

四、缓存清除:purge

内容更新了,但缓存还是旧的,需要主动清除。推荐用 ngx_cache_purge 模块。

第 1 步:编译时加模块(或直接用集成该模块的发行版如 OpenResty)

./configure --add-module=../ngx_cache_purge-2.5
make && make install

第 2 步:配置清除接口(只允许内网/管理员访问)

location ~ /purge(/.*) {
    allow 127.0.0.1;
    deny all;
    proxy_cache_purge my_cache "$host$1";
}

清除某个页面缓存:

curl http://127.0.0.1/purge/post/1

不用模块的土办法:直接删缓存文件。

find /var/cache/nginx -type f | xargs rm -f
nginx -s reload    # 或只删特定 key 对应文件

简单粗暴,全站缓存一次清空,适合低频更新站点。

五、按页面/参数精细控制缓存

1. 只缓存特定路径(比如只缓存文章页)

location ~ ^/post/ {
    proxy_cache my_cache;
    proxy_cache_valid 200 60m;
    proxy_pass http://127.0.0.1:8080;
}

2. 带查询参数的页面不缓存或差异化缓存

# 不同参数单独缓存(如分页)
proxy_cache_key "$host$request_uri";

# 或者带 cookie 的请求不缓存
location / {
    if ($http_cookie ~ "session_id") {
        set $skip_cache 1;
    }
    proxy_cache_bypass $skip_cache;
    proxy_no_cache $skip_cache;
}

3. 后端标记的页面不缓存(后端返回特定响应头时)

# 后端返回 Set-Cookie 的响应不缓存
proxy_no_cache $sent_http_set_cookie;

六、命中率调优与防击穿

1. 提高命中率的技巧

  • 缓存 key 尽量简单:$host$request_uri 即可,不要带上时间戳等易变因素;
  • inactive 设大一点(如 24h),减少缓存被清理的频率;
  • 对热门页面用 proxy_cache_lock on 防止同时多个请求打后端。
proxy_cache_lock on;                # 缓存不存在时,只放一个请求去后端
proxy_cache_lock_timeout 5s;        # 防止锁等待过长

2. 防缓存击穿(热点 key 过期瞬间大量请求压垮后端)

开启 cache_lock 后,同一时刻只有一个请求会穿透到后端,其余等待缓存生成,后端压力大幅降低。

3. 后台更新时避免缓存雪崩

给缓存时间加一点随机抖动:

# 通过 proxy_cache_valid 配合变量做随机化
proxy_cache_valid 200 ${cache_time};

cache_time 可以用 map 按 URI 设置不同值,避免全站缓存同时过期。

七、常见问题排查

1. 配置后 curl 没有 X-Cache-Status 头

确认 add_header 写在了启用缓存的 location 里,且重载了配置(nginx -s reload)。

2. 命中率一直很低

检查缓存 key 是否包含了易变参数、inactive 是否过短、页面是否带 cookie 被 no_cache 绕过了。

3. 缓存目录权限报错

Nginx worker 用户需要缓存目录写权限:

mkdir -p /var/cache/nginx
chown -R nginx:nginx /var/cache/nginx

4. 改了后端,页面不更新

主动清除对应缓存(purge 或删文件),或等待缓存过期。

5. 磁盘被缓存撑爆

调小 max_size,或者调整 inactive 让冷缓存早点清理;也可以对不重要的路径不缓存。

总结

Nginx proxy_cache 是性价比极高的性能优化手段:一个配置文件就能让动态站点的响应速度提升数倍、后端负载大幅下降。核心配置就三件事——proxy_cache_path 定义缓存空间、proxy_cache 启用、proxy_cache_valid 设定缓存时间,再加一个 X-Cache-Status 头观察命中率,配合 purge 清除机制就能完整跑起来。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

iptables 防火墙详解:四表五链、常用规则、NAT 端口转发与规则持久化实战

MongoDB 安装与基础操作教程:集合、增删改查、索引、备份恢复与远程连接实战

评 论
更换验证码