先给结论:不要从最外层缓存开始逐层清,而要先固定一个可重复的请求标识,再对比每一层返回的实体标签、修改时间和响应头,找出第一处分叉。分叉点之前的层可以保留,分叉点之后的层需要改写键或退出缓存,直到各层对同一标识返回同一版本。
多层缓存下出现不同版本,通常不是某一层坏了,而是各层用了不同的缓存键。CDN 可能按完整 URL 加查询串缓存,反向代理可能忽略查询串,应用层缓存可能只认商品 ID。三者对同一个页面给出不同快照,于是你看到的是版本不一致,而不是缓存失效。
定位动作:给目标 URL 加一个不会命中已有缓存的测试参数,例如 ?cache_probe=1,然后依次请求 CDN 边缘、反向代理回源地址和应用层缓存接口,记录每层返回的 ETag、Last-Modified 和响应体中的版本标记。第一处与源站不一致的层,就是分叉点。
这个动作的结果决定下一步:如果分叉点在 CDN,问题多半是缓存键太粗或刷新未传播;如果分叉点在应用层,问题多半是源数据写入后没有失效对应键。两种原因的修复方向完全不同,先清全部缓存只会暂时掩盖分叉点。
找到分叉点后,处理方式不是只有清缓存一种。可以按下面的条件选择:
判断依据不是哪层更先进,而是这一层能否在数据变更时被可靠失效。能失效就保留,需要不同粒度就改写,不能失效就退出。
清完缓存不等于一致。需要重新发一轮带相同测试参数的请求,确认各层返回的版本标记相同,并且该标记与源站当前版本一致。如果仍然不同,说明还有一层没有参与刷新,或者刷新顺序有误。
假设一个场景:源站数据版本从 v1 更新到 v2,应用层已返回 v2,但 CDN 仍返回 v1。此时先检查 CDN 的刷新任务是否成功,再检查回源请求是否带上了会绕过中间缓存的头。若回源请求仍被中间层缓存拦截,CDN 拿到的还是 v1,刷新自然不会生效。这个例子只用于说明比较方法,不代表任何真实平台行为。
验证通过后,把测试参数从正式 URL 中移除,并确认移除后各层仍返回同一版本。若移除后再次分叉,说明缓存键设计仍有问题,需要回到改写或退出方案。
抓取量下降、某个查询返回空、或某一层日志不再报错,都不能单独证明一致性问题已修复。抓取量下降可能是抓取预算调整或站点地图变更;返回空可能是请求被限流;日志不报错可能只是错误被上层吞掉。要证明修复有效,必须回到同一请求标识下各层版本标记一致这一条证据。
另外,robots.txt 的抓取限制不等于可靠的索引移除,站点地图也不保证收录。这些手段解决的是抓取和发现,不解决多层缓存返回不同版本的问题。若页面同时存在收录异常,应把缓存一致性作为独立问题先处理,再判断收录表现。
每次出现版本不一致时,按同一顺序执行:固定请求标识,逐层记录版本标记,定位第一处分叉,按保留、改写或退出选择处理方式,再复验各层标记。这样做的结果不是一次清缓存,而是让下一次同类问题能直接落到具体层,而不是重新猜测。
如果分叉点反复出现在同一层,说明该层的缓存键或失效机制需要长期调整,而不是继续临时刷新。此时应把该层的键设计和失效条件写成配置约束,避免后续改动再次引入不同版本。