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」生效。常见失效场景和应对方式:
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
- 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 条

















