先做一件事:把“谁在什么条件下看到哪个版本”变成可核对的记录,而不是继续争论哪一层缓存有问题。二级域名设置本身往往只决定请求落到哪个源站或应用实例,真正让同一事实出现多个版本的原因,通常分散在浏览器缓存、CDN边缘节点、反向代理和应用内存缓存里。下面用一个假设情境说明如何把分歧转成可以逐项核对的项目。
假设这样一个情境:static.example.com 和 www.example.com 都指向同一套内容服务,运营同事在 www 上看到的是旧价格,开发同事在 static 上看到的是新价格,双方都认为自己看到的是“当前版本”。这时不要先问“哪个缓存坏了”,而要先把判定条件写下来。
ETag 或 Last-Modified?这一步的实际动作是把上述条件写成一条核对记录,例如“以源站返回的 ETag 为准,两个域名在发布后五分钟内必须一致”。结果是后续所有争论都围绕这条记录展开,而不是围绕个人浏览器截图展开。如果连判定条件都没定,后面查到的差异只能证明“不同”,不能证明“错”。
条件定好之后,下一步不是刷新页面,而是固定变量再取样。固定同一个 URL 路径、同一个查询参数、同一个请求头组合,分别向不同层发起请求。可以按下面的顺序做,每一步都记录返回的版本标识和响应头。
这里的关键动作是“固定变量”。如果第一步用带 cookie 的请求,第二步用不带 cookie 的请求,那么版本不同可能来自请求头差异,而不是缓存层差异。只有固定变量后,某一层返回的版本与其他层不同,才值得继续追查该层的缓存策略。
多层缓存返回不同版本,常见原因有两类,处理方式完全不同。
第一类是过期时间不同。例如源站已经更新,但 CDN 边缘节点的 TTL 还没到,浏览器本地缓存也还没过期。这种情况下,各层最终会收敛到同一版本,只是时间差。判断依据是:等待一个 TTL 周期后重新取样,差异是否消失。如果消失,问题属于同步窗口,需要调整的是各层 TTL 的匹配关系,而不是代码逻辑。
第二类是缓存键不同。例如 CDN 按 Host 头缓存,而二级域名和主域名被当成两个不同的缓存键,于是同一个内容被缓存了两份,更新时只刷新了其中一份。这种情况下,等待再久差异也不会消失。判断依据是:两个域名返回的版本长期不同,且源站版本只有一个。此时要核对的是缓存键的组成,而不是 TTL 数值。
区分这两类原因的实际意义在于:前者可以通过调整过期策略缓解,后者必须统一缓存键或增加主动刷新动作。如果一开始就假设是 TTL 问题,可能会反复等待却始终等不到一致。
当多个角色对同一事实有不同理解时,最有效的做法是让每个人提交同一格式的核对项。可以要求每个角色提供:请求的完整 URL、请求时间、返回的版本标识、响应头中的缓存相关字段、以及请求是否经过代理。把这些记录并排放在一起,差异会自己显现。
如果记录显示某一层始终返回旧版本,而其他层都返回新版本,那么下一步动作就是针对该层做单点验证:清除该层缓存后重新请求,观察是否变为新版本。如果清除后一致,说明问题在该层的缓存策略;如果清除后仍不一致,说明该层可能读取了不同的数据源,需要回到二级域名设置本身,确认它指向的源站或应用实例是否与预期一致。
需要留意的是,某一层请求量归零或抓取统计下降,并不能单独证明该层缓存处理正确。请求量变化还可能来自采集时间窗口、日志采样方式或流量本身波动。因此在核对清单里,版本标识比流量数字更有判断价值。
继续前面的假设情境。发布后,static.example.com 返回新版本,www.example.com 返回旧版本。按以下顺序核对:
Host,如果包含,它们天然是两个缓存条目。这个顺序的作用是:每做完一步,都能排除一种原因。如果第一步就发现源站有两个版本,那么问题不在缓存层,而在发布流程;如果源站只有一个版本,才继续往下查缓存键和回源目标。这样做的结果是,排查范围逐步收窄,而不是在多个层之间反复猜测。
最后要说明的是,robots.txt 的抓取限制不等于可靠的索引移除,站点地图也不保证收录,这些与缓存版本一致性不是同一类问题,不应混在同一张核对清单里。把版本一致性问题限定在请求路径和缓存策略上,才能让核对记录真正指向可执行的动作。