一条命令,六小时静默:Meta 2021 BGP 大宕机如何让全球最大社交网络从互联网消失

2 minute read

Published:

English version 英文版

先看一个应该让每个 infra 工程师停下来想一想的数字:2021 年 10 月 4 日,一条例行维护命令断开了 Meta 所有数据中心之间的连接——几分钟内,Facebook、Instagram、WhatsApp 和 Messenger 从互联网上消失了约六小时。不是变慢,不是降级,是消失,就像有人同时拔掉了每个数据中心的网线。

服务器还在运行。数据完好无损。也没有黑客攻击——Meta 自己的 postmortem 明确写了,这次宕机没有恶意活动,也没有证据表明用户数据泄露。坏掉的是服务器之下的那一层:告诉互联网这些服务器在哪的网络,以及让服务器彼此通信的网络。

这是 🔥 Incident Recap 系列的第一篇,选它开篇是有原因的,因为它的教训让人不舒服:这次宕机不是由一个错误造成的,而是一个错误穿过了三个放大机制,每个机制单独看都合情合理,合在一起却是灾难性的。修掉其中任何一个,事故都会小得多;三个全留着,一条命令就能把一家公司从互联网上抹掉。

背景:骨干网是什么,BGP 和 DNS 是干什么的

Meta 的平台跑在一个私有的全球骨干网(backbone)上:这是 Meta 自己建的网络,用数万英里的光纤把全球所有计算设施连接起来。

按 Meta postmortem 的说法,数据中心有两种形态:

  • 大型计算与存储数据中心——容纳数百万台机器的庞大建筑,负责存储数据和运行繁重的计算负载。
  • 小型边缘设施——骨干网与更广阔的互联网、与用户相遇的地方。你打开 App 时,请求先到最近的边缘设施,再经由骨干网到达大型数据中心,取回并处理信息后原路返回。

这个物理网络之上跑着两个互联网协议,两者都与这次事故有关:

  • DNS 是互联网的通讯录:把 facebook.com 这样的名字翻译成服务器 IP 地址。Meta 用自己的权威域名服务器回答这些翻译查询,这些服务器就位于小型边缘设施中。
  • BGP(边界网关协议) 是各个网络互相宣告自己存在的方式。Meta 的域名服务器占据着众所周知的 IP 地址,这些地址通过 BGP 向整个互联网宣告。如果某段地址的 BGP 宣告被撤回,互联网其余部分就找不到去往它的路由——那个地址背后的服务器即使通电且运转正常,也变得不可达。

记住最后这一点,因为它是整个事故的支点:可达性(reachability)和健康状态(health)是两回事,而这次宕机正是系统把两者混为一谈的结果。

时间线(UTC,2021 年 10 月 4 日)

时间(UTC)事件
~15:40Cloudflare 观测到 Meta 网络出现 BGP 路由变更高峰——麻烦开始了。
~15:50公共 DNS 解析器上 facebook.com 停止解析。
15:58Meta 停止宣告其 DNS 前缀的 BGP 路由。
15:51–16:00Cloudflare 开内部 incident(”Facebook DNS lookup returning SERVFAIL”),一开始还怀疑是自家解析器坏了。
当晚Meta 派工程师亲赴数据中心现场;物理与系统安保拖慢了进入与操作。
~21:00Meta 网络出现新的 BGP 活动,21:17 达到高峰。
~21:20公共解析器上 facebook.com 恢复解析。
~21:28Meta 似乎重新接入全球互联网,服务分阶段恢复。

仅 DNS 黑洞窗口(约 15:50 到 21:20 UTC)就长达约五个半小时,服务完全恢复还要更久。通常引用的时长是约六小时。

故障传播:一条命令,三个放大器

下面是故障传播链,从维护命令到全球消失:

graph TD; A["例行维护命令"] -->|"评估骨干网容量"| B["骨干网容量管理系统"]; B -->|"审计工具 bug,未拦截"| C["全部骨干网连接被撤下"]; C --> D["数据中心彼此失联"]; D --> E["边缘 DNS 服务器连不上数据中心"]; E -->|"健康检查,撤回 BGP"| F["全部 DNS 的 BGP 宣告被撤回"]; F --> G["互联网找不到 Meta 的服务器"]; G --> H["App 重试,DNS 查询暴涨 30 倍"]; C --> I["主用与带外访问全部中断"]; I --> J["工程师被派往现场"]; J -->|"物理安保拖慢进入"| K["骨干网恢复"]; K -->|"分阶段恢复,电力与缓存风险"| L["服务在数小时内陆续恢复"];

图中每个箭头都是一种机制,值得单独理解——因为只看时间线,这次宕机会像是运气不好。它不是运气不好,是耦合。

放大器 1:护栏本身有 bug——而且它是唯一的护栏

触发事件按 Meta 的说法是:一次例行维护中发出了一条命令,本意是评估全球骨干网容量的可用性,却意外地切断了骨干网中的全部连接,实际上让 Meta 的数据中心在全球范围内彼此断联。

Meta 的系统本来设计了审计机制来拦截这类命令,防止正是这样的错误。但审计工具里的一个 bug 导致它没能正确阻止这条命令。

这是第一个需要认真对待的机制,因为它不是”工程师敲错了命令”。它是安全层内部的单点故障:审计工具是横在一条例行命令和一场全球宕机之间的控制手段,而审计工具背后什么都没有——没有第二道检查,没有爆炸半径上限(比如把一条命令的影响封顶在一个区域或一部分骨干链路),没有金丝雀(先把变更应用到一小部分、观察结果再继续)。

一个会静默失效的护栏不是护栏,只是延迟。这个机制要求的修复不是”以后小心点”,而是结构性的:爆炸半径是全球的命令,必须接受不依赖于单一工具正确性的限制。具体来说:硬性限制一条命令能触碰多少骨干网资源;即使是听起来只读的评估命令也要分阶段推出;审计工具本身要拿已知有害命令做测试。注意这个机制修不了什么:哪怕审计工具完美无缺,如果底层系统允许一条命令触碰一切,你依然不安全。爆炸半径限制和护栏测试是互补的,不是互相替代的。

放大器 2:单独看合理的健康检查,被所有人同时执行

第二个机制是把一次骨干网故障变成”从互联网消失”的那一步。

Meta 的 DNS 服务器被设计成:如果自己连不上数据中心,就停用自己的 BGP 宣告,因为这表明网络连接不健康。正常运行时这很合理:如果某个边缘站点病了,它主动让开,让互联网其余部分路由到健康的站点。健康检查是局部的——每个 DNS 服务器只判断自己的连通性。

但这次事故中,整个骨干网都被撤下运行。于是每个边缘站点的健康检查同时给出了同一个答案:不健康。所有站点同时撤回了 BGP 宣告。最终结果用 Meta 的话说就是:DNS 服务器变得不可达,尽管它们仍在运行——互联网其余部分再也找不到 Meta 的服务器了。

这就是相关性故障 / 共模耦合:一个安全机制的触发条件被所有副本共享。每次单独的撤回按局部规则看都是正确的;全局结果却是整个系统把自己撤下了。打破这种耦合的机制不是”去掉健康检查”——单个站点故障时健康检查确实有用。而是让撤回决策具备相关性意识:对撤回做阻尼或错峰、要求多个独立信号达成 quorum,或者在故障是全局性而非局部性时继续宣告 last-known-good 路由。设计问题应该是:当所有人同时报告不健康时,集群该做什么?如果答案是”所有人同时让开”,那你的健康检查就是一个自毁按钮,只等一个相关性触发器来按下它。

还有一个值得点名的二阶效应。Cloudflare 测到,宕机期间全球 DNS 解析器处理的查询量达到了平时的 30 倍,因为应用和用户都不接受”报错”这个答案:App 疯狂重试,用户反复刷新、重启。一次彻底的消失会把每个客户端变成重试循环,而重试风暴会压垮所有人共享的基础设施——公共 DNS 解析器。”我们不可达”的爆炸半径,超出了你自己的系统。

还有一个 Cloudflare 外部视角捕捉到的微妙之处:宕机期间 Meta 的其他 IP 地址仍然在路由。服务器并非在 IP 层全部不可达——但没有 DNS,客户端发现不了这些 IP,服务实际上依然不可用。DNS 是唯一的会合点,它一倒,它上面的一切都跟着倒。

放大器 3:恢复路径穿过了已经故障的系统

第三个机制解释了为什么是六小时,而不是六十分钟。

骨干网断掉后,Meta 的工程师面临两个障碍,postmortem 里都写了:因为网络断了,无法通过正常手段访问数据中心;DNS 的全面丢失又破坏了 normally 用于调查和解决这类宕机的许多内部工具。主用和带外网络访问都断了。

于是 Meta 派工程师亲赴数据中心现场,去调试问题、重启系统。这花了时间,因为这些设施的设计就强调高级别的物理与系统安全:它们很难进入;进去了之后,硬件和路由器也被设计成即使物理上能接触到也难以修改。激活安全访问协议、让人到场并能动手操作服务器,又花了额外的时间。只有到那时,团队才能确认问题、让骨干网重新上线。

这就是恢复依赖病人本身的故障模式:工具、访问路径、调查机器,全都依赖于已经故障的那个网络。一条与被恢复系统同命运的恢复路径,根本不是恢复路径。打破这种耦合的,是真正独立的带外通道——独立的网络、独立的认证、独立的工具——并且要在演习中真正使用它来证明它可用,而不是只写进文档。Meta 的 postmortem 坦承安保措施拖慢了恢复,并把这框定为值得付出的 tradeoff:大大提升日常安全性,换取在希望罕见的事件中更慢的恢复。这个 tradeoff 可以成立——但前提是成本侧被诚实定价、break-glass 路径被演练过,而这次事故恰恰揭示了这一点在这种规模上并未做到。

回来的路:为什么恢复是分阶段的,而不是一键翻转

骨干网连接在各数据中心区域恢复后,一切并没有简单地回来。Meta 知道,如果一次性把所有服务全部打开,可能因流量激增引发新一轮崩溃。个别数据中心报告的电力用量下降幅度达到了数十兆瓦量级,而突然逆转这样幅度的用电下降,可能危及从电气系统到缓存的一切。

所以恢复是分阶段、谨慎管理的。让这成为可能的,是准备工作:Meta 归功于长期运行的 “storm” 演习——故意让某个服务、某个数据中心或整个区域下线,来对基础设施和软件做压力测试。这些演习的经验给了团队把服务带回来并管理不断增长负载的信心——服务恢复了,且没有再发生系统级故障。

但 postmortem 里有一句诚实的承认:Meta 此前从未运行过模拟全球骨干网下线的 storm 演习,今后会寻找方法模拟这类事件。演习覆盖了他们想象过的故障模式;事故是他们没演练过的那一种。这个缺口——演练了组件故障,却没演练相关性的、全局的变体——正是整场宕机的精确形状。

值得偷走的教训

  1. 把控制平面变更当作生产发布,而不是维护。 一条能触碰整个骨干网的命令,值得拥有和代码发布一样的机器:爆炸半径上限、分阶段推出、金丝雀度量、回滚。”例行维护”是个标签,不是风险等级。
  2. 你的护栏也需要护栏。 一个静默失效、没拦住灾难性命令的审计工具,比没有审计工具更糟,因为它制造了虚假的安全感。拿已知有害输入测试安全层本身,并且永远不要让单一工具成为一条命令与全球影响之间的唯一屏障。
  3. 健康检查必须具备相关性意识。 任何能让所有副本同时撤回、摘除或切换的机制,都是一个自毁按钮,只等一个相关性触发器。问一句:当所有人同时报告不健康时,这个系统会做什么?如果答案是”所有人同时让开”,那就重新设计——阻尼、错峰、quorum,或者保留 last-known-good 宣告。
  4. 恢复路径不能与被恢复的系统同命运。 如果你的带外访问、内部工具和 runbook 都依赖于刚刚故障的那个网络,那你并没有带外访问。建一条真正独立的 break-glass 路径——并且在演习中使用它来证明它有效,而不是只把它写进文档。
  5. 演练相关性故障,而不只是组件故障。 让单个服务或单个区域下线的 storm 演习是必要的,而且这次确实派上了用场。但真正发生的事故是没人模拟过的全局变体。你的演习计划里至少应该有一次”一切同时故障”的场景,因为正是那种场景会考验你的耦合假设。
  6. 把安全性与可恢复性的 tradeoff 显式定价。 Meta 的安保措施拖慢了它自己的恢复,而 Meta 为这个 tradeoff 辩护。这个立场可以成立——但前提是成本被度量过、break-glass 路径被演练过。在紧急情况下无法在受控条件下绕过的安全措施,会在停机时间上向你收费。

Postmortem 没说的话

诚实起见,也要指出 Meta 公开 postmortem 没有包含什么。它没有公布带日期的具体修复清单——只说正在进行广泛的复盘,并从方向上承诺加强测试、演习与韧性。它没有在技术细节上解释审计工具的 bug。它也没有量化用户或业务影响,除了宕机本身。这种单薄本身就是一个数据点:公开 postmortem 往往更擅长解释发生了什么,而不擅长承诺要改什么。上面的教训来自 postmortem 确实描述的机制——审计失效、相关性 BGP 撤回、恢复耦合、分阶段恢复——而不是来自 Meta 公布的任何修复清单。读 postmortem 时,要把机制证据(这里很扎实)和整改承诺(这里很单薄)分开,并相应地加权。

Sources

  • Santosh Janardhan, “More details about the October 4 outage,” Engineering at Meta, October 5, 2021. https://engineering.fb.com/2021/10/05/networking-traffic/outage-details/ — 本篇机制 claims 的主要来源:触发原因(骨干网容量命令、审计工具 bug)、DNS/BGP 撤回机制、主用与带外访问丢失、现场派人、数十兆瓦量级的电力下降、分阶段恢复、storm 演习、安全与恢复的 tradeoff。
  • Santosh Janardhan, “Update about the October 4th outage,” Engineering at Meta, October 4, 2021 (updated Oct 5). https://engineering.fb.com/2021/10/04/networking-traffic/outage/ — 确认无恶意活动、无证据表明用户数据泄露的主要来源。
  • Cloudflare, “Understanding how Facebook disappeared from the Internet,” October 4, 2021. https://blog.cloudflare.com/october-2021-facebook-outage/ — 独立的外部视角度量:BGP 路由变更高峰约 15:40 UTC、DNS 前缀 15:58 UTC 前撤回、facebook.com 约 15:50 UTC 无法解析、约 21:20 UTC 恢复解析、新的 BGP 活动约 21:00 UTC、21:17 UTC 达峰、约 21:28 UTC 重新连接,以及公共解析器上约 30 倍的 DNS 查询激增。Meta 的叙述与 Cloudflare 的时间戳在粒度上有差异时,本文对外部观测时间采用 Cloudflare,对内部因果采用 Meta。