先别把“版本不一致”当成单一故障。对收录好的域名来说,更常见的实际情况是:CDN、反向代理、应用内缓存和浏览器缓存各自保存了同一页面的不同副本,而你的抽样恰好只命中了其中一层。要定位一致性问题,第一步不是清缓存,而是先固定一个页面、一个URL、一组请求头,逐层记录“谁返回了什么”,再判断差异来自缓存键、失效机制还是回源内容。
你手里的资料或页面不能直接拿来排查,必须先转成可执行对象。选一个已收录、更新过内容、且经过多层缓存的URL,准备同一台机器、同一网络环境、同一组请求头。每次请求都记录四件事:响应状态、Content-Length或正文摘要、ETag或Last-Modified、以及Age、X-Cache一类缓存标记(如果响应中存在)。
把同一URL连续请求三次,观察差异是否稳定:三次都不同,说明至少有一层在持续生成不同副本;只有一次不同,可能是边缘节点或本地缓存命中差异;换一个出口IP后结果变化,则要把网络路径纳入变量。这个动作的结果决定下一步:如果差异可复现,继续做逐层对比;如果不可复现,先怀疑抽样方式和缓存命中分布,而不是直接改配置。
多层缓存最容易被忽略的是缓存键。CDN可能按URL加查询字符串缓存,反向代理可能按URL加Host缓存,应用层可能按URL加语言或设备类型缓存。只要某一层的键比另一层多一个维度,就会出现“同一URL、不同版本”的现象。
可以按下面的顺序做一次假设性排查,数字只用于说明比较方法:
Accept-Language或User-Agent的请求,重复第2步,记为C。如果A等于B但不等于C,问题更可能出在缓存键维度或内容协商;如果A不等于B,说明回源内容本身就不一致,或者中间层在改写响应;如果A、B、C都相同,但你本地看到的仍是旧版本,那问题在更靠近浏览器的一端。这个判断结果直接决定你下一步该查缓存配置、查应用输出,还是查客户端。
很多一致性问题不是缓存没更新,而是更新只发生在一部分层。常见情况是:源站发布新内容后,CDN的某个边缘节点仍持有旧副本,反向代理已刷新,应用内缓存按固定间隔过期。此时你用不同出口IP请求,就会拿到不同版本,看起来像随机异常,实际是各层失效时间不一致。
判断这一点,可以观察响应中的Age和缓存标记是否随时间递减或跳变。如果旧版本的Age持续增大,说明它仍在被某层当作有效缓存返回;如果新版本出现后旧版本Age归零或消失,说明失效动作已经扩散。这里要注意:某个统计归零不能单独证明处理正确,它也可能是该层不再被命中、请求被转到其他节点或缓存被整体清空后的结果。需要结合多个出口IP和多次请求才能区分。
定位到具体层之后,动作才有意义。如果差异来自缓存键,优先核对各层对查询字符串、请求头和Cookie的处理是否一致,而不是先清空全部缓存;如果差异来自失效机制,先确认发布流程是否同时通知了所有层,再考虑缩短某层缓存时间或增加主动刷新;如果差异来自回源内容,缓存层只是放大了问题,应回到应用输出和发布流程。
对收录好的域名来说,还要注意一个边界:搜索引擎抓取到的版本和你本地看到的版本可能不同。robots.txt的抓取限制不等于可靠的索引移除,站点地图也不保证收录,这些机制不会替你解决缓存版本不一致。你能做的是保证同一URL在各层返回的正文和关键头部尽量一致,并让更新后的版本能被稳定请求到。
最后用一个可执行检查收尾:固定一个URL,连续三天、每天在不同时间段用两个出口IP各请求一次,记录正文摘要和缓存标记。如果三天内同一出口IP的结果稳定、不同出口IP之间出现差异,就继续按出口IP定位边缘节点;如果同一出口IP也开始漂移,就把排查重点移到失效机制和发布流程。这个记录方式不能保证问题立刻消失,但能让你在下次出现例外时,知道该从哪一层开始查。