proxy_cache_lock 仅对同一缓存 key 的瞬时 MISS 请求串行化,首请求回源,其余等待;需配齐缓存区、启用缓存、location 中开启 lock,并统一 cache_key、忽略干扰头、过滤随机参数,配合 stale 回退与合理有效期才能有效缓解热点击穿。

proxy_cache_lock 不能“解决”缓存击穿,它只对同一缓存 key 的瞬时未命中(MISS)请求做串行化——放行第一个去回源,其余等待结果写入后直接读缓存。要让它在热点资源场景下真正起效,必须把锁“对准”真正的热点,同时堵住 key 分裂、超时放弃、无兜底等常见漏洞。
确保锁有地方落脚:基础三件套缺一不可
没缓存区,锁就是空转;没启用缓存,就压根没有 MISS;没在 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)后续会被引用,大小按每 1MB 支持约 8000 个 key 估算;use_temp_path=off 避免临时文件拷贝,提升一致性 - 在目标 location 块 中启用缓存:
proxy_cache my_cache; - 在同一 location 中开启锁并设合理超时:
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
超时建议 3–8 秒:太短,等待请求快速放弃锁并发回源;太长,用户明显卡顿
让锁真正锁住热点:统一 cache_key 是关键
锁只认 key,key 不一致 = 完全失效。热点接口(如 /api/product/123)常因参数、Header、Cookie 被拆成几十个 key,等于没锁:
- 剥离动态 query 参数:
proxy_cache_key "$scheme$host$uri";
这样/api/product/123?id=1和/api/product/123?from=app&t=1715556000都映射到同一个 key - 忽略干扰 Header 和 Cookie:
proxy_ignore_headers Set-Cookie Vary;
防止带Set-Cookie的响应被跳过缓存,也让 key 不受登录态影响 - 前端加的随机参数(如
?v=2.3.1或?t=1715556000)必须显式过滤,否则每个请求都是独立 key
不靠锁硬扛:加 stale 回退 + 合理有效期双保险
光等锁结果风险高——首个请求可能失败、超时或慢。stale 是降级安全阀,cache_valid 是源头减压器:
- 允许返回旧缓存应对异常:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当首个请求回源出错或超时,等待中的请求可立即返回 stale 缓存,不卡顿也不穿透 - 给热点 API 设最低保鲜期:
proxy_cache_valid 200 302 30s;
proxy_cache_valid 404 10s;
30 秒已足够缓解瞬时压力;静态资源可设为 1h 或更长
验证是否真生效:别信配置,看日志和响应头
配置写完不算数,必须观测实际行为:
- 在 location 中加响应标记:
add_header X-Cache-Status $upstream_cache_status; - 用
curl -I发两次紧邻请求:
首次应返回X-Cache-Status: MISS,第二个若返回HIT,说明锁成功阻塞并复用了结果;若仍是MISS,大概率是 key 不一致或配置未重载 - 压测验证后端负载:
用ab -n 20 -c 10 http://your-api/xxx并发请求同一 URL,检查后端 access log —— 开启 lock 后应仅记录 1 条访问,而不是 10 条











