先确认一件事:多层缓存返回不同版本,通常不是“某一层坏了”,而是各层对同一个请求的缓存键、过期时间或变体判断不一致。定位时不要从最外层开始清缓存,而要先固定一个可复现的URL和请求头,逐层比对响应,找出第一处版本分歧发生在哪一层。下面的情境是假设,用来演示决策顺序,不是真实项目记录。
假设一个站点使用wordpress主机,前面有CDN,主机内部有页面缓存插件,PHP层还有对象缓存。编辑更新了一篇旧文章后,未登录访客看到新标题,登录用户看到旧标题,移动端则偶尔出现两者交替。此时“清一次缓存”可能让现象暂时消失,却不能说明根因,因为三层里任意一层的键不同,都会制造同样的表象。
第一步动作是构造一个最小对照:同一条URL,分别用无Cookie、带登录Cookie、带移动端User-Agent三种请求各取一次响应,记录状态码、正文中的版本标记和响应头里能看到的缓存线索。这个动作的结果会直接决定下一步:如果三种请求在三层都返回同一版本,说明问题在变体识别之外,应转向检查是否有多个源站或旧系统仍在响应。
多层缓存不一致,常见原因可以归为三类,判断依据不同:
区分这三类很重要,因为处理动作完全不同。键不同要统一键规则,过期不同要对齐失效触发,变体不同要明确哪些维度必须参与缓存判断。若把变体问题当成过期问题反复清缓存,现象会反复出现,且每次“恢复”都只是巧合。
在假设情境中,可用的手段是逐层绕过:先直接请求源站,确认源站本身返回的是新版本;再请求主机内部页面缓存层;最后请求CDN。每一层都记录同一URL的正文版本标记。哪一层开始出现旧版本,分歧点就在该层或其上游。
这里有一个容易误判的地方:如果源站返回新版本,而CDN返回旧版本,并不自动等于CDN配置错误,也可能是主机内部页面缓存先返回了旧版本,CDN只是忠实缓存了它。因此顺序应当是从内到外,而不是从外到内。先确认最靠近应用的一层输出正确,再向外检查。
另一个实际动作是给旧内容加一个可核验的版本标记,例如在正文中写入一个只用于排查的短字符串,并确保它随内容更新而变化。这样每次比对不必依赖肉眼判断标题差异,减少把“看起来一样”当成“版本一致”的错误。该动作的结果是让后续每一步都能用同一证据判断,避免在不同层使用不同标准。
当旧内容、旧系统或旧合作关系需要退出,但仍保留部分有价值内容时,一致性问题的处理重点会变化。此时不是让所有层都返回最新版本,而是明确哪些URL应当返回新版本、哪些应当返回重定向或不再提供内容。若只更新了内容层,却没有让各缓存层的失效规则覆盖这些URL,就会出现部分层仍提供旧内容的情况。
可执行的判断方法是列出一组代表性URL,分别覆盖:已更新但仍保留的内容、已下线并重定向的内容、已下线且不再提供的内容。对每一类,在源站、主机缓存层和CDN各验证一次响应状态和版本。只有三类都符合预期,才说明退出处理在各层生效。
需要说明的是,robots.txt的抓取限制不等于可靠的索引移除,站点地图也不保证收录。缓存一致性和搜索索引是两件事:前者影响访客和爬虫当下拿到的响应,后者取决于搜索引擎各自的处理。若旧内容退出同时涉及索引,应把缓存验证和索引核查分开进行,不要用缓存已更新推断索引已更新。
当三层返回一致,先不要立即宣布问题解决。应再做一次带时间间隔的复查:在内容更新后的一个缓存周期内,用相同请求组合再取一次响应。如果此时又出现旧版本,说明失效触发没有覆盖全部层,或者某一层的过期时间晚于预期,需要回到键与失效规则上继续查。
如果复查稳定一致,下一步是把这次使用的请求组合和版本标记保留为常规检查项,用于后续内容更新或旧内容退出时快速比对。这样做的价值不在于预防所有缓存问题,而在于把“多层返回不同版本”从随机现象变成可重复定位的流程。至此,判断依据已经足够支撑下一步决策:是继续调整某一层的键规则,还是确认退出处理已经完成。