proxy_cache_lock 要真正防止并发重建,必须满足“锁得准、锁得住、退得快”三闭环:统一 cache key、正确定义缓存区并启用 lock、配合 stale 与 background update;通过 x-cache-status 和压测验证生效。

要让 proxy_cache_lock 在缓存失效时真正防止并发重建,不能只开一个开关,必须确保“锁得准、锁得住、退得快”三者闭环。它本质是:当多个请求同时命中一个已过期或未缓存的 key 时,Nginx 只放行第一个去回源,其余请求要么等待新缓存写入后直接返回,要么按策略退回旧内容——前提是整个链路配置无断点。
锁得准:所有请求必须落在同一个 cache key 上
锁按 key 绑定,key 不一致就等于没锁。默认 $request_uri 包含 query 参数,/api/order?id=123 和 /api/order?id=456 就是两个独立 key,锁完全无效。
- 对固定路径接口(如商品详情、订单查询),统一 key:
proxy_cache_key "$scheme$host:/api/order"; - 更通用做法:剥离所有 query 参数,只保留路径主体:
proxy_cache_key "$scheme$host$uri"; - 过滤前端随机参数(
?t=123456、?v=2.1)和易变 header(Authorization、Cookie、User-Agent) - 禁用干扰响应头:
proxy_ignore_headers Set-Cookie Vary;,否则带Set-Cookie的响应默认不缓存,lock 就无法介入
锁得住:三要素缺一不可
没有缓存区、没启用缓存、location 里没开 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;目录需存在且 Nginx 进程有读写权限 - 在目标
location中启用缓存:proxy_cache my_cache;
没这句,就没有 MISS,lock 就是摆设 - 在同一
location中开启 lock 并设超时:proxy_cache_lock on;<br>proxy_cache_lock_timeout 5s;
超时建议 3–8 秒:太短(如 1s)导致等待请求快速放弃锁,仍并发回源;太长(如 30s)用户明显卡顿
退得快:stale + background update 是保命组合
首个请求可能慢、失败或超时,不能让其余请求干等或全部穿透。
- 允许返回旧缓存(即使已过期):
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; - 开启后台静默更新(需配套
updating):proxy_cache_background_update on;
但必须确保proxy_cache_use_stale显式包含updating,否则后台子请求根本不会发起 - 为 404 等空响应也设有效期,防穿透:
proxy_cache_valid 404 10s;
验证是否真生效
上线后靠响应头快速确认:
- 加响应头便于观测:
add_header X-Cache-Status $upstream_cache_status;
看到HIT、MISS、STALE、UPDATING等状态,就能判断锁和 stale 是否走通 - 用压测工具模拟并发请求同一失效 key,观察后端日志是否只出现一次回源调用











