hello!大家好!
上周五晚上九点半左右,我坐在电脑前正准备把一个功能分支合并进主分支。
在网页上点下 Merge 后,浏览器顶部那条蓝色的进度条卡在中间不动了。过了几秒,整页直接跳出一片空白,随后返回了 500 错误。我顺手强制刷新页面,依然无法加载。
第一反应是以为本地网络代理出了问题,我随手新开了一个标签页刷了下某个屎黄色站点,视频秒开,网络非常顺畅。再切回 VS Code,右下角 Copilot 图标也悄悄亮起了无法连接的提示。
这时候在技术交流群里已经有人开始发截图问:“GitHub 是不是挂了?”。然而群里的反馈并不一致:有的朋友说完全打不开,有的朋友却说自己拉取代码一切正常。推特时间线上也有不少开发者陆续晒出 500 报错页面。
大家一边在群里发表情包,一边排查到底发生了什么。这种“部分地区能用、部分地区报错”的半瘫痪状态持续了很久。部分用户的 PR 无法合并、CI/CD 停滞,VS Code 里的 Copilot 也频频断连。
一直到第二天早上,经历了整整 7 个多小时的局部震荡后,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 等桌面客户端。
这种“有人正常、有人全挂”的局部异常,反而让排查变得更加扑朔迷离。
梳理官方报告可以发现,整场事故的源头来自一个容易被忽视的网络代理配置盲区:
Sidecar 代理触及并发上限:Central US 数据中心遭遇流量高峰,负责内部网络路由的单个 Istio sidecar pod 达到了并发连接上限。举个例子,就好比一个业务窗口虽然大门敞开,但门前的专用安检通道已经挤满了人,流量大到挤满通道,没法疏导。
自动扩容指标未联动:自动扩缩容策略(HPA)当时只盯住了宿主业务服务的 CPU 和请求指标,未把 Sidecar 代理的并发负荷算进去。系统误以为容量充足,未及时启动弹性扩容。
关键节点连接耗尽:局部的网络阻塞迅速扩散,直接导致上游 4 个关键 HAProxy 节点耗尽了连接与流量配额(flow limit)。
认证通路大面积变慢: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 ”老师“ 一起讨论过后,总结了几个小建议 😆:
在封装前端请求、调用第三方 API 或消费消息队列时,不要简单写一个固定次数的死循环重试。
当下游服务真正崩溃时,成千上万个客户端同时无间隔重试,等于在联手攻击自己的后端。务必给重试加上最大尝试次数、递增的等待时间(指数退避)以及随机抖动(Jitter),错开并发请求,避免形成共振。

很多时候监控看板上的 CPU、内存一切平稳,容器状态也全绿,但核心业务可能已经不可用了。
这次事故中大部分基础服务进程并没有挂,瘫痪的是最前端的鉴权通道。日常开发中,应将接口真实状态码分布(4xx/5xx)、核心业务成功率与 耗时作为第一梯队的告警依据。
在现代架构中,请求到达业务代码之前往往要经过浏览器、Nginx 反向代理、API 网关以及各种辅助服务。
业务代码写得再快,只要前面的 Nginx 连接数超标或辅助服务代理并发被打满,请求在进入代码前就已经失败了。做压力测试和容量规划时,必须将整条网络路径上的各层代理限制一并纳入评估。
看来,强如 GitHub 这样的顶级工程师团队依然会犯错。在复杂系统中,很多看似为了“保障可用性”而编写的重试与容错逻辑,在极端场景下极易异化为击垮系统的最后一把推手。
建立重试边界,管控调用放大。下一次在代码中执行重试时,值得多为系统的极限承载力多考虑一些异常情况。
还有一个挺逗的事情,故障发生时,推特上有条关于 500 报错页的高赞调侃:
GitHub 不应该用独角兽作为服务不可用页面的 UI 图片,因为独角兽几乎看不到,而 GitHub 经常挂掉。
调侃归调侃,其实每次 GitHub 出故障,都是一次近距离学习大型服务故障防护的好机会 😆。
好了,今天就到这里,大家下次见~
