proxy_cache_lock 仅对同一缓存 key 的并发 miss 请求串行化,首请求回源,其余等待;能否抗住数万连接取决于 key 一致性、缓存启用、共享内存区配置及 stale 回退策略。

proxy_cache_lock 本身不能“避免数万连接同时击穿回源”,它只在同一缓存 key 发生未命中(MISS)的瞬间,把并发请求串行化——仅放行第一个去后端,其余等待缓存写入后直接读取。面对数万连接,能否真正压住回源量,取决于你是否让这数万个请求落在同一个锁上,并配好退路和兜底策略。
必须先搭好缓存基础,否则 lock 完全不生效
proxy_cache_lock是个“依赖型”机制:没缓存区、没启用缓存、没触发 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:512m是关键,512MB 内存可支持约 400 万个缓存 key,足以覆盖常见热点接口。 - 确保
/var/cache/nginx/proxy_cache目录存在,且 Nginx 进程有读写权限(Linux/macOS 下注意 umask 或 SELinux)。
-
-
在目标
location中必须启用缓存:location /api/hot { proxy_cache my_cache; proxy_cache_lock on; # 其他配置... }没有
proxy_cache my_cache,proxy_cache_lock on就是摆设。
让数万请求真正共用一把锁,关键在 cache_key 的一致性
默认 key 是 $scheme$proxy_host$request_uri,只要 URL 参数、Header、Cookie 有一处不同,就生成新 key → 锁失效 → 数万请求变成数万个独立回源。
要让它们“挤进同一把锁”,必须主动收窄 key:
-
剥离所有干扰参数(最常用且稳妥):
proxy_cache_key "$scheme$host$uri";
这样
/api/hot?id=123和/api/hot?id=456都变成/api/hot,共用一个 key。 -
进一步排除前端随机参数(如
?t=1716942840、?v=2.4.1): 不靠$request_uri,改用更干净的组合:proxy_cache_key "$scheme$host:/api/hot";
-
过滤掉破坏一致性的响应头:
proxy_ignore_headers Set-Cookie Vary;
否则带
Set-Cookie的响应默认不缓存,lock 也就没机会介入。 避免把用户身份信息混入 key: 如果接口需登录态,但又想统一锁定(比如首页推荐),就别用
$http_cookie或$http_authorization做 key 组成部分。
设置合理超时与 stale 回退,防止“等不来”变“全崩”
锁只管“排队”,不管“排到哪”。数万连接若卡在锁里等 30 秒,既伤用户体验,也压垮后端。
-
proxy_cache_lock_timeout 5s;
推荐设为 3–8 秒:- 太短(如 1s)→ 等待请求快速超时,放弃锁,各自发起回源 → 击穿重现。
- 太长(如 30s)→ 用户明显卡顿,后端压力未减,只是延后爆发。
-
proxy_cache_use_stale是救命稻草:proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当首个请求回源失败、超时或正在更新时,后续请求不等、不重试、不穿透,直接返回旧缓存(stale),服务不中断。
-
同时延长缓存有效期,从源头减少 MISS:
proxy_cache_valid 200 302 30s; # API 类 # 或对静态资源:proxy_cache_valid 200 1h;
验证是否真起效:别信配置,看日志和响应头
-
加响应头方便观测:
add_header X-Cache-Status $upstream_cache_status;
用
curl -I请求:- 首次应为
X-Cache-Status: MISS - 紧随其后的并发请求若返回
HIT或LOCKING(Nginx ≥1.7.8),说明锁已介入; - 若仍是
MISS,说明 key 不一致或缓存被 bypass。
- 首次应为
-
压测验证最直观:
ab -n 1000 -c 200 http://your-domain.com/api/hot?id=123
开启 lock 后,检查后端 access log:理想情况是只看到 1 条回源记录(或略多几条,因 lock timeout 或 stale fallback),而不是 200 条。
不复杂但容易忽略











