proxy_cache_lock 不能避免缓存击穿,仅对同一 key 的并发 MISS 请求串行化:首请求回源,其余等待缓存写入后直接读取;需配齐缓存区定义、location 启用及 key 统一三要素,否则不生效。

proxy_cache_lock 不能“避免”缓存击穿,它只对同一缓存 key 的并发未命中(MISS)请求做串行化:放行第一个去回源,其余等待结果写入后直接读缓存。要让它在高并发激增时真正起效,必须把锁对准真实热点,并堵住 key 分裂、超时放弃、无兜底等漏洞。
基础三件套必须配齐
缺一不可,否则 lock 完全不触发:
- 在 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:512m 是核心,512MB 内存可支撑约 400 万个 key,覆盖常见热点接口;use_temp_path=off避免临时文件拷贝,提升一致性 - 确保
/var/cache/nginx/proxy_cache目录存在,且 Nginx 进程有读写权限(注意 Linux/macOS 下 umask 或 SELinux 限制) - 在目标 location 块 中启用缓存和锁:
proxy_cache my_cache;<br>proxy_cache_lock on;<br>proxy_cache_lock_timeout 5s;
——没proxy_cache my_cache,proxy_cache_lock on就是摆设
让锁真正锁住所有同类请求
锁只认 cache key,key 不一致 = 锁失效 = 并发回源照旧。常见干扰源和应对方式:
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
- 默认 key 含
$request_uri,/api/hot?id=1和/api/hot?id=2就是两个独立 key
→ 改用:proxy_cache_key "$scheme$host$uri";(剥离所有 query 参数) - 前端加随机参数(如
?t=1716942840、?v=2.4.1)会人为制造 key 差异
→ 更彻底收束:proxy_cache_key "$scheme$host:/api/hot"; - Cookie 或认证 Header(如
Authorization、User-Agent)不同也会分裂 key
→ 配合:proxy_ignore_headers Set-Cookie Vary;,并避免在 key 中引入$cookie_*或$http_*
控制等待行为 + 设置失败退路
光靠锁硬等风险高——首个请求可能慢、失败或超时。必须搭配两层保险:
-
超时设合理:
proxy_cache_lock_timeout 3–8s
太短(如 1s),等待请求快速放弃锁并发回源;太长(如 30s),用户明显卡顿 -
stale 回退兜底:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当首个请求回源出错、超时或正在更新时,后续请求可立即返回旧缓存,不卡顿也不穿透 -
延长缓存有效期:
proxy_cache_valid 200 302 30s;
MISS 越少,锁竞争越弱;静态资源可设为1h,API 接口建议至少 30 秒
验证是否真生效
别只看配置,要观测实际行为:
- 在 location 中加:
add_header X-Cache-Status $upstream_cache_status; - 用
curl -I发起两次紧邻请求:
首次应返回X-Cache-Status: MISS,第二个若返回HIT,说明锁成功复用结果;若仍是MISS,说明 key 不一致或配置未加载 - 压测验证:用
ab -n 20 -c 10并发请求同一 URL,开启 lock 后后端 access log 应只记录 1 条,而非 10 条

















