先给有条件的结论:如果同一 URL 在不同网络、不同地区或登录状态下返回的 HTML 主体不同,优先怀疑 CDN 边缘缓存与源站应用缓存之间缺少统一的缓存键和失效链路,而不是先怀疑搜索引擎抓取异常。只有当你能用带唯一查询参数的请求稳定复现同一版本、且源站日志显示每次请求都到达应用层时,才应把排查重心转到抓取与索引侧。这个判断成立的前提是:你能够分别观测边缘节点响应与源站响应,并且知道缓存键由哪些请求头或参数构成。
多层缓存下版本不一致,最常见的原因是观测本身没有固定。浏览器可能命中本地磁盘缓存,CDN 可能按 Accept-Encoding、Cookie 或设备类型分流,源站又可能按登录态输出不同模板。要在这种环境里定位问题,第一步不是清缓存,而是固定一个观测点:选定一个 URL、一个 User-Agent、不带 Cookie 的请求方式,并在响应头里记录 Age、X-Cache、Via、ETag 这类字段(字段名取决于你的服务商,不保证都存在)。
实际操作是:对同一 URL 连续发起两次间隔很短的请求,一次直连源站,一次经过 CDN。比较两次响应的 ETag 与正文中一段稳定文本(例如主标题或一段固定说明)。如果直连源站两次一致、经过 CDN 两次不一致,说明分层之间至少有一层在按不同键缓存。这个动作的结果会直接决定下一步:差异出现在边缘层,就去核对缓存键与失效规则;差异在源站内部,就要查应用缓存与数据库读写分离的延迟。
面对多层缓存版本不一致,团队通常会在两条路里选:一条是统一各层缓存键并建立主动失效链路,另一条是大幅缩短 TTL、让版本差异尽快自愈。两者都成立,但适用条件不同。
判断依据可以看一个假设例子:假设某页每天更新两次,CDN TTL 为一天,反向代理 TTL 为一小时,应用缓存为十分钟。用户在更新后一小时内可能拿到三种版本。此时缩短 CDN TTL 到十分钟能减少窗口,但若更新触发点明确,改缓存键并主动失效更彻底。若更新触发点不明确、内容由多个来源拼装,缩短 TTL 反而是成本更低的过渡方案。
上面把版本差异归因于分层缓存,有一个明确的反例:源站对同一请求返回不同内容。常见诱因包括读写分离导致主从延迟、灰度发布让不同应用实例加载不同模板、以及依赖外部接口时超时降级输出旧数据。这种情况下,无论你怎么统一缓存键或缩短 TTL,边缘层只是如实缓存了源站给出的不同版本。
区分方法是看源站直连请求:连续多次直连同一 URL,如果正文关键段落或结构化数据本身就在变化,问题不在缓存层。另一个可区分证据是响应头中的生成时间或版本标识——如果它随请求变化而缓存头保持不变,说明变化发生在缓存之前。此时继续调整 CDN 配置不会解决问题,应转向应用发布与数据一致性排查。
定位完成后,动作应当与层对应,而不是全站重推。边缘层不一致,就核对缓存键包含哪些请求头、哪些查询参数被忽略,并确认失效接口是否覆盖了所有相关 URL 变体。源站不一致,就先固定应用实例或关闭灰度,观察版本是否收敛。只有在确认各层返回一致之后,才去考虑抓取与索引层面的问题,因为此时你才有稳定的版本可以作为对照。
还要注意一个容易误判的现象:抓取量或某类请求量归零,并不能单独证明缓存处理正确。它也可能来自抓取节奏调整、站点地图未被读取、或 robots.txt 限制了部分路径。robots.txt 的抓取限制不等于可靠的索引移除,站点地图也不保证收录。把缓存一致性问题和收录问题混在一起排查,会让两边的证据互相污染。先让同一 URL 在各层返回一致版本,再分别核查不同搜索引擎对抓取与索引的支持情况,这样每一步的结论才有可验证的基础。