proxy_cache_lock的核心价值是保一致,即确保同一缓存key的并发miss请求仅首请求回源、其余排队等待,从而避免后端雪崩与响应不一致;其生效必须满足四条件:定义缓存区、启用proxy_cache、统一cache key、显式开启lock并设合理timeout与stale退路。

proxy_cache_lock 的核心价值不是“加速”,而是“保一致”——它确保同一缓存 key 下的并发请求不会因缓存未命中(MISS)而全部打到后端,从而避免数据写入冲突、响应不一致或后端雪崩。但它本身不自动生效,必须精准配置才能真正提升读写一致性。
缓存上下文是锁的前提
没有缓存区定义和启用,lock 就无从谈起。Nginx 不会为未配置缓存的 location 启动任何缓存流程,更不会判断 MISS 或尝试加锁。
- 在 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)需与后续引用完全一致;use_temp_path=off 可避免临时文件写入导致的缓存状态不一致
- 确保目录存在且 Nginx 进程有读写权限:
mkdir -p /var/cache/nginx/proxy_cache && chown www-data:www-data /var/cache/nginx/proxy_cache - 在目标 location 块中启用缓存:
proxy_cache my_cache;
key 必须严格统一,否则锁形同虚设
锁按 cache key 绑定。只要两个请求生成的 key 不同,Nginx 就认为它们是不同资源,各自独立走 MISS 流程——并发回源照旧,一致性无从谈起。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 默认 key(如 $scheme$host$request_uri)会把 /api/user?id=1 和 /api/user?id=2 当作两个 key → 改用:
proxy_cache_key "$scheme$host$uri";(丢弃所有 query 参数) - 前端埋点参数(?t=1716942840、?v=2.4.1)或用户标识头(Authorization、X-User-ID)也会分裂 key → 不要在 key 中引入 $http_*、$cookie_* 等动态变量
- 配合:
proxy_ignore_headers Set-Cookie Vary;
防止后端响应带 Set-Cookie 导致缓存被跳过,破坏写入一致性
锁行为需可控:超时 + 退路缺一不可
只开 proxy_cache_lock on 而不设 timeout,或不配 stale 回退,极易引发阻塞或穿透——首个请求慢或失败时,其余请求要么卡死,要么集体放弃锁并回源。
- 设置合理等待上限:
proxy_cache_lock_timeout 5s;
建议值为后端 P95 响应时间的 1.2–1.5 倍(例如 P95 是 2.4s,则设 3s) - 必须搭配 stale 容错:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当首个请求出错、超时或正在更新时,后续请求可立即返回旧缓存,既不卡顿也不击穿 - 延长有效缓存时间(减少 MISS 频次):
proxy_cache_valid 200 302 30s;
验证是否真正生效
仅看配置不够,要确认 lock 是否实际介入了请求处理链路。
- 在 location 中添加响应头便于观测:
add_header X-Cache-Status $upstream_cache_status; - 发起并发请求(如 ab -n 100 -c 50),观察响应头:
• MISS 表示首次请求回源
• HIT 表示已缓存命中
• EXPIRED + LOCKING(或类似标记)表示排队等待锁释放(需结合日志或 debug 日志确认) - 检查 error.log 是否出现 “lock failed”、“lock timeout” 等提示,用于调优 timeout 值










