proxy_cache_lock 仅对同一缓存 key 的瞬时 MISS 请求串行化,首请求回源,其余等待;需配齐 cache_path、proxy_cache、proxy_cache_lock 三件套,收窄 key、设 lock_timeout 和 stale 回退兜底,并通过 X-Cache-Status 与日志验证。

proxy_cache_lock 不能“防止”缓存击穿,它只对同一缓存 key 的瞬时未命中(MISS)请求做串行化:放行第一个去回源,其余等待结果写入后直接读缓存。要让它在高并发下真正起效,必须配齐基础、收窄 key、设好超时、加兜底策略。
基础三件套必须配齐
缺一不可,否则 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;use_temp_path=off 避免临时文件拷贝,提升一致性 - 确保 /var/cache/nginx/proxy_cache 目录存在,且 Nginx 进程有读写权限(注意 Linux/macOS 下 umask 或 SELinux 限制)
- 在目标 location 块 中启用缓存和锁:
proxy_cache my_cache;
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
没有 proxy_cache my_cache,proxy_cache_lock on 就是摆设
锁得住的前提:所有请求必须落在同一个 key 上
锁按 key 绑定,key 不一致 = 锁失效 = 并发回源照旧。常见干扰源和应对方式:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 默认 key 含 $request_uri,导致
/api/hot?id=1和/api/hot?id=2被视为两个独立 key → 改用:
proxy_cache_key "$scheme$host$uri";(剥离所有 query 参数) - 前端加随机参数(如
?t=1716942840、?v=2.4.1)会人为分裂 key → 更彻底收束:
proxy_cache_key "$scheme$host:/api/hot"; - Cookie 或认证 Header(如
Authorization、User-Agent)不同也会分裂 key → 配合:
proxy_ignore_headers Set-Cookie Vary;,并避免在 key 中引入$cookie_*或$http_*
等不起时要有退路
光靠锁硬等风险高——首个请求可能慢、失败或超时。必须搭配两层保险:
-
超时设合理:
proxy_cache_lock_timeout 3–8s;太短(如 1s),等待请求快速放弃锁并发回源;太长(如 30s),用户明显卡顿 -
stale 回退兜底:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当首个请求回源出错、超时或正在更新时,后续请求可立即返回旧缓存,不卡顿也不穿透 - 对空响应也缓存,防穿透:
proxy_cache_valid 404 10s;
验证是否真生效
别只看配置,要用实际观测确认:
- 在 location 中添加:
add_header X-Cache-Status $upstream_cache_status; - 用
curl -I查看响应头:首次请求应为 MISS,紧随其后的并发请求应出现 HIT(说明锁成功阻塞并复用结果)或仍为 MISS(说明 key 不一致或配置未生效) - 查后端访问日志:用
ab -n 20 -c 10并发压测同一 URL,开启 lock 后后端应仅记录 1 条访问,而非 10 条

















