系统学习 学习路径总入口:先选领域,再建立模型,最后用故障演练验证

43 秒网络分区触发 Orchestrator 跨区域选主,GitHub 为保住写入选择“向前恢复”,事故持续 24 小时 11 分钟。 本文是公开报告的摘要与解读,事实以原始报告为准

本文是公开报告的摘要与解读,事实以原始报告为准。

事件概要

2018 年 10 月 21 日 22:52 UTC,GitHub 在更换故障的 100G 光传输设备时,切断了美国东海岸网络枢纽与东海岸主数据中心之间的连接。连接在 43 秒后恢复,但这短暂的网络分区触发了更大的故障。

运行在东海岸主数据中心的 Orchestrator 在 Raft 共识中失去 leader 身份;西海岸和公有云中的 Orchestrator 节点组成 quorum,把西海岸的 MySQL 主库提升为新的主库,应用写入随之转向西海岸。当连接恢复时,东海岸数据库保留了少量尚未复制到西海岸的写入,两边出现分叉,GitHub 无法安全地把主库切回东海岸。

GitHub 选择保留西海岸的写入,也就是“向前恢复”,而不是回滚并丢弃这部分数据。事故从 2018 年 10 月 21 日 22:52 UTC 持续到 10 月 22 日 23:03 UTC,报告给出的时长是 24 小时 11 分钟。

时间线

时间(UTC) 事件
10 月 21 日 22:52 更换 100G 光设备时切断东海岸网络枢纽与主数据中心连接;43 秒后恢复,触发后续故障
22:54 监控产生故障告警,值班人员开始排查
23:02 发现多个 MySQL 集群处于非预期拓扑;Orchestrator API 只显示西海岸数据库服务器
23:07 内部部署工具已被手动锁定,停止进一步变更
23:09 站点状态设为黄色,自动升级为事故并通知事故协调人
23:11 事故协调人加入
23:13 状态改为红色,数据库工程师被呼叫;西海岸集群已承接应用写入近 40 分钟
23:19 暂停 webhook 投递和 Pages 构建,主动降低功能以保护数据
10 月 22 日 00:05 确定恢复计划:恢复备份、同步两侧副本、回到稳定拓扑、处理积压
00:41 开始恢复所有受影响的 MySQL 集群备份
06:51 部分东海岸集群已恢复并从西海岸复制;较大集群仍在恢复,团队找到更快的“直接从西海岸恢复”路径,估计还需两小时
07:46 发布事故博客;由于 Pages 构建暂停,发布过程变慢
11:12 所有数据库主库回到东海岸,响应改善,但数十个只读副本仍落后数小时,读取可能不一致
13:15 接近流量高峰,复制延迟上升;在东海岸公有云增加 MySQL 只读副本并分散读流量
16:24 副本同步完成,切回原拓扑;状态仍为红色,继续处理积压
16:45 积压包含超过 500 万个 hook 事件和 8 万个 Pages 构建;约 20 万个 webhook 负载超过内部 TTL 被丢弃,暂停处理并提高 TTL
23:03 所有待处理 webhook 和 Pages 构建处理完毕,确认系统完整性,状态恢复绿色

影响面

事故持续 24 小时 11 分钟。用户看到的是过期或不一致的信息;大部分时间里,GitHub 无法投递 webhook 事件,也无法构建和发布 GitHub Pages。报告没有给出错误率百分比。

数据方面,报告明确说“最终没有用户数据丢失”,但写作时仍在人工核对“几秒钟的数据库写入”。受影响最繁忙的一个集群有 954 条写入需要核对;部分写入已被用户重试成功。恢复后,GitHub 通过 MySQL binlog 捕获未复制到西海岸的东海岸写入,能自动对账的自动处理,必要时联系用户。

积压方面,报告给出超过 500 万个 hook 事件和 8 万个 Pages 构建;约 20 万个 webhook 负载因超过内部 TTL 被丢弃。GitHub 暂停处理并提高 TTL,避免继续丢弃。

根因

触发点是 43 秒的网络分区。GitHub 当时运行多个 MySQL 集群,Orchestrator 负责拓扑管理和故障切换。东海岸的 Orchestrator 失去 Raft leader 后,西海岸与公有云节点形成 quorum,并按配置把西海岸主库提升为新的写入点。

Orchestrator 并没有违背配置。报告的原话是:Orchestrator 的行为符合配置,但应用层无法支持这种拓扑变化。东海岸应用跨全国写入西海岸数据库带来的延迟,超过应用层能承受的范围,许多用户因此无法正常使用服务。

当网络恢复时,东海岸数据库还有少量写入没有复制到西海岸,西海岸则已承接近 40 分钟的应用写入。两边都有对方没有的数据,直接切回东海岸会丢失西海岸写入,因此 GitHub 选择保留西海岸数据,先恢复服务,再对账。

处置与恢复

GitHub 的处置顺序是:先停止会放大问题的写入型工作,暂停 webhook 投递和 Pages 构建;再恢复备份、同步副本、回到稳定拓扑;最后处理积压并对账分叉写入。

备份每 4 小时一次,存放在远程公有云 blob 存储中。恢复多个 TB 的数据需要传输、解压、校验、准备和加载,耗时数小时。报告说这套流程经常测试,但 GitHub 此前从未从备份重建过整个集群。恢复过程中,团队发现直接从西海岸恢复部分集群更快,绕过离站存储的吞吐限制。

10 月 22 日 11:12,所有主库回到东海岸,但只读副本仍落后;13:15 增加东海岸公有云只读副本,分散读流量并降低延迟;16:24 副本同步完成,切回原拓扑;23:03 积压清空、完整性确认,事故结束。

教训

第一,故障切换必须理解应用层的延迟边界。Orchestrator 按 Raft 规则选主没有错,但它把一个应用无法承受的跨区域拓扑变成了现实。自动化的“正确”不等于业务上的“可用”。

第二,恢复时间估算不能线性外推。报告指出复制追赶呈“幂衰减”而不是线性轨迹,欧洲和美国的早高峰流量又延长了恢复时间。演练和估算都应考虑负载变化。

第三,状态页要按组件细分。简单的绿黄红无法表达“部分功能可用、部分数据可能不一致”,会放大沟通成本。

第四,数据优先于可用性。GitHub 选择保留西海岸写入、暂停 webhook 和 Pages,而不是丢弃数据换快速恢复;这个取舍需要在事故前就明确。

第五,复杂系统需要故障注入和混沌工程。报告把“更积极地测试假设”和“投资故障注入、混沌工程工具”列为改进方向,并推动多数据中心 active/active/active 架构与 N+1 设施冗余。

对本站读者的检查清单

恢复手册与同类复盘

相关命令

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. 43 秒的网络分区,为什么会演变成 24 小时 11 分钟的事故?
  2. GitHub 为什么选择“向前恢复”,而不是把主库切回东海岸?
  3. 从故障演练、状态沟通和数据对账三个角度,这次事故各留下什么改进点?
答案
  1. 分区让东海岸 Orchestrator 失去 Raft leader,西海岸节点组成 quorum 并提升西海岸主库;应用跨区域写入近 40 分钟,网络恢复后两侧出现分叉写入,无法安全切回,只能恢复备份、重建复制并处理积压。
  2. 切回东海岸会丢失西海岸已承接的写入;GitHub 选择保留数据,先在西海岸恢复服务,再通过 binlog 对账处理东海岸未复制的少量写入。
  3. 演练要覆盖网络分区、跨区域切换和回切,并加入故障注入与混沌工程;状态页要按组件细分,能表达降级和数据一致性;对账要覆盖分叉写入、异步积压、TTL 和用户重试。
微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令