proxy_cache_lock 通过只放行首个缓存未命中请求回源、其余请求等待或返回旧缓存,缓解缓存击穿压力;需配合过期时间分散、多级缓存、限流等策略共同防雪崩。

nginx 的 proxy_cache_lock 是防止缓存失效时大量并发请求穿透到后端的关键机制,它本身不直接解决缓存雪崩,但能有效缓解“缓存击穿”引发的瞬时压力——这是雪崩链条中的重要一环。真正防雪崩需配合过期时间分散、多级缓存、限流等策略,而 proxy_cache_lock 负责在缓存未命中时,只放行一个请求去回源重建缓存,其余请求等待该结果返回后直接使用,避免多个相同请求同时打到后端。
proxy_cache_lock 的核心作用与触发条件
当多个请求同时访问一个尚未缓存(或已过期)的资源时,若启用 proxy_cache_lock,nginx 会锁定该缓存 key,仅让第一个请求进入 upstream 回源,其他请求阻塞等待(默认最多等待 proxy_cache_lock_timeout),待缓存写入成功后统一返回。这显著降低后端负载峰值。
- 仅对“缓存未命中且需回源”的请求生效;已有有效缓存时完全不触发
- 锁定粒度是 cache key,不是 URI 或参数组合,需确保 key 设计合理(如忽略无关 query 参数)
- 不保证绝对原子性:若上游响应慢或超时,锁可能提前释放,导致后续请求再次回源
基础配置写法与关键指令
必须在 location 或 server 块中启用,并搭配 proxy_cache 使用:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
proxy_cache my_cache; proxy_cache_valid 200 302 10m; proxy_cache_lock on; # 启用锁机制 proxy_cache_lock_timeout 5s; # 锁等待上限,超时后放弃等待直接回源 proxy_cache_lock_age 5s; # (可选)锁存在时间,避免旧锁长期占用 proxy_cache_use_stale updating; # 允许在更新缓存时返回旧内容,进一步降压
-
proxy_cache_lock_timeout建议设为略大于正常回源耗时(如 3–8 秒),太短易失效,太长影响用户体验 -
proxy_cache_use_stale updating很关键:当缓存正在被第一个请求更新时,其余请求可直接返回旧缓存,而非等待,极大减少阻塞 - 若后端支持 stale-while-revalidate(如通过 Cache-Control 头),可结合
proxy_cache_use_stale更精细控制
配合防雪崩的必要补充措施
proxy_cache_lock 单独无法抵御大规模缓存集中过期或 Redis 整体宕机这类典型雪崩场景,必须叠加以下手段:
-
分散过期时间:在生成缓存 key 时加入随机偏移,例如
cache_key "$scheme$request_method$host$request_uri|$arg_v";中对 TTL 加 ±60 秒抖动 - 主动预热 + 缓存永不过期 + 后台异步刷新:高频接口缓存设为 long max-age,靠后台任务定期更新,避免自然过期
- 多级缓存:Nginx 本地缓存(proxy_cache)+ Redis 分布式缓存 + 应用内本地缓存(Caffeine/Guava),逐层降级
-
兜底限流:在 upstream 不可用时,用
limit_req或 OpenResty 的 lua-resty-limit-traffic 控制最大回源请求数
验证是否生效的简单方法
可通过日志观察 proxy_cache_lock 行为:
- 开启
log_format包含$upstream_cache_status,命中缓存显示HIT,回源显示MISSEXPIRED或MISS - 当出现
LOCK状态,说明有请求被锁住等待;REVALIDATED表示使用了 stale 内容 - 对比开启前后后端 access log 的 QPS 波动,尤其在缓存批量失效窗口期

















