nginx缓存锁核心是控制回源数量、防击穿且不显式阻塞用户,proxy_cache_lock仅在miss时生效,首请求回源加锁,其余等待;超时后仅放行一个再回源,需配合stale策略、key收敛与合理有效期才能生效。

高并发下 Nginx 缓存锁的核心目标不是“完全避免回源”,而是控制回源请求数量、防止缓存击穿,同时不让用户明显感知等待。关键不在加不加锁,而在锁怎么设、超时怎么配、配套策略怎么跟。
proxy_cache_lock 的真实作用机制
它只在缓存 MISS(未命中)时生效,且必须配合 proxy_cache_lock on 使用。当多个请求同时访问一个未缓存或已过期的资源:
- Nginx 放行第一个请求去后端取数据,并为该 cache key 加锁
- 其余请求进入等待队列,不直接回源
- 若首个请求在 proxy_cache_lock_timeout 内完成并写入缓存,所有等待请求直接读新缓存返回
- 若超时仍未完成,Nginx 放行一个等待请求去回源(不是全部),其余继续等待或按 stale 策略处理
proxy_cache_lock_timeout 的合理取值
这个值不是越长越好,也不是越短越安全,需结合后端响应稳定性动态设定:
- 后端平均响应 3–5 秒 → 设为 4–6 秒:覆盖绝大多数正常回源,避免无效排队
- 后端偶有慢查询或依赖外部服务(如第三方 API、数据库)→ 设为 6–8 秒:留出缓冲,减少二次穿透
- 绝对避免设为 0 或 1 秒:会导致大量请求几乎立刻放弃等待、并发回源,击穿风险反而升高
- 不建议超过 10 秒:用户端延迟显著,移动端易触发重试,可能引发雪崩式请求
必须同步启用的配套策略
单独调大 timeout 没有意义,必须与以下机制联动才能真正提升可用性:
-
启用 stale 策略:如
proxy_cache_use_stale updating error timeout http_502 http_503。当锁等待中首个请求尚未完成,但已有旧缓存(stale),Nginx 可直接返回旧内容,大幅降低用户等待感 -
收紧 cache key 粒度:确保相同业务语义的请求生成同一 key,例如统一忽略无意义 query 参数(
v=xxx),否则 lock 对不同 key 完全无效 -
设置合理缓存有效期:如
proxy_cache_valid 200 302 5m,减少 MISS 频次,从源头降低锁竞争概率
验证是否生效的实操方法
靠日志和响应头快速确认行为是否符合预期:
- 开启
add_header X-Cache "$upstream_cache_status";,观察并发请求响应头中是否出现 MISST(首个请求)、MISS(超时后第二个回源)、HIT(后续请求命中新缓存)的组合 - 检查后端 access log 中同一 URI 的请求频次:启用 lock 后,MISS 阶段应明显收敛为单个或极少量请求
- 用
wrk -t10 -c100 -d10s模拟并发压测未缓存路径,对比开启/关闭 lock + timeout 前后的后端请求数差异











