FastCGI缓存惰性更新是缓存过期后由首个请求异步重建、其余请求继续返回旧内容的机制,需配置fastcgi_cache_use_stale updating、fastcgi_cache_background_update on和fastcgi_cache_lock on三者协同实现。

FastCGI 缓存的惰性更新(lazy expiration)不是“自动刷新”,而是“缓存过期后不立即重建,而是由下一个请求触发重建、同时将旧缓存继续返回给后续请求”。这个机制能有效避免高并发下多个请求同时击穿缓存、排队等待 PHP-FPM 生成新内容的问题——也就是常说的“缓存雪崩+请求阻塞”。
理解惰性更新如何解决排队
默认情况下,当 fastcgi_cache_valid 设定的缓存时间一到,Nginx 就会认为该缓存条目失效。如果此时有 100 个用户同时访问同一个动态页面(比如商品详情页),而 PHP-FPM 只有 20 个 worker,那么前 20 个请求会进入 PHP 处理,剩下 80 个只能排队等待,造成首字节延迟飙升和连接堆积。
启用惰性更新后,缓存过期只是“标记为待更新”,Nginx 仍用旧内容响应所有请求;仅由第一个到达的请求异步触发后台更新(通过 fastcgi_cache_use_stale updating + 后台更新机制配合实现),其余请求完全不受影响。
必须启用的三项关键配置
惰性更新不是默认开启的,需显式组合以下指令:
- fastcgi_cache_use_stale updating:允许在缓存正在被后台更新时,继续使用陈旧缓存响应请求
- fastcgi_cache_background_update on:启用后台更新模式——即过期后由一个请求发起重建,其他请求照常读旧缓存
- fastcgi_cache_lock on(可选但推荐):防止多个请求同时触发重建;只让第一个请求去生成新缓存,其余全部回源旧内容
完整 location 示例(含防排队保护)
以下配置适用于 PHP 动态接口或文章页等易受并发冲击的场景:
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
<pre class="brush:php;toolbar:false;"># 缓存基础设置
fastcgi_cache PHP_CACHE;
fastcgi_cache_valid 200 301 302 5m; # 基础缓存5分钟
fastcgi_cache_min_uses 2; # 至少被访问2次才进缓存(防爬虫刷)
# 惰性更新核心三件套
fastcgi_cache_use_stale updating error timeout invalid_header http_500;
fastcgi_cache_background_update on;
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 5s; # 锁超时,避免卡死
# 可选:对高价值页面延长逻辑过期(配合后端Cache-Control)
add_header X-Cache-Status $upstream_cache_status;}
搭配后端控制效果更稳
单靠 Nginx 层的惰性更新还不够,建议 PHP 脚本中也做轻量协同:
- 返回 Cache-Control: public, max-age=300, stale-while-revalidate=60,明确告诉 Nginx “允许过期后60秒内走stale”
- 避免在脚本里输出 no-cache 或 private,否则 fastcgi_cache 直接跳过缓存
- 对用户登录态等个性化内容,用 fastcgi_cache_bypass 和 fastcgi_no_cache 精准排除,别让整个缓存策略失效

















