fastcgi_cache_lock本身不造成请求堆积,它仅让并发未命中请求排队等待5秒(硬编码上限),超时后自动放弃并各自回源;真正引发堆积的是后端慢、fastcgi_read_timeout过短、客户端重试三者叠加。

fastcgi_cache_lock 本身不造成请求堆积,它只是让并发未命中请求“排队等缓存”,但这个等待有硬性上限(5秒),超时后自动放弃并各自回源。真正引发堆积的,是后端慢、超时短、重试多这三者叠加的结果。
为什么开启 lock 反而看起来更卡?
这不是 lock 在“锁住”连接,而是以下组合导致用户感知延迟升高:
- PHP-FPM 执行缓慢(如数据库查询慢、外部 API 响应长),实际耗时超过 5 秒
- fastcgi_read_timeout 设置过短(比如只设 8 秒),第一个请求还没返回,Nginx 就中断连接
- 客户端(浏览器或 App)启用 keepalive 并自动重试,失败请求反复复用连接,导致 worker_connections 逐渐耗尽
- 缓存 key 设计不合理(例如含随机参数或 Set-Cookie),使 lock 无法复用,大量请求各自触发回源
关键配置必须对齐
单独开 fastcgi_cache_lock on 没用,必须同步调优三项:
- fastcgi_read_timeout ≥ 后端 P95 耗时:比如 PHP 报表平均需 18 秒,这里至少设为 25 秒,避免 Nginx 主动断连
- fastcgi_cache_valid 按业务分层设 TTL:首页/列表页设 15m,搜索页设 60s,避免大量缓存同时过期引发雪崩
- fastcgi_cache_use_stale updating:让等待中的请求能直接返回旧缓存,而不是干等或失败;配合 background update 更稳
什么情况下该关掉 lock?
当存在明确的慢接口(导出、聚合搜索、实时计算类)且无法缩短响应时间时,关闭 lock 是更安全的选择:
- 关掉:
fastcgi_cache_lock off; - 转而用
fastcgi_cache_use_stale error timeout http_500 http_503;提供降级能力 - 对慢接口路径单独禁用缓存:
fastcgi_cache_bypass $is_slow_path;,避免干扰主站缓存策略 - 用 CDN 或后端 Redis 缓存替代,实现更细粒度控制
验证是否生效的实用方法
别只看配置,用真实响应头确认行为:
- 加响应头:
add_header X-Cache-Status $upstream_cache_status;和add_header X-Cache-Lock $upstream_cache_lock; - 压测时观察:MISS 后是否出现多个 STALE(说明 updating 生效)、是否有 EXPIRED(说明 inactive 清理正常)
- 检查缓存目录文件时间戳,确认不同状态码的缓存是否按预期存续











