proxy_cache_lock不能防止缓存击穿,仅对同一cache key的并发miss请求串行化:首请求回源,其余等待后读缓存;需围绕“锁得准、锁得住、退得快、源头少”四点配置,包括统一cache_key、定义keys_zone、启用proxy_cache和proxy_cache_lock、设合理timeout及stale策略。

proxy_cache_lock 不能“防止”缓存击穿,它只对同一缓存 key 的并发未命中(MISS)请求做串行化:放行第一个回源,其余等待结果写入后直接读缓存。要让它在高并发下真正起效,必须围绕“锁得准、锁得住、退得快、源头少”四点系统配置。
锁得准:所有请求必须落在同一个 cache key 上
锁按 key 绑定,key 不一致就等于没锁。默认 key 含 $request_uri,/api/hot?id=1 和 /api/hot?id=2 就是两个独立 key,数万请求会变成数万个回源。
- 对固定路径热点接口(如商品详情),统一 key:
proxy_cache_key "$scheme$host:/api/product"; - 更通用做法是剥离 query 参数:
proxy_cache_key "$scheme$host$uri";(丢掉 $args) - 过滤前端随机参数(?t=1716942840、?v=2.4.1)和易变 header(Authorization、User-Agent、Cookie)
- 配合
proxy_ignore_headers Set-Cookie Vary;,避免响应因含 Set-Cookie 被跳过缓存
锁得住:三要素缺一不可
没有缓存区、没启用缓存、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 进程有读写权限:
mkdir -p /var/cache/nginx/proxy_cache && chown www:www /var/cache/nginx/proxy_cache - 在目标 location 中必须启用缓存:
proxy_cache my_cache;
没这句,就没有 MISS,lock 就是摆设 - 在同一 location 中开启 lock:
proxy_cache_lock on;proxy_cache_lock_timeout 5s;
超时建议 3–8 秒:太短易放弃,太长用户卡顿
退得快:stale 是保命配置
首个请求若慢、失败或超时,不能让其余请求干等或全部穿透。
- 允许返回旧缓存(即使已过期):
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; - 可选后台静默更新:
proxy_cache_background_update on; - 对空响应也缓存,防穿透:
proxy_cache_valid 404 10s;
源头少:减少 MISS 才是治本
MISS 越少,锁竞争越弱,系统压力越小。
- 为热点接口设置合理有效期:
proxy_cache_valid 200 302 5m; - 静态资源可设数小时,API 接口建议至少 30 秒
- 检查是否误配了
proxy_no_cache、proxy_cache_bypass,或响应头含 Cache-Control: no-cache、Set-Cookie - 用
add_header X-Cache-Status $upstream_cache_status;验证行为:压测中看到大量 MISS 后紧跟 HIT,且并发请求日志时间戳高度集中,说明 lock 起作用











