• AaronConlon.dev
  • Talk
  • Weekly
  • 工具
  • 编程
  • 翻译
  • 资讯
  • 通识

GitHub 故障 7 小时复盘:最隐蔽的重试风暴

2026年08月20上次更新于 21 天前
编程

hello!大家好!

上周五晚上九点半左右,我坐在电脑前正准备把一个功能分支合并进主分支。

在网页上点下 Merge 后,浏览器顶部那条蓝色的进度条卡在中间不动了。过了几秒,整页直接跳出一片空白,随后返回了 500 错误。我顺手强制刷新页面,依然无法加载。

第一反应是以为本地网络代理出了问题,我随手新开了一个标签页刷了下某个屎黄色站点,视频秒开,网络非常顺畅。再切回 VS Code,右下角 Copilot 图标也悄悄亮起了无法连接的提示。

这时候在技术交流群里已经有人开始发截图问:“GitHub 是不是挂了?”。然而群里的反馈并不一致:有的朋友说完全打不开,有的朋友却说自己拉取代码一切正常。推特时间线上也有不少开发者陆续晒出 500 报错页面。

大家一边在群里发表情包,一边排查到底发生了什么。这种“部分地区能用、部分地区报错”的半瘫痪状态持续了很久。部分用户的 PR 无法合并、CI/CD 停滞,VS Code 里的 Copilot 也频频断连。

一直到第二天早上,经历了整整 7 个多小时的局部震荡后,GitHub Status 正式发布了事故复盘。报告里记录了这次事故的前因后果。

撇开那些过于晦涩的技术术语,我们用清晰、直白的方式,看看这场局部受损却波及极广的事故到底是怎么发生的。

来源:GitHub Status 事故报告

事故影响:部分服务与区域受阻

根据 GitHub Status 官方记录( 8 月 17 日 13:28–21:15),本次事故持续了整整 7 小时 47 分钟。

需要先明确一个关键事实:本次事故并非全球全站彻底下线,主要受灾区域集中在 Central US 数据中心,表现为部分地区与部分服务的间歇性高错误率。

官方披露的核心受损指标相当直观:

  • 网页端与 REST/GraphQL API 整体错误率峰值接近 20%(其余大部分正常流量依然可达)。

  • 仓库 archive 与 raw content 的下载错误率攀升至约 50%。

  • Issues、Pull Requests、Actions 和 Webhooks 出现大面积降级,Git 操作、Pages 与 Copilot 均受到不同程度冲击。

  • 涉及企业级身份认证的 SAML/OIDC、SCIM 以及 Team Sync 路径同样出现局部故障。

  • 采用 Data Residency 架构的企业客户,由于部分 Actions 工作流依赖 GitHub.com 托管的公开 Step 定义,也遭到级联波及。

  • 与此同时,通过 GitHub CLI 和 GitHub App 使用 Copilot 的用户全程未受影响,受灾最严重的是 VS Code 等桌面客户端。

这种“有人正常、有人全挂”的局部异常,反而让排查变得更加扑朔迷离。

故障根因:容量配置盲区引发连锁阻塞

梳理官方报告可以发现,整场事故的源头来自一个容易被忽视的网络代理配置盲区:

  1. Sidecar 代理触及并发上限:Central US 数据中心遭遇流量高峰,负责内部网络路由的单个 Istio sidecar pod 达到了并发连接上限。举个例子,就好比一个业务窗口虽然大门敞开,但门前的专用安检通道已经挤满了人,流量大到挤满通道,没法疏导。

  2. 自动扩容指标未联动:自动扩缩容策略(HPA)当时只盯住了宿主业务服务的 CPU 和请求指标,未把 Sidecar 代理的并发负荷算进去。系统误以为容量充足,未及时启动弹性扩容。

  3. 关键节点连接耗尽:局部的网络阻塞迅速扩散,直接导致上游 4 个关键 HAProxy 节点耗尽了连接与流量配额(flow limit)。

  4. 认证通路大面积变慢:HAProxy 承载着网关身份鉴权的核心链路。一旦这里堵死,依赖鉴权验证的网页端、API、Actions 和 Copilot 服务立即陷入大面积延迟和超时。

认证网关如同整座系统的总闸机,闸机卡住后,内部即便各模块完好,外部用户也无法正常通行。

放大效应:客户端重试引发流量风暴

如果仅仅是局部网关卡顿,系统或许能较快排查并完成切换。真正让事故拉锯了近 8 个小时的关键,在于各层重试机制造成的流量放大。

平时遇到接口报错,大家最下意识的动作是什么?

重试!不行就再点一次!接着连续狂按重试!

大家总觉得“多试一次总能成”,而客户端程序更是在后台不知疲倦地把这个动作放大了成千上万倍。

在大规模故障场景下,未经节制的重试往往会演变成无意识的集群压迫:

  • 鉴权与服务端响应延迟飙升。

  • 客户端判定请求超时并自动触发重试。

  • 网关层根据既定策略同样向下游追加重试。

  • 呈几何级数叠加的重试流量,彻底挤占了负载均衡器与认证服务的全部可用带宽。

用户在 VS Code 里看到的只是一句“Copilot 登录超时”,而在服务端看来,这就如同几万名用户因为闸机稍慢了一拍,在几秒内疯狂连刷了几十次卡。

官方数据揭示了这一惊人事实:Copilot Token Service 日常请求量为 7–9K RPS,在重试叠加下被暴力推升至 70–100K RPS。整整 10 倍的畸形洪峰,直接让正在尝试恢复的服务再次过载。

此外,VS Code 内部存在一个潜伏的重试逻辑缺陷,当某个内部端点响应稍有延迟,编辑器便会进入快速循环补发,成为了阻碍恢复的核心堵点。

系统出现故障时,盲目的重试机制往往比原始缺陷更快拖垮整套架构。

跨区域调度与紧急止血手段

为了分流压力,GitHub 曾尝试将 Central US 的受阻流量切往 Northern Virginia 数据中心。

然而,跨区域调度只能改变请求的目的地,无法削减总调用量。数以百万计的客户端依然在以极高频率狂发重试,这股被放大了 10 倍的洪峰涌入新机房后,很快又给新的节点带来了沉重负担。

面对不断自我繁殖的恶性流量,GitHub 采取了数项强硬的阻断措施:

  • 紧急推送配置,在网关层大幅降低自动重试的频次。

  • 在负载均衡器层对部分 Copilot Token 请求直接返回 403 拒绝,强行截断客户端的重试死循环。

  • 分站点、小批量逐步放行流量,给后端留出充足的缓冲时间。

  • 同步暂停存在异常的 HAProxy 节点并完成状态恢复。

把盲目的重试流量完全压制住之后,整个服务集群才终于恢复平稳。

看完报告的几点体会

笔者作为每天都在使用 GitHub 的“麻瓜”开发者,读完这篇详实的官方复盘,还是发表一下感触吧:

  • 强如行业标杆,也会被微小的配置盲区绊倒:业务服务与代理容器没有联动扩容、客户端埋着一个偶发的重试死循环,平时风平浪静,一旦遇上业务高峰就会引发连锁反应。

  • 多机房调度并不是万能解药:面对失控的客户端重试风暴,单纯切机房只是把压力转移到另一个地方,甚至会迅速拖垮健康的备用节点。

  • 详实透明的复盘具有极高价值:GitHub 没有用一句含糊的“系统维护”带过,而是把完整的故障周期(7 小时 47 分钟)、各业务受损指标(API 20%、下载 50%)、10 倍流量放大数据以及具体的改进举措完整公开。这种复盘不仅能给用户明确的交代,也是极具参考价值的工程教材,这里就不得不提一下国内某大厂,简直是反着来,恶心!

日常开发的避坑建议

GitHub 的架构规模非常庞大,但这场事故里暴露出的问题,也许在咱们的日常业务开发中同样很常见。结合这次教训,在和 Claude Fable ”老师“ 一起讨论过后,总结了几个小建议 😆:

1. 写重试时,务必加上退避与随机抖动

在封装前端请求、调用第三方 API 或消费消息队列时,不要简单写一个固定次数的死循环重试。

当下游服务真正崩溃时,成千上万个客户端同时无间隔重试,等于在联手攻击自己的后端。务必给重试加上最大尝试次数、递增的等待时间(指数退避)以及随机抖动(Jitter),错开并发请求,避免形成共振。

2. 监控业务指标,不只看进程存活状态

很多时候监控看板上的 CPU、内存一切平稳,容器状态也全绿,但核心业务可能已经不可用了。

这次事故中大部分基础服务进程并没有挂,瘫痪的是最前端的鉴权通道。日常开发中,应将接口真实状态码分布(4xx/5xx)、核心业务成功率与 耗时作为第一梯队的告警依据。

3. 关注调用链条上的每一层代理限制

在现代架构中,请求到达业务代码之前往往要经过浏览器、Nginx 反向代理、API 网关以及各种辅助服务。

业务代码写得再快,只要前面的 Nginx 连接数超标或辅助服务代理并发被打满,请求在进入代码前就已经失败了。做压力测试和容量规划时,必须将整条网络路径上的各层代理限制一并纳入评估。

最后

看来,强如 GitHub 这样的顶级工程师团队依然会犯错。在复杂系统中,很多看似为了“保障可用性”而编写的重试与容错逻辑,在极端场景下极易异化为击垮系统的最后一把推手。

建立重试边界,管控调用放大。下一次在代码中执行重试时,值得多为系统的极限承载力多考虑一些异常情况。

还有一个挺逗的事情,故障发生时,推特上有条关于 500 报错页的高赞调侃:

GitHub 不应该用独角兽作为服务不可用页面的 UI 图片,因为独角兽几乎看不到,而 GitHub 经常挂掉。

调侃归调侃,其实每次 GitHub 出故障,都是一次近距离学习大型服务故障防护的好机会 😆。

好了,今天就到这里,大家下次见~


not-by-ainot-by-ai
已读 0%
文章推荐
文章封面
TypeScript 中的 never、unknown 的使用时机
更新于 2024-09-24
编程
文章封面
React i18n 浅解
更新于 2025-10-26
编程
GitHubTwitter / XMediumDevJuejin

友情链接

Jimmy
Jimmy
老胡
老胡
Submara
Submara
Bruce Song
Bruce Song
Scarsu
Scarsu
宇阳
宇阳
Steven Lynn's Blog
Steven Lynn's Blog
OJ·Jimmy (Other Jimmy)
OJ·Jimmy (Other Jimmy)
liruifengv - Web 开发者,Astro 项目成员,开源爱好者。
liruifengv - Web 开发者,Astro 项目成员,开源爱好者。