Skip to main content

多 CDN 与多 DNS 容灾实战:健康检查、降级预案与切换检查表

October 5, 2026
以近期 Cloudflare 全球故障为引子,给出多 CDN 与多 DNS 的容灾设计:流量分配与健康检查配置、静态资源降级、源站直连预案、切换演练流程,以及故障判定与回切的检查表。
多 CDN 与多 DNS 容灾实战:健康检查、降级预案与切换检查表

更新日期:2026-10-05

2025 年 11 月 18 日,Cloudflare 发生其 CEO 称之为「2019 年以来最严重」的全球故障:一次 ClickHouse 权限变更让 Bot Management 的特征文件生成查询缺少数据库过滤条件,返回大量重复行、文件体积翻倍,超出核心代理模块预设的特征上限后触发 Rust panic,核心 CDN 与安全服务大面积 5xx,持续约 5 小时 46 分钟。故障初期,因为系统在「恢复—崩溃」之间反复震荡(特征文件每 5 分钟重生成,好坏配置交替传播),Cloudflare 自己一度把异常流量判读为超大规模 DDoS——官方事后复盘明确说明那不是攻击。2026 年 10 月 2 日,Cloudflare 状态页又记录了一次持续 11 分 24 秒的 critical 级 CDN/Cache 事件,期间通过 Dashboard 发起的配置变更与缓存清除持续报错,而 API 发起的清除不受影响。

把这两次放在一起,是为了说明一个朴素的事实:单一供应商的可用性承诺,覆盖不了它自己出故障的时刻。多 CDN/多 DNS 不是「多买一家」那么简单——买了第二家却没配健康检查、没定切换判据、没演练过降级路径的团队,故障当晚的真实动作仍然是盯着手忙脚乱地改 DNS。本文给的是后三样:分层容灾设计、可执行的检查与切换操作、以及一张可以直接贴在值班手册里的检查表。站点层面的缓存命中与回源治理,站内 CDN 缓存命中率从 60% 到 95%:缓存规则、Cache Key 与回源治理 已有专门讨论,本文不重复;DNS 迁移期间的 TTL 与 DNSSEC 细节见 零停机 DNS 迁移实战:TTL 策略、DNSSEC 与邮件记录切换检查表。

适用范围:已有一个主力 CDN(以 Cloudflare 为例,方法论不限厂商)与单一 DNS 托管商、有静态资源可降级、流量以 Web/HTTP 为主的站点。不适用场景:全动态、强会话粘滞、离开单一 CDN 就无法工作的架构(先做无状态化改造,容灾才有意义);预算只够一份 CDN 合同的站点——本文第六节的「应用层降级」仍然适用,但 DNS/CDN 双活部分可以跳过;以及把容灾理解为「签了两家供应商」的采购行为——那是本文要纠正的起点。

先看结论

  1. 容灾分三层,各自的失效模式和工具不同:DNS 层(解析可达)、CDN 层(边缘服务能力)、应用层(功能降级)。三层混在一起谈「高可用」,故障时每一层都不知道该谁出手。
  2. 健康检查必须独立于被检查的对象。 用 CDN 自己的探针判断 CDN 是否健康,它挂了你收不到告警;外部拨测 + 状态页订阅 + Radar 类故障地图,至少要有两路独立信号。
  3. DNS 切换是最慢的开关,TTL 不是越短越好。 主备 DNS 用区域传送(XFR)保持一致,权威侧故障切换靠注册商级别的 NS 与 TTL 纪律;日常 TTL 300 秒量级,故障切换才依赖它提速。
  4. CDN 双活比主备好,但主备更便宜。 起步方案:主 CDN 承载全部流量 + 备 CDN 冷备配置 + DNS 加权记录;成熟方案:按地域或比例分流。两者都必须每月演练。
  5. 缓存清除走 API,不走控制台。 2026-10-02 那次 11 分钟的事件里,Dashboard 发起的清除报错而 API 正常——这既是「API 优先」的论据,也说明故障期间哪些功能还活着要靠验证,不靠猜测。
  6. 应用层降级是最后一道防线,也是唯一你完全可控的一道。 静态资源可回源、关键页面有纯静态版本、purge 与发布脚本不依赖单一控制台。
  7. 切换判据写进剧本,不靠值班同学临场判断。 「持续 N 分钟错误率超 X% 且供应商状态页确认」触发切流;「错误率回到基线 M 分钟且官方确认恢复」触发回切,避免来回震荡。
  8. 每季度做一次半真实演练:把主 CDN 的回源 hosts 指向黑洞,验证备路自动接管与业务影响面,演练结果记入值班手册。

从两次故障看单点依赖的失败形态

先看 2025-11-18 的官方时间线(UTC),注意每一步的形态——它不是流量打挂的,是配置变更经全局同步机制放大的:

时刻(UTC)事件
11:05数据库权限变更落地
11:20 起核心服务出现大量 5xx;Turnstile、Workers KV、Dashboard 登录、Access 认证相继受影响
14:30核心流量基本恢复
17:06全部服务恢复,总时长约 5 小时 46 分

根因链条值得每个运维记住:权限变更 → 特征文件生成查询缺 default 库过滤 → 重复行把文件撑大一倍 → 超过核心代理预设的 200 个特征上限 → Rust panic → 5xx → 每 5 分钟的重生成让坏配置反复传播 → 官方一度误判为 DDoS。它教训有三:内部配置文件要按不可信输入做防御(官方事后的加固项之一);核心组件要有全局 kill switch(官方加固项之二);故障期间供应商自己的判读也会错,所以你的切换判据必须基于自己观测到的错误率,而不是供应商的口头结论。

再看 2026-10-02 的短事件:21:46:34 UTC 开始,21:57:57 UTC 解决,受影响组件是 CDN/Cache 与 Cache Purge,Dashboard 驱动的变更与清除报错,API 清除不受影响,级别 critical。11 分钟对多数业务无伤,但它演示了一个细节:同一家供应商的多个入口,故障时存活状态不同。这也解释了为什么降级路径要提前设计好多个——控制台挂了走 API,API 挂了走预置脚本,主链路挂了走降级静态版。

容灾的三个层次:各自的目标与工具

层次失效形态目标主要工具
DNS权威服务器不可达/解析错误域名始终可解析,并能快速把流量指到健康的 CDN主备权威 + 区域传送;注册商处低 TTL;DNS 故障切换记录
CDN边缘 5xx、回源失败、控制台/API 功能受损流量能按比例或地域在供应商间转移LB 健康检查与引流策略;双供应商配置热备
应用依赖的边缘功能不可用时业务不可用无 CDN 也能出关键页面静态资源多源;关键页静态化;API 优先的运维脚本

三层的关键差异在切换速度与影响半径:DNS 最慢(TTL + 各地递归缓存,分钟到几十分钟),但影响全局;CDN 层的健康检查切换最快(探针间隔秒级),但只覆盖走它引流的流量;应用降级零切换时间,但只保核心功能。设计时按「DNS 兜底、CDN 主力、应用保命」分配职责,而不是指望任何一层包打一切。

DNS 层:主备解析与故障切换

目标只有一个:无论哪家 DNS 出问题,域名都能被解析,且你能把解析结果改指到健康的一侧。落地分三步。

第一步,主备权威。 主 DNS 保持现状,备 DNS 用区域传送(AXFR/IXFR)同步。以 Cloudflare 为例,官方提供作为 Secondary DNS 的完整文档,支持与第三方 primary 组成主备,含 NOTIFY 与 ACL 配置、以及 secondary 侧的 DNSSEC 处理。配置后验证:

# 向主备权威分别查询,确认记录一致(把 ns1/ns2 换成你的主备权威)
dig @ns1.example-dns.com www.mf8.biz A +short
dig @ns2.backup-dns.net www.mf8.biz A +short

# 确认序列号在增长(IXFR 生效)
dig @ns2.backup-dns.net mf8.biz SOA +short

第二步,TTL 纪律。 需要应急切换的记录(A/CNAME 指向 CDN 的那些),TTL 保持在 300 秒量级;更低会放大查询量、更高会拖慢切换。注意 TTL 只约束「允许缓存多久」,各地递归服务器的实际遵守程度不一,所以切换判据里的「生效等待时间」要按 2–3 倍 TTL 估。

第三步,注册商层的预案。 NS 记录的变更在注册商处,极端情况下(权威全面失联)你要能把 NS 整体指向备方。把这个流程写成三行命令级别的操作单,并确认注册商的变更生效时间——这件事一年做一次演练就够,但必须做过。

DNS 层的自动化故障切换(health-check 驱动的记录切换)各家 DNS 都有,可以用;但记住 2025-11-18 的教训——探测与切换系统本身也可能是故障域。关键记录的手工切换路径永远保留。

CDN 层:多供应商的流量分配与健康检查

健康检查的设计参数,以 Cloudflare Load Balancer 的官方文档为参照:每个监控项按可配置间隔探测,每个区域默认 3 个数据中心探测、多数表决判定健康,类型覆盖 HTTP/HTTPS、TCP、ICMP、UDP-ICMP、SMTP;Enterprise 可选全部数据中心探测;多区域加低间隔会产生可观的探测流量。独立于负载均衡的 Standalone Health Checks 可以只监控源站不参与引流。这些参数的工程含义:

  • 多数表决 + 多数据中心是为了防单点误判,但它防不了「全局性误判」——比如所有探针走同一个上游出口。条件允许时,外部拨测(另一家供应商的拨测服务)必须有一路。
  • 探测路径要直指关键资产:不是探测首页,而是探测「经 CDN 的完整链路」——一个边缘缓存的静态探针 + 一个回源的动态探针,分别命中缓存层故障与回源故障两种形态。

双供应商的两种形态,按成熟度选:

# 形态 A:主备(起步)。主 CDN 承载 100%,备 CDN 配置热备但 0 流量。
# DNS 用加权记录:primary 权重 100 / secondary 权重 0,故障时对调。
# 验证备路配置是否真的能服务(关键!0 流量的配置一定会腐烂):
curl -s -o /dev/null -w "backup cdn: %{http_code} %{time_total}s\n" \
  --resolve www.mf8.biz:443:$(dig +short backup-gw.mf8.biz | head -1) \
  https://www.mf8.biz/static/app.js

# 形态 B:双活(成熟)。按地域/延迟引流,单家故障时健康检查自动把池摘除。
# 每家各承载 50%,故障影响半径从 100% 降到 50%,代价是两边配置都要维护。

形态 A 的最大风险是冷备腐烂:证书过期、源站证书链变更、缓存键规则漂移,备路三个月没接流量,切换时才发现证书是错的。所以形态 A 的月度演练不是可选项。两种形态共同的前提:两家的缓存规则、源站配置、压缩与头部策略保持一份对齐清单,变更时两边同步改——「配置漂移」是多 CDN 故障的第一大根因。

应用层降级:让「没有 CDN」也能活

DNS 与 CDN 都失守时的最后防线,目标是核心页面可读、核心事务可用,而不是完整体验。三件事:

静态资源多源。 关键 JS/CSS/字体除了主 CDN,还有源站直连路径(或对象存储直链)。资源引用用相对协议的自身域名时,可以做「同路径双源」:CDN 失效时,通过备用域名或 hosts 覆盖仍能拿到同一路径。验证方法:

# 模拟 CDN 失效:把主 CDN 域名指向黑洞,验证浏览器降级路径(改 hosts 前先备份)
# 然后核对:页面在 CDN 不可达时,静态资源是否来自源站直连路径
curl -s -o /dev/null -w "origin direct: %{http_code}\n" https://origin-direct.mf8.biz/static/app.js

关键页面静态化。 首页、帮助页、状态页生成纯静态版本放在不依赖主链路的位置。这条同时服务故障与流量洪峰两种场景。

运维脚本 API 优先。 缓存清除、DNS 记录修改、证书续期,全部用 API + 预置凭据的脚本完成,控制台只做查阅。2026-10-02 的事件再次验证了这条:控制台清除持续报错时,API 调用不受影响。把「本次故障期间哪些入口还活着」的验证写进故障剧本,而不是等下次故障现场试。

演练:切换剧本与检查表

容灾的价值在演练里兑现。季度演练的完整检查表:

  • 备份并冻结演练窗口的生产变更;通知团队与(必要时)供应商。
  • 确认备 DNS 区域序列号与主区一致;dig 抽查关键记录双源一致。
  • 确认备 CDN 证书有效期 > 30 天、源站回源连通、缓存规则与主对齐清单无漂移。
  • 将主 CDN 回源路径指向黑洞(或在测试域名上复刻链路),观察外部拨测与自身监控的告警时间与准确性。
  • 执行 DNS 切换(测试域名或加权记录对调),记录从执行到全球生效的时间,与 2–3 倍 TTL 的预期对照。
  • 验证备路全链路:首页、关键 API、登录、支付回调(如有)。
  • 执行回切,记录回切判据的命中情况;确认无流量震荡(错误率无二次抬升)。
  • 复盘并更新本表:实际生效时间、误报的告警、配置漂移项,全部落进值班手册。

日常(非演练)的故障切换判据,示例基线(按业务容忍度调整):

  • 切换触发:核心路径错误率(5xx 占比)> 5% 持续 5 分钟,或 P95 延迟 > 3 倍基线持续 10 分钟,且供应商状态页/公告确认或无法排除平台侧故障。
  • 回切触发:主路错误率回到基线(如 < 0.5%)持续 15 分钟,且供应商确认恢复。回切用渐进权重(10% → 50% → 100%),每步观察一个探测周期,防止坏配置未清除干净导致二次切流。

故障期间的信号源

订阅这些,并且不止订阅一家供应商的:

# 1. 状态页 RSS(Cloudflare 状态页官方提供,替换订阅地址即可复用)
curl -s https://www.cloudflarestatus.com/api/v3/incidents.rss | head -20

# 2. 历史事件 JSON(排障时拉取确认时间线)
curl -s "https://www.cloudflarestatus.com/api/v2/incidents.json?limit=20" | jq '.incidents[0] | {name, impact, created_at}'

# 3. 互联网级故障地图:Cloudflare Radar Outage Center
#    https://radar.cloudflare.com/outage-center
#    区分「只有我的站点异常」与「区域性/全球性异常」

信号源的用法要事先定好:状态页是判定依据(触发切换判据里的「平台确认」项),Radar 是范围判据(区分自己回源配置坏了还是平台坏了),自有监控是唯一的事实来源(错误率、延迟、影响用户数)。三者的角色不要混。

观测与告警:让容灾状态可见

容灾体系没有观测,切换就只能靠用户投诉来触发。观测层要回答三个问题,每个都给到具体实现:

问题一:现在流量走在哪条路上? 双活或灰度期必须能随时回答。DNS 层用加权记录时,网关/CDN 的日志里带上游标识;应用响应头里加一行自报家门:

# 源站响应头自报(便于拨测与排障确认当前路径)
add_header X-Serve-Path "primary-cdn" always;

问题二:每条路的健康度如何? 合成拨测按「主路关键 URL + 备路关键 URL」双份配置,间隔 30–60 秒,双地域发起。判据不是 HTTP 200,而是「200 + 内容特征 + 延迟阈值」三重——只看状态码,抓不到「200 但返回的是缓存错误页」这种最伤人的形态。

问题三:什么时候该人肉介入? 告警分级与容灾动作直接挂钩:P3(单点拨测失败)值班关注;P2(多地域拨测失败或错误率 > 1% 持续 5 分钟)触发「核对供应商状态页 + 预热切换决策」;P1(切换判据命中)直接执行剧本。每个级别的通知渠道、响应时限写进值班手册——告警没有对应动作,等于没有告警。

错误预算是这套观测的货币:把「月度 99.9% 可用」拆成分钟数,每次降级与切换消耗的错误预算记录在案——容灾演练消耗预算是正常成本,无演练积累的容灾在真故障时的表现才是真正的未知数。

演练之外:把容灾写进日常流程的四个触点

演练之外,容灾状态会腐烂,因为它不在任何日常流程里。四个把容灾「日常化」的触点:

变更单模板:所有 CDN/DNS 配置变更的模板里,固定两栏「对备路的影响」「是否需要同步到备供应商」——2025-11-18 那类「一次变更全局放大」的事故,一半的防线就是变更单里那行强制思考。

证书与域名监控:备路证书 30 天到期的告警、域名注册商到期与 DNSSEC DS 记录的核对,进运维日历月检——冷备腐烂的两大来源都是「没人记得它」。

供应商沟通渠道:故障时需要工单/电话/客户经理通道,这些通道的可用性要在非故障时验证一次(发一张状态询问工单,记录响应时长)——故障当天第一次找渠道,找到的通常是排队页。

值班交接:交接单固定一栏「当前流量路径状态」——正常主路/降级中/演练中,让每一次交接都重新确认「现在谁在服务」,避免「降级跑了三天没人记得切回来」这类事故。

供应商锁定的成本账

容灾方案自己也有成本结构,「锁定」是其中最隐蔽的一项。三个维度的账:配置可移植性——缓存规则、WAF 规则、路由逻辑在供应商间的翻译成本,随使用深度线性上涨,这句话的工程含义是:把「规则即代码」(Terraform/API 管理)作为从第一天起的纪律,迁移时是搬运,否则是重写;数据与流量成本——多 CDN 之间的回源流量、日志导出、跨云传输各有计费口径,双活的账单不是单活的两倍,常常是 2.5 倍以上,预算要按实测口径做;合同与承诺——备供应商的「冷备」流量几乎为零时,商务谈判里拿到的费率与技术支持等级都会打折,演练流量、按量承诺、支持响应条款要在签约时写进去,否则容灾的真实水平由合同决定而不是由架构决定。

把这三个维度写成一年一度的复核:规则代码化覆盖率、双路实测月账单、备方合同条款清单。容灾的敌人从来不是故障,而是「故障来时,你以为的容灾和实际存在的容灾之间的差值」——复核就是把差值清零的动作。

官方资料与继续阅读

外部官方链接:

站内相关文章:

事实与日期边界:2025-11-18 故障的时间线、根因与加固项来自 Cloudflare 官方复盘;2026-10-02 事件的状态页记录截至本文更新日尚无官方根因复盘,本文仅引用状态页事实。健康检查与区域传送的功能描述以 Cloudflare 官方文档为准,具体参数(探测间隔、定价、Enterprise 功能)随产品更新,采用前以文档当日版本为准。