fastcgi_cache_lock on 的作用是缓存未命中时仅允许首个请求回源,其余请求阻塞等待最多5秒后复用新缓存;需配齐缓存区定义、启用缓存与锁、统一cache key三项基础配置才生效。

fastcgi_cache_lock on 的作用不是直接“防止并发连接突增”,而是精准控制缓存未命中时的请求行为:当多个请求同时访问一个尚未缓存或已过期的 URL,它让仅第一个请求穿透到 PHP-FPM 执行,其余请求在 Nginx 层阻塞等待最多 5 秒,等缓存写入后统一返回结果。这能显著降低后端瞬时并发压力,但前提是配置协同、超时合理、key 统一。
必须配齐的三项基础配置
缺一不可,否则 fastcgi_cache_lock 完全不生效:
- 在
http块中正确定义缓存区:fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=phpcache:100m max_size=1g inactive=30m use_temp_path=off;
keys_zone名称(如phpcache)需与后续引用一致;use_temp_path=off避免临时文件拷贝,提升一致性。 - 确保缓存目录存在且权限正确:
mkdir -p /var/cache/nginx/fastcgi && chown www-data:www-data /var/cache/nginx/fastcgi
- 在
location ~ \.php$中启用缓存和锁:fastcgi_cache phpcache; # 必须有,否则无 MISS,锁无意义 fastcgi_cache_lock on; # 开启串行化 fastcgi_cache_lock_timeout 5s; # 虽然实际等待上限固定为 5 秒(源码硬编码),该指令仍建议显式设置
缓存 key 必须统一,否则锁失效
锁按 key 绑定,key 不一致 = 多个独立锁 = 并发回源照旧:
- 避免含易变参数:默认
$scheme$host$request_uri会把/api/user?id=1和/api/user?id=2当作不同 key。 - 推荐精简 key:
fastcgi_cache_key "$scheme$host$uri"; # 忽略 query string
- 过滤干扰头:
fastcgi_ignore_headers Set-Cookie Vary; # 防止因 Cookie 或 Vary 导致缓存跳过或分裂
关键协同参数必须对齐
单开 fastcgi_cache_lock 不足以稳住高并发:
-
fastcgi_read_timeout至少比 PHP 最长合理耗时多 5 秒:
若导出接口平均耗时 18 秒,设为25s;设成5s会导致首个请求未返回就被中断,锁释放失败,后续请求全部穿透。 -
fastcgi_cache_valid避免集中过期:
对主页/列表页用fastcgi_cache_valid 200 15m;,配合业务层加随机 TTL 偏移,或用map按路径分层设不同有效期。 -
fastcgi_cache_use_stale updating必须开启:
让等待中的请求在锁生效期间可返回旧缓存,而不是干等或失败——这是降低用户感知延迟的关键兜底。
效果验证方式
加响应头便于调试:
add_header X-Cache-Status $upstream_cache_status; add_header X-Cache-Lock $upstream_cache_lock;
观察日志或浏览器开发者工具:
-
HIT+MISS减少 → 缓存命中率上升; -
UPDATING状态频繁出现 → 锁正在起作用; -
MISS请求量不再随并发线性增长 → 后端压力被有效收敛。
不复杂但容易忽略











