网站后台慢、数据库扛不住、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 清除机制就能完整跑起来。


