死链处理:多层缓存返回不同版本时怎样定位一致性问题

📍 WDQWDWQD987AAAAA:216.73.216.164
📱 Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
🔗 /86dd4c1d8df3.html
📄

死链处理:多层缓存返回不同版本时怎样定位一致性问题

先给有条件的结论:当同一死链在不同层返回的版本不一致时,优先怀疑“缓存层各自持有了不同时间点的响应”,而不是死链本身被修好了。要定位一致性,必须把每一层的响应当独立证据采样,而不是只看浏览器或单一节点。只有当各层对同一请求的响应头、状态码和缓存键都能对齐后,才能判断死链处理是否真正生效。

先把“不同版本”拆成可核对的响应特征

多层缓存下,不一致通常表现为状态码、响应头或正文三者之一不同。不要用“页面看起来变了”作为判断依据,因为浏览器可能命中本地缓存,而中间层仍返回旧副本。一个可核对的证据是:同一 URL 在固定请求头下,分别记录状态码、Age、Cache-Control、ETag 或 Last-Modified,以及正文首段。若状态码在 404 与 200 之间摆动,说明至少有一层缓存了旧的成功响应,而源站已改为死链处理。

实际操作上,可以先用固定请求头逐层请求,而不是依赖浏览器。动作是:对同一 URL 分别从客户端、CDN 边缘、反向代理和源站各取一次响应,记录上述字段。结果会直接影响下一步——如果只有边缘层返回 200,而源站返回 404,那么问题不在死链规则,而在边缘缓存未失效;如果源站也返回 200,则要检查死链处理逻辑是否真的命中该 URL 规则。

缓存键与请求头是常见的不一致来源

不同层可能因为缓存键不同而返回不同版本。例如 CDN 按完整 URL 加查询字符串缓存,反向代理却忽略查询字符串,于是带参数的请求命中一个旧副本,不带参数的命中新副本。另一种情况是请求头差异:某些层对 Accept-Encoding 或 User-Agent 做变体缓存,导致同一 URL 出现多个版本。要验证这一点,可以固定请求头后再逐层请求,观察响应是否收敛。若收敛,说明不一致来自缓存键或变体,而不是死链处理本身。

假设一个场景:某 URL 已加入死链处理,源站返回 404,但 CDN 边缘仍返回 200 且 Age 很大。此时先不要急着刷新全站缓存,而应取该边缘节点的响应头,确认它是否携带了旧的 Cache-Control。如果旧响应头允许长缓存,那么边缘层只是按旧规则持有副本。下一步动作是让源站返回明确的失效信号,并确认边缘层是否按该信号更新。这个动作的结果会影响后续判断:若边缘层更新后仍返回 200,则要怀疑有中间层未传递失效信号。

用分层采样区分“缓存假象”与“处理未生效”

分层采样是区分两种解释的关键。第一种解释是死链处理已生效,但缓存层未同步;第二种解释是死链处理规则未覆盖该 URL,缓存层只是如实返回了源站的 200。区分方法是对同一 URL 同时记录源站响应和缓存层响应。若源站为 404、缓存层为 200,则属于缓存未同步;若源站也为 200,则属于规则未生效。不要用“抓取量归零”或“某层请求量下降”单独证明处理正确,因为这些现象也可能来自抓取预算调整、robots.txt 限制或外部链接变化。

这里有一个反例会使上述结论失效:如果源站本身在多台后端之间返回不同版本,那么缓存层只是放大了不一致,而不是造成不一致。此时逐层请求会看到源站内部也不一致,需要先统一源站响应,再谈缓存同步。换句话说,多层缓存不一致只是症状,源站多副本不一致才是病因。若忽略这一点,只清缓存,问题会再次出现。

下一步动作:先固定证据,再决定清哪一层

在证据未固定前,不要批量刷新所有缓存。建议按以下顺序推进:

  1. 对同一 URL 固定请求头,逐层记录状态码、Age、Cache-Control 和正文首段。
  2. 确认源站是否对同一 URL 稳定返回同一状态码;若源站不稳定,先修源站。
  3. 若源站稳定而某层不一致,检查该层的缓存键、变体规则和失效信号是否与源站一致。
  4. 只对确认持有旧副本的层执行失效,然后重新采样,观察是否收敛。

这个顺序的结果会决定下一步:如果失效后各层收敛到同一状态码,说明问题在缓存同步;如果失效后仍不收敛,则要回到源站和缓存键规则,检查是否存在未被发现的变体或中间层。死链处理的一致性,最终不取决于清了多少次缓存,而取决于每一层是否对同一请求给出可核对的相同响应。

图1 图2

nginx