Nginx 返回 STALE 后,上游 429 没有刷新缓存有效期
已有缓存过期后遇到429返回STALE,不会自动续有效期。按保留旧成功对象或缓存错误选择策略,后台更新只合并更新期间请求,不保证固定退避。
缓存新鲜时请求显示 HIT,过期后上游返回 429,客户端仍得到旧内容并显示 STALE;紧接着的请求又去访问已经限流的上游。配置了 proxy_cache_use_stale http_429,不等于收到 429 后会把旧缓存重新变成一段时间的 HIT。
这条指令允许在相应错误条件下使用已经过期的缓存。选择旧对象时,新的 429 不替换它,也不会因这次 STALE 把原对象的有效期续上。Nginx 1.30.5 的正式处理路径仍有这一行为,不能把单纯升级当作续期方案。
先确认缓存对象确实存在并已过期
用受控的公共资源观察同一缓存键的响应与上游访问记录。可以按下面的顺序核对,而不是只看客户端最终状态码:
先让上游成功返回允许缓存的内容,核对保存的对象及新鲜期。新鲜期内再次请求相同键,应观察 HIT,这次请求无需读取上游。
等对象过期后,让受控上游返回 429。已允许该 stale 条件时,客户端得到旧对象,状态为 STALE。
随后再请求同一键,旧对象仍然过期,仍可能访问上游。不能把前一次 STALE 当成已经进入新的 HIT 窗口。
还要核对 URI、身份隔离、Vary 和缓存键是否一致,确认业务响应真的是旧对象。这里的 429 是上游结果,客户端收到的可能仍是缓存中的 200。单凭客户端的 200 看不出发生了限流。
如果一直 MISS、根本没有对象,应先查缓存资格和 缺少有效期,那与已有对象过期后选用 STALE 不同。
同键保留旧成功响应与缓存新 429 是两种策略
希望短时间向客户端返回缓存的 429,可以按业务要求缓存这个错误响应,并撤掉与该策略冲突的 http_429 旧对象回退条件。缓存规则仍须考虑响应头和有效期,不能认为增加 proxy_cache_valid 429 60s 就会覆盖所有上游禁止缓存的要求。
代价是同一缓存键的新 429 会替换原来的成功对象,之后就没有那份旧 200 可供回退。不能在单个对象上同时要求“保存新 429 的有效期”和“继续保留原成功正文”。选择之前先明确,用户应看到有限期错误,还是在允许的陈旧范围内继续看到旧数据。
若必须保留成功对象,并对实际上游请求设定明确的重试间隔,需要另外设计有状态的退避或错误响应层。分别确认缓存键、用户隔离、错误持续时间和恢复探测,不能把一条 stale 指令描述成熔断器。
后台更新只合并正在进行的更新
对于允许使用旧公共数据的端点,可在现有策略中评估:
proxy_cache_background_update on;
proxy_cache_use_stale http_429 updating;
这是需合入已有对应 location 的片段,后台更新从 1.11.10 起提供。它允许客户端得到旧对象时启动后台更新,并允许其他请求在更新进行期间使用旧对象;修改时保留原来已批准的其他 stale 条件、认证、限流、缓存隔离与代理设置。
如果后台尝试很快返回 429,更新已经结束,稍后的请求仍可能启动新尝试。因此它能减少并发更新期间的重复访问,却不保证“每 60 秒只探测一次”,也不会自动续上旧对象 TTL。proxy_cache_lock 主要控制新缓存对象的填充,也不能当作所有过期重验证的固定退避间隔。
业务必须明确允许陈旧多久。直接指令的 stale 条件与响应头中的有限陈旧窗口有优先级区别,不能只在上游写一个时间就假设它限制了已有指令。需要有限陈旧时,核对所选策略和超出窗口后的实际行为,尤其不要把过期权限或私人响应当作公共旧数据继续服务。
用上游请求数量判断是否达到目的
先备份原配置,在对应本机配置和版本上验证,再按原部署流程加载。测试包含新鲜、过期、连续 429、更新进行中及上游恢复成功,记录同键请求的缓存状态、对象内容和上游调用时间。
成功标准应来自业务要求:旧内容是否在获准范围内、错误是否按期恢复、上游实际调用频率是否受控。减少客户端错误并不等于减少上游负载。
保留 Cache-Control、Set-Cookie 与身份隔离语义,不为了让示例显示 HIT 就忽略它们或共享认证错误。回退时恢复本次更新与 stale 策略,按原流程检查并加载;已存在的缓存对象不会因恢复配置自动全部删除,必要时沿用原有的精确失效流程,不清空共用缓存目录。


