仅配置 proxy_cache_use_stale updating 无效,必须同时启用 proxy_cache_background_update on 和 proxy_cache_lock on;否则缓存过期时仍会引发请求风暴,导致大量回源和上游负载激增。

proxy_cache_use_stale updating 本身不能消除请求风暴,必须配合 proxy_cache_background_update 和 proxy_cache_lock 才能真正起效。
为什么只配 updating 没用
单纯在 proxy_cache_use_stale 中加上 updating,只是告诉 Nginx:“当缓存正在被后台更新时,允许返回旧缓存”。但如果没有启用后台更新机制,Nginx 根本不会触发“updating”状态——它只会按默认逻辑:缓存一过期,所有并发请求全部穿透回源。
常见错误现象是:明明写了 proxy_cache_use_stale updating;,一到缓存过期时间点,日志里仍看到大量 MISS 或 EXPIRED,上游 CPU 瞬间拉满。
- 必须显式开启
proxy_cache_background_update on;,否则updating条件永远不满足 -
proxy_cache_background_update只在缓存即将过期(由proxy_cache_valid定义)且有请求命中时才触发子请求,不是定时刷 - 若缓存已彻底过期(
inactive超时被清理),后台更新也不会启动——此时连“旧缓存”都没得用
proxy_cache_background_update 的实际行为边界
这个指令不是“后台定时刷新”,而是“懒加载式预热”:只有用户请求撞上“即将过期”的缓存(比如 proxy_cache_valid 200 10m;,而当前缓存已存 9m50s),Nginx 才会悄悄发一个子请求去更新,同时把旧缓存立刻返回给用户。
关键限制点:
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
- 子请求使用的是同一个
proxy_cache_key,但不会继承原始请求的 header(如Cookie、Authorization),所以要确保后端能接受无认证/无 Cookie 的刷新请求 - 子请求失败(如超时、5xx)不会影响主响应,但后续再无后台重试机制;需靠
proxy_cache_use_stale error timeout http_500;补位 - 子请求不计入
limit_req或limit_conn限流,可能绕过你设的回源保护——建议单独用proxy_cache_lock控制并发更新数
必须配套的三项配置
缺一不可,漏掉任意一项都会让 updating 形同虚设:
-
proxy_cache_lock on;:防止多个请求同时触发后台更新。否则即使开了background_update,也可能出现 10 个请求一起撞上临界点,Nginx 启动 10 个子请求刷同一资源 -
proxy_cache_lock_timeout 3s;:设定等待锁的上限,避免长尾请求卡死;配合proxy_cache_lock_age 5s;允许超时后放行第二个更新请求(防止单点卡死导致长期 stale) -
proxy_cache_valid 200 302 10m;:必须设明确过期时间。“过期”是触发updating的前提;如果只写any 1m却没覆盖 200,那 200 响应根本不会进缓存,更谈不上更新
验证是否真生效的三个信号
别只看日志有没有 UPDATING,重点观察这三个现场指标:
- 用
add_header X-Cache-Status "$upstream_cache_status";,正常流程应看到连续请求返回HIT→STALE(首次过期)→HIT(后台更新完成),而不是反复MISS - 监控
proxy_cache_miss计数器:在缓存过期窗口内,该值应接近 0;若持续上涨,说明background_update未触发或失败 - 检查磁盘缓存文件修改时间:
find /var/nginx/cache -name "*$(echo -n "https://example.com/path" | md5sum | cut -d' ' -f1)*" -ls 2>/dev/null,应能看到同一 key 的文件 mtime 在后台更新后被刷新
最易忽略的是:后台更新依赖原始缓存项未被 inactive 清理。如果你设了 inactive=1m 却让内容缓存 10 分钟,那 1 分钟后缓存文件就被删了,updating 根本无从谈起。










