proxy_cache_lock仅实现同一cache key下miss请求的串行化回源,非原子操作;必须配齐缓存区定义、location启用proxy_cache、统一cache key三要素,否则不生效。

proxy_cache_lock 本身不保证“缓存更新的原子性”,它只实现同一 cache key 下并发未命中(MISS)请求的串行化回源——即首个请求去后端取新数据并写入缓存,其余请求暂停等待,等缓存写完后直接读取,避免大量重复回源。这不是传统意义上的原子操作(如数据库事务),而是一种轻量级的“锁住请求流”的协调机制。
必须配齐三个基础环节
缺一不可,否则 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 名称要和后续引用一致,use_temp_path=off 避免临时文件导致写入不一致
- 目标 location 中启用缓存:proxy_cache my_cache; ——没这句,Nginx 不走缓存流程,也就没有 MISS,lock 失效
- 在同一 location 中显式开启锁:proxy_cache_lock on; proxy_cache_lock_timeout 5s; ——超时建议设为后端 P95 响应时间的 1.2–1.5 倍(例如 P95 是 2.4s,设 3s)
cache key 必须严格统一
锁按 key 绑定,key 不一致 = 多个锁并行 = 并发回源照旧:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 默认 key 含 $args,
/api/user?id=1001和/api/user?id=1002就是两个 key → 改用 proxy_cache_key "$scheme$host$uri";(丢掉 query 参数) - 前端加的随机参数(如
?t=1718614290)、用户身份头($http_x_user_id)、Cookie 等都会分裂 key → 不要在 key 中引入 $cookie_* 或 $http_* 变量 - 响应带 Set-Cookie 或 Vary 头会跳过缓存 → 配合 proxy_ignore_headers Set-Cookie Vary;
等待不能硬扛,得有退路
首个请求若失败、超时或慢,其余请求不能干等或全部穿透:
- 允许返回过期缓存: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 才是治本
proxy_cache_lock 是“缓存失效时的兜底串行”,不是万能解药。高频 MISS 源头不控,锁再严也压不住压力:
- 延长有效缓存时间:proxy_cache_valid 200 302 60s;
- 对静态资源或低频变动接口,缓存时间可设为数分钟甚至小时级
- 结合业务预热、定时刷新或主动失效(如 purge),降低冷启动击穿概率










