fastcgi_cache_lock 通过限制并发回源缓解缓存穿透压力:仅首个请求回源,其余最多等待5秒获取新缓存或返回旧缓存(需启用fastcgi_cache_use_stale updating),避免后端被突发流量击穿。

fastcgi_cache_lock 的作用不是“解决”缓存穿透,而是控制穿透的并发量:当多个请求同时命中未缓存的 URL 时,只让第一个去后端,其余等待最多 5 秒,等缓存写入后统一返回。它不消除穿透,但把“炸锅式并发回源”变成“排队领缓存”。
它怎么缓解缓存穿透压力
- 多个相同 URL 请求进来(比如首页被刷屏),若都没缓存,不全打到 PHP-FPM,只放行一个
- 其余请求在 Nginx 层暂停,不发给后端,也不立即失败,而是等第一个结果落地
- 等待时间固定为 5 秒(硬编码,不可改),超时则各自回源——不是卡死,是自动放弃
这个机制对以下情况有效:
- 后端响应快(≤3 秒)
- 请求高度集中(大量重复 URL)
- 缓存 key 设计合理(不含随机参数、Cookie、变动 query)
- 响应头不干扰缓存(如已用
fastcgi_ignore_headers Set-Cookie Cache-Control)
必须配套的关键配置
光开 fastcgi_cache_lock on; 不够,容易适得其反:
fastcgi_read_timeout至少设为后端最长合理耗时
例如 PHP 接口平均 4 秒、P95 是 6 秒,那就设fastcgi_read_timeout 8s;否则第一个请求还没回来,Nginx 就中断连接,锁失效,后续请求全涌过去fastcgi_cache_valid要避免集中过期
比如fastcgi_cache_valid 200 10m;可配合业务逻辑加几秒随机偏移(如用$upstream_http_x_cache_ttl动态设 TTL),或用map对不同路径设不同过期时间fastcgi_cache_use_stale updating;必须启用
这样在锁生效期间,等待中的请求能直接返回旧缓存内容,而不是干等或失败——用户无感,后端零压力fastcgi_cache_key要收束一致
推荐:fastcgi_cache_key "$scheme$host$request_uri";
再加fastcgi_ignore_headers Set-Cookie;,防止带 Cookie 的请求导致 key 分裂
什么时候不该开 lock
- 后端有慢接口(如导出、搜索聚合),执行常超 5 秒
-
fastcgi_read_timeout设置过短(比如只设 3 秒),而实际 PHP 需 7 秒 - 请求 URL 带大量随机 query(如
?t=123456789)、或每个用户 Cookie 不同
此时开 lock 反而放大问题:第一个请求超时失败,所有等待者同步失败,还可能引发连接堆积、RST 断连
不复杂但容易忽略


















