关键在于用过期缓存兜底并后台静默刷新,需同时启用proxy_cache_lock on、proxy_cache_background_update on和proxy_cache_use_stale updating;cache key须稳定(如"$scheme$host$request_uri"),proxy_cache_valid必须配置以触发updating状态,并补充error/timeout/5xx等容错选项。

要让缓存失效时不卡顿、不堆积回源请求,关键不是“快回源”,而是“不等回源就响应”——用过期缓存兜底,后台悄悄刷新。这需要三者协同:锁住首个请求去更新、允许后续请求立刻取旧内容、确保后台真能静默拉新。
必须同时开启的三个核心指令
缺一不可,否则所谓“快速回源”只是假象:
- proxy_cache_lock on:同一缓存 key 的并发请求中,只放行第一个去回源,其余排队或直接走 stale;
- proxy_cache_background_update on:让那个被放行的请求在后台异步刷新,不阻塞响应流;
- proxy_cache_use_stale updating:配合前两者,明确告诉 Nginx——“正在更新中”时,允许返回过期缓存。
缓存键与过期时间要稳且准
key 不稳定,锁和后台更新就各刷各的;过期时间没设,Nginx 根本不知道什么叫“即将过期”:
- 统一 cache key,推荐:proxy_cache_key "$scheme$host$request_uri";(忽略 $args、$cookie 等易变参数);
- 必须配置 proxy_cache_valid,例如:proxy_cache_valid 200 302 30s; —— 没这行,updating 条件永远不触发;
- 避免用 if 块动态设有效期,改用 map 预定义变量,更安全高效。
容错兜底不能只写 updating
仅写 proxy_cache_use_stale updating 是脆弱的。真实环境里,后台刷新可能失败、超时、后端挂掉。应一并启用:
- proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
- 这样即使后台刷新失败,用户仍能拿到旧缓存,不会暴露 5xx 或长时间等待;
- 建议把 proxy_cache_lock_timeout 设为后端 P95 响应时间的 1.2–1.5 倍(如 4s),太短会漏锁,太长影响首屏。
验证是否真正生效
别只看配置,用实际响应确认:
- 加头:add_header X-Cache-Status $upstream_cache_status;
- 停掉后端,发请求:若返回极快且头中显示 X-Cache-Status: STALE,说明机制已跑通;
- 再恢复后端,观察后续请求是否自然变为 HIT,证明后台刷新成功写入。











