收录入口多层缓存返回不同版本时怎样定位一致性问题

📍 WDQWDWQD987AAAAA:216.73.217.95
📱 Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
🔗 /1f61f5c4d3aa.html
📄

收录入口多层缓存返回不同版本时怎样定位一致性问题

先给结论:不要从“哪个版本正确”开始查,而要先确定同一请求在每一层缓存里被谁改写、以什么键存储。多层缓存返回不同版本,通常不是某一层坏了,而是缓存键、失效顺序或回源条件不一致。定位时用同一个 URL、同一组请求头、同一时刻逐层取样,比反复刷新页面更能区分原因。

先判断是缓存键不同,还是失效顺序不同

两种原因的表现很像,但处理方式相反。缓存键不同,意味着各层把请求看成不同对象;失效顺序不同,意味着各层看的是同一对象,只是清理时间不一致。

区分动作:固定 URL 和请求头,连续取样并记录每层返回的 ETag、Last-Modified、Age 或版本标识。如果标识随请求头变化,优先查缓存键;如果标识只随时间收敛,优先查失效顺序和 TTL。

用可核对的证据逐层取样

不要只看浏览器最终结果,那已经是多层叠加后的产物。按请求路径从外到内取样,每层记录三项:响应状态、内容版本标识、缓存命中提示。

  1. 先请求最外层,保存完整响应头。
  2. 绕过最外层,直接请求下一层,使用相同 URL 与请求头。
  3. 最后请求源站,确认源站当前返回的版本。

把三份响应头并排比较。若源站版本已更新而中间层仍旧,问题在中间层失效;若中间层已更新而最外层仍旧,问题在最外层失效或键设计。这个动作的结果直接决定下一步:是改失效通知,还是改缓存键。

两种条件下的不同选择

条件一:版本差异只在带 Cookie 或特定请求头时出现。此时应优先统一缓存键规则,而不是加大清理频率。因为清理只能暂时掩盖分叉,键不一致会让旧版本再次被写入。实施动作是列出各层参与键计算的字段,删掉不必要的维度,或让各层使用同一份键定义。结果是同一请求在各层映射到同一缓存对象,版本自然收敛。

条件二:版本差异与请求头无关,只与发布时间相关。此时应优先检查失效传播链路和 TTL 设置。实施动作是给发布流程加一步:内容更新后按由内到外的顺序触发失效,并记录每层确认时间。结果是能看出是哪一层延迟确认,而不是笼统地“清缓存”。

一个注明假设的短例子

假设某页面发布后,外层返回旧标题,中间层返回新标题,源站返回新标题。若外层缓存键包含 Accept-Language,而中间层不包含,那么带不同语言头的请求会命中不同对象。此时先统一键定义,再观察是否仍分叉;若统一后仍分叉,才转向失效顺序。这个例子只说明比较方法,不代表真实项目结果。

例外与容易误判的情况

有些差异并非缓存造成。源站本身按地域、设备或登录态返回不同内容时,各层只是如实缓存了不同变体。判断依据是:直接请求源站并改变相同条件,若源站也返回不同版本,问题在源站内容协商,不在缓存一致性。

另外,抓取限制、站点地图提交或协议层配置都不能单独证明缓存已一致。它们各自解决的是抓取或传输问题,与多层版本分叉不是同一回事。定位时把证据留在响应头和取样记录里,再决定改键、改失效还是改源站协商,下一步才不会反复。

图1 图2

nginx