proxy_cache_lock 仅串行化同 key 回源请求,防数据库压垮需四点:锁得准(统一 cache_key)、锁得住(配齐 proxy_cache_path/lock/use_stale)、等不起有退路(stale+valid)、源头减压(合理缓存时长)。

proxy_cache_lock 本身不能“避免冲垮数据库”,它只负责把同一缓存 key 的并发回源请求串行化——即只让第一个请求去查数据库,其余请求等结果写入缓存后直接返回。真正决定数据库是否被压垮的,是配置是否完整、key 是否统一、超时是否合理、兜底是否到位。
要让它在数万并发下守住数据库,必须做到四件事:
-
锁得准
锁只对完全一致的cache_key生效。如果每个请求因参数、Cookie、随机字段不同而生成不同 key,那数万请求就变成数万个独立锁,等于没锁。
✅ 正确做法:- 剥离无关 query 参数:
proxy_cache_key "$scheme$host$uri";(忽略$args) - 过滤前端加的
?t=123、?v=2.3.1等干扰参数 - 忽略登录态差异:
proxy_ignore_headers Set-Cookie;,并在 key 中不包含$cookie_session
- 剥离无关 query 参数:
-
锁得住
没有缓存区、没启用缓存、location 里没开 lock,机制根本不会启动。
✅ 必须配齐三要素:-
http块中定义:proxy_cache_path /path keys_zone=my_cache:512m use_temp_path=off; - 对应
location中:proxy_cache my_cache; - 同一
location中:proxy_cache_lock on; proxy_cache_lock_timeout 5s;
-
-
等不起时有退路
数万请求排队等一个慢查询?不行。必须允许在异常时快速降级:
✅ 加这两条保命配置:-
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
→ 首个请求失败或超时,后续请求立刻返回旧缓存,不卡、不穿透 -
proxy_cache_valid 200 302 30s; proxy_cache_valid 404 10s;
→ 把空响应(404)也缓存 10 秒,防止恶意穿透反复打数据库
-
源头减压
MISS 越少,锁竞争越弱。30 秒有效期对多数 API 已足够抗住瞬时洪峰;静态资源可设为 1 小时甚至更长。
验证很简单:用 curl -I 发两个紧邻请求,看第二个是否返回 X-Cache-Status: HIT;再用 ab -c 100 -n 1000 压测,后端 access log 应只看到个位数的新增请求,而不是上百条。
不复杂,但容易忽略细节。











