proxy_cache_lock 通过串行化同一缓存 key 的并发请求保护后端服务,需同时满足三项基础配置:定义缓存区(proxy_cache_path)、启用缓存(proxy_cache)、显式开启锁(proxy_cache_lock on);key 必须统一(如用 "$scheme$host$uri"),并配 stale 策略兜底。

proxy_cache_lock 不直接保护数据库,它保护的是后端应用服务(比如 API 网关、Web 服务),通过在 Nginx 代理层对同一缓存 key 的并发请求做串行化处理,把原本可能几十上百个并发回源的请求,压成“只放行一个”,其余排队等结果——从而间接大幅减少打到后端服务的请求数量,也自然减轻了后端服务对数据库的查询压力。
必须配齐的三项基础配置
缺一不可,否则 lock 完全不触发:
-
定义缓存区:在
http块中配置proxy_cache_path,例如: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可避免临时文件拷贝,提升锁状态一致性。 -
启用缓存:在目标
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);低于 3s 易超时并发,高于 8s 用户感知明显卡顿。
锁只对完全一致的 cache key 生效
key 不统一,等于多把锁并行,形同虚设。常见问题包括:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 默认 key 含
$args,导致/api/user?id=1001和/api/user?id=1002被视为两个独立 key; - 误将
$http_x_trace_id、$cookie_session或随机参数(如?t=1678901234)加入 key;
推荐做法:proxy_cache_key "$scheme$host$uri";(忽略全部 query 参数和干扰 header)
同时配合:proxy_ignore_headers Set-Cookie;
避免响应因含 Cookie 被跳过缓存。
必须配 stale 策略作为容错退路
不能让成百上千请求干等一个慢接口。关键配置是:
-
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
其中updating最重要:首个请求正在回源时,后续请求可立刻返回旧缓存(stale),用户无感,后端也不再承压; - 搭配
proxy_cache_valid减少 MISS 次数,例如:proxy_cache_valid 200 302 30s;(API 类接口)proxy_cache_valid 200 1h;(静态资源)
验证锁是否真实生效
靠日志和响应头确认,不靠猜测:
- 加响应头:
add_header X-Cache-Status $upstream_cache_status;
压测时观察是否出现MISSTIMEOUT(说明 timeout 太小)或连续多个MIS(说明 key 不统一或 cache 未启用); - 查 Nginx error log,搜索
cache lock timeout; - 比对后端访问日志:开启 lock 后,同一 URI 的回源请求数应显著收敛(如 100 并发下仅 1~2 次 MISS)。










