如何通过proxy_cache_background_update缓解缓存过期瞬间导致的回源流量高峰问题?
- 内容介绍
- 文章标签
- 相关推荐
本文共计752个文字,预计阅读时间需要4分钟。
《简述以下原创内容开头,不要试图图解问题,不要啰嗦,不超过100个字。》
proxy_cache_background_update 的真实行为
它只做一件事:缓存过期后,立刻返回旧内容,同时在后台发一个新请求去刷新缓存。但这个“后台请求”是无节制的——只要有一个请求触发了过期判定,就发一次;1000 个并发请求命中同一个过期 key,就会并发发起 1000 次后台更新。
这不是“缓解压力”,这是“分散压力到上游”,而且是毫无收敛的分散。
- 它不判断当前是否已有同 key 的更新正在进行
- 它不等待、不排队、不合并
- 它和 proxy_cache_lock 完全无关,即使 lock 开着,background_update 仍会照常发请求(除非你显式禁用)
真正起作用的是 proxy_cache_lock + proxy_cache_use_stale updating
要让“过期后只允许一次回源”,必须靠 proxy_cache_lock 控制入口,再用 proxy_cache_use_stale updating 让其他请求有路可退。
-
proxy_cache_lock on:对同一proxy_cache_key,只放行第一个请求去 upstream,其余等待或走 stale -
proxy_cache_lock_timeout 2s:等太久会拖慢用户,设短些(比如 2 秒),超时后直接走 stale -
proxy_cache_lock_age 10s:上一次更新完成后的 10 秒内,禁止新锁竞争,避免刚刷完又被抢 -
proxy_cache_use_stale updating:配合 background_update,让没抢到锁或超时的请求,也能返回旧缓存
为什么 background_update 还值得开?
因为它保留了“用户零感知”的能力:用户请求不卡在锁里,也不因锁超时而看到错误,而是拿到可用的旧数据——前提是 proxy_cache_lock 已经把后台更新收敛到一次。
- 关掉
proxy_cache_background_update,用户就得等锁释放+响应返回,TTFB 明显升高 - 只开
proxy_cache_background_update不开proxy_cache_lock,上游瞬间被打穿,和没缓存一样 - 两者一起开,且配好 lock 参数,才能实现“用户快、上游稳、缓存鲜”
容易被忽略的关键点
很多人以为开了 proxy_cache_background_update on 就万事大吉,结果压测时上游 CPU 直接飙满——问题往往出在没意识到 background_update 和 lock 是两个独立开关,且 lock 必须显式开启并调参。
proxy_cache_lock_age 和 proxy_cache_lock_timeout 的数值需要根据业务响应时间权衡:设太短,锁释放太快,重复刷新;设太长,更新滞后,缓存陈旧期拉长。没有通用值,得看你的上游平均响应耗时再加一点余量。
本文共计752个文字,预计阅读时间需要4分钟。
《简述以下原创内容开头,不要试图图解问题,不要啰嗦,不超过100个字。》
proxy_cache_background_update 的真实行为
它只做一件事:缓存过期后,立刻返回旧内容,同时在后台发一个新请求去刷新缓存。但这个“后台请求”是无节制的——只要有一个请求触发了过期判定,就发一次;1000 个并发请求命中同一个过期 key,就会并发发起 1000 次后台更新。
这不是“缓解压力”,这是“分散压力到上游”,而且是毫无收敛的分散。
- 它不判断当前是否已有同 key 的更新正在进行
- 它不等待、不排队、不合并
- 它和 proxy_cache_lock 完全无关,即使 lock 开着,background_update 仍会照常发请求(除非你显式禁用)
真正起作用的是 proxy_cache_lock + proxy_cache_use_stale updating
要让“过期后只允许一次回源”,必须靠 proxy_cache_lock 控制入口,再用 proxy_cache_use_stale updating 让其他请求有路可退。
-
proxy_cache_lock on:对同一proxy_cache_key,只放行第一个请求去 upstream,其余等待或走 stale -
proxy_cache_lock_timeout 2s:等太久会拖慢用户,设短些(比如 2 秒),超时后直接走 stale -
proxy_cache_lock_age 10s:上一次更新完成后的 10 秒内,禁止新锁竞争,避免刚刷完又被抢 -
proxy_cache_use_stale updating:配合 background_update,让没抢到锁或超时的请求,也能返回旧缓存
为什么 background_update 还值得开?
因为它保留了“用户零感知”的能力:用户请求不卡在锁里,也不因锁超时而看到错误,而是拿到可用的旧数据——前提是 proxy_cache_lock 已经把后台更新收敛到一次。
- 关掉
proxy_cache_background_update,用户就得等锁释放+响应返回,TTFB 明显升高 - 只开
proxy_cache_background_update不开proxy_cache_lock,上游瞬间被打穿,和没缓存一样 - 两者一起开,且配好 lock 参数,才能实现“用户快、上游稳、缓存鲜”
容易被忽略的关键点
很多人以为开了 proxy_cache_background_update on 就万事大吉,结果压测时上游 CPU 直接飙满——问题往往出在没意识到 background_update 和 lock 是两个独立开关,且 lock 必须显式开启并调参。
proxy_cache_lock_age 和 proxy_cache_lock_timeout 的数值需要根据业务响应时间权衡:设太短,锁释放太快,重复刷新;设太长,更新滞后,缓存陈旧期拉长。没有通用值,得看你的上游平均响应耗时再加一点余量。

