proxy_cache_lock 不能防止击穿,仅将并发回源转为串行;需配齐缓存区、启用缓存、开启锁及合理超时三要素,且 key 必须一致,再配合 stale 回退与缓存有效期控制才有效。

proxy_cache_lock 本身不能“防止击穿”,它只能把并发回源压成串行,让后端只承受一个请求的压力。真正起效的前提是配置完整、key 稳定、超时合理,并配合 stale 回退和缓存有效期控制。
必须配齐的基础三要素
缺一不可,否则 lock 完全不触发:
- 在 http 块 中定义缓存区:
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=my_cache:10m inactive=60m use_temp_path=off;——keys_zone是锁的内存载体,没它 lock 就没地方存状态 - 在 location 块 中启用缓存:
proxy_cache my_cache;—— 没缓存就没有 miss,lock 就无从谈起 - 在同一 location 中开启锁并设超时:
proxy_cache_lock on; proxy_cache_lock_timeout 5s;—— timeout 太短(如 1s)会导致等待请求快速放弃锁,仍并发回源;太长(如 30s)会让用户明显卡顿
让锁真正覆盖所有同类请求
锁只对「完全一致的 cache key」生效。常见失效场景和应对方式:
阿里百炼大模型平台多人共享账号用量统计代理服务。解决公司共用账号时无法区分个人用量的问题。适用场景:1)部署用量统计代理;2)统计多人Token用量和调用次数;3)管理大模型API调用配额。
- query 参数不同(如
/api/user?id=1和/api/user?id=2)→ 用proxy_cache_key "$scheme$host$uri";剥离$args,统一锁定整个路径 - 前端加随机参数(
?t=1713086520或?v=2.3.1)→ 同样通过自定义 key 忽略这些字段,或让前端改用文件名哈希代替参数版本号 - Cookie 或 header 差异(如登录态带 session)→ 配合
proxy_ignore_headers Set-Cookie;和精简的proxy_cache_key,避免把用户身份信息混进 key
光靠锁不够,还得加两道保险
即使锁生效,首个请求也可能失败或慢,后续请求不能干等:
- 启用 stale 回退:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;—— 当锁持有者回源出错或超时,等待中的请求可立即返回旧缓存,不卡顿也不穿透 - 延长热点缓存时间:
proxy_cache_valid 200 302 30s;(API)或proxy_cache_valid 200 302 1h;(静态资源)—— MISS 越少,锁竞争越弱,后端压力自然下降
验证是否真生效
别只看配置,要观测实际行为:
- 加响应头:
add_header X-Cache-Status $upstream_cache_status;,用curl -I查看:首次应为MISS,紧随其后的并发请求若返回HIT,说明锁成功复用结果;若仍是MISS,说明 key 不一致或配置未加载 - 压测验证:用
ab -n 20 -c 10请求同一 URL,检查后端 access log —— 开启 lock 后应只记录 1 条访问,而不是 10 条










