proxy_cache_lock 通过 Nginx 代理层串行化缓存失效时的回源请求来保护后端应用,间接减轻数据库压力;需配齐 proxy_cache_path、proxy_cache、proxy_cache_lock 三项配置,并合理设置 cache_key、忽略干扰响应头、启用 stale 容错及缓存时效策略。

proxy_cache_lock 本身不直接保护数据库,它保护的是后端应用服务(如 API 网关、Web 应用),间接减少打到数据库的请求量。真正让数据库崩溃的,往往是上游应用在缓存失效时被海量并发请求击穿,从而密集查询数据库。所以关键不是“锁数据库”,而是让 Nginx 在代理层把并发回源压成串行,并快速复用结果。
要让它切实起效,得从配置闭环入手,缺一不可。
必须配齐的三个基础环节
-
proxy_cache_path在http块中定义缓存区和共享内存锁载体,例如:proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=my_cache:512m inactive=3h use_temp_path=off;
keys_zone名称(如my_cache)后续会被引用;use_temp_path=off避免临时文件拷贝,提升锁状态一致性。 proxy_cache my_cache在目标location中启用缓存——没缓存就没有MISS,lock完全不触发。proxy_cache_lock on; proxy_cache_lock_timeout 5s;同一location内开启并设超时;超时建议 3–8 秒:太短(如 1s),等待请求放弃锁直接回源;太长(如 30s),用户明显卡顿。
让锁真正覆盖数据库查询类请求
锁只对完全一致的缓存 key 生效。而数据库压力常来自动态接口(如 /api/order?id=123),默认 key 含 $args,导致每个 ID 都是独立 key,锁形同虚设。
应主动简化 key,例如:
- 统一锁定整个订单查询接口:
proxy_cache_key "$scheme$host:/api/order";
- 或剥离所有 query 参数,保留路径主体:
proxy_cache_key "$scheme$host$uri";
同时禁用干扰缓存的响应头:
proxy_ignore_headers Set-Cookie Vary;
否则带
Set-Cookie的响应默认不缓存,lock就无从介入。
加两道容错,避免锁持有者失败拖垮全局
即使锁生效,首个请求也可能超时、报错或慢得离谱。不能让其余请求干等或全部降级。
-
允许返回过期缓存应对异常:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当锁持有者回源失败或超时,等待请求可立即返回旧缓存(stale),不卡顿、不穿透。
-
延长热点接口缓存时间,从源头减少
MISS:proxy_cache_valid 200 302 30s; # 普通 API # 或对读多写少的查询(如商品详情)设为 5–10 分钟 proxy_cache_valid 200 302 5m;
验证是否真起作用
别信配置,看行为:
-
在
location中加响应头:add_header X-Cache-Status $upstream_cache_status;
-
用
curl -I发起两次以上并发请求(如ab -n 20 -c 10),观察:- 首次响应头含
X-Cache-Status: MISS - 紧随其后的响应若为
HIT,说明锁成功复用结果;若仍是MISS,说明 key 不一致或缓存未命中逻辑被绕过(比如响应头含Cache-Control: no-cache)。
- 首次响应头含
查后端 access log:开启 lock 后,并发请求打到后端的日志条数应显著收敛为 1 条(或略多,因超时重试)。
不复杂但容易忽略。


















