GitHub 这次 7 小时 47 分钟事故,最值得抄进自己系统的不是“多加机器”,而是先把 Retry Loop 关进笼子

GitHub 昨天公布了 8 月 17 日事故复盘。

这次事故持续 7 小时 47 分钟,影响了 github.com、认证、GitHub Actions、API、Pull Request、Issue 和 Copilot。

表面看,这是一个很典型的容量事故:Central US 数据中心里的关键基础设施组件,在新的流量峰值下没有及时扩容,压力随后扩散,认证和多个服务一起受到影响。

真正让我觉得特别值得 AI 工程团队看的,是恢复阶段的另一个细节:

部分 Copilot 服务在恢复时出现了客户端 Retry Loop,错误请求持续重试,反过来继续增加恢复阶段的流量。

也就是说,原始故障还没完全消失,客户端又制造了一轮“自激流量”。

Agent 系统尤其容易踩这个坑,因为它天然比普通 Web 服务有更多重试层。

一次“善意重试”为什么会变成二次故障

正常状态:

1000 req/s

如果下游突然有 40% 请求超时,而每个失败请求最多重试两次:

原始请求:1000
第一轮失败:400
第一轮重试:400
其中再次失败:160
第二轮重试:160

系统瞬间已经接近:

1560 req/s

如果下游本来就是因为容量不够才失败,这些请求不是“恢复机制”,而是继续把剩余容量挤掉。

更危险的是,生产系统里重试很少只有一层:

SDK Retry
业务 Retry
消息队列 Retry
Agent Step Retry
用户手动重试

五层叠在一起,一个请求很容易被放大十几次。

我现在会给 Retry 单独做预算

只写:

retry:
  max-attempts: 3

不够。

我更愿意加:

retry:
  max-attempts: 2
  retry-budget-ratio: 0.08
  backoff: exponential
  jitter: true

max-attempts 控制的是单个请求。

retry-budget-ratio 控制的是整个系统在一个时间窗口内,额外重试流量不能超过正常请求的 8%。

这是两个完全不同的问题。

十万个请求同时失败时,前者几乎救不了你,后者才开始有价值。

Agent 还有一个普通 Web 服务没有的放大器:Loop

一个用户请求可能长这样:

User
↓
Router
↓
Planner
↓
RAG
↓
Tool A
↓
Tool B
↓
Reviewer
↓
Final Model

表面上是:

100 req/s

内部可能变成:

700—1500 次模型和 Tool 调用

某个 Prompt 一改,Reviewer 从两轮变成八轮,用户 QPS 没变,内部负载却直接翻几倍。

所以我越来越建议监控:

model_calls_per_run
tool_calls_per_run
steps_per_run
retry_per_run

而不是只看入口 API QPS。

一个很有用的指标:Amplification Factor

定义:

内部调用总数
/
用户请求数

例如:

1 万次用户请求
→ 7.8 万次模型调用
→ 3.2 万次 Tool Call

模型放大系数:

7.8×

Tool 放大系数:

3.2×

如果一个新版本上线后,模型放大从 7.8× 变成 12.4×,即使用户没涨,基础设施也可能突然过载。

这个指标特别适合发现“Agent 变得更啰嗦、更喜欢循环”的问题。

GitHub 这次的增长数字也很值得看

GitHub 自己披露,从 4 月到现在,月 Commit 已经从:

14 亿

增长到:

29 亿

接近翻倍。

GitHub 同时明确说,这能解释压力,但不是事故的借口。

我很喜欢这句话。

很多系统出问题后的第一反应是:

“最近用户涨太快。”

可容量规划的职责本来就是应对增长。

真正应该问的是:

关键组件为什么没有提前扩容?
哪一个组件不能水平扩展?
Capacity Forecast 为什么没看到拐点?

AI 应用更容易低估真实容量

因为容量单位不能只用 QPS。

还需要:

Token / sec
Tool Calls / sec
Concurrent Runs
Queue Depth
Context Size
Retry Rate
Fan-out

两个同样 100 QPS 的 Agent:

A:

每个请求 1 次模型调用

B:

每个请求 9 次模型调用

完全不是一个容量等级。

恢复阶段不要瞬间切回 100%

GitHub 的恢复方式包括:

Reroute Traffic
Isolate Infrastructure
Restore in Stages

我觉得“Restore in Stages”特别重要。

AI Provider 恢复以后,不要:

0% → 100%

更合理:

5%
↓
15%
↓
30%
↓
60%
↓
100%

每一阶段观察:

Error Rate
P95
429
Queue Depth
Retry Rate

健康检查变绿,不代表系统已经能吃满全部积压流量。

为什么恢复阶段比正常阶段更容易过载

故障一小时以后,系统会积累:

  • 消息队列;
  • Scheduled Task;
  • 用户手动重试;
  • Webhook;
  • Batch;
  • Cache Miss;
  • 延迟任务。

服务一恢复:

Backlog
+
正常新流量

一起冲进来。

所以恢复阶段通常需要专门的:

Queue Drain Rate

例如:

recovery:
  normal-workers: 100
  recovery-workers: 130
  max-queue-drain-qps: 1200

只比正常速度高一点,慢慢排空。

否则恢复动作本身会变成第二次压测。

GitHub 已经加了很多资源,但“加机器”并不是全部答案

GitHub 说,今年已经增加超过:

300 万 CPU Cores
120 PB High-speed Storage

同时加速向 Azure 迁移。

当前 Azure 已承载大约:

58% GitHub 平台负载
50% Git 操作

而 5 月平台负载还只有 12%。

这已经是巨大的基础设施扩展。

但 GitHub 仍然强调要继续消除:

architectural bottlenecks

原因很简单。

一个全局锁、单一 Metadata Service、集中认证依赖,再多机器也不一定解决。

Agent 平台也很容易造出全局瓶颈

典型的:

单一 Tool Registry
单一 Approval Service
单一 Budget DB
单一 Session Store
单一 Prompt Config Service

每个 Run 都经过它。

平时看起来很稳定,一到流量峰值就成为整个系统的共享故障点。

这些 Control Plane 组件同样需要:

缓存
分区
只读副本
降级策略
Fail Open / Fail Closed 设计

Authentication 往往是最危险的共享依赖

GitHub 这次容量压力传播后,认证失败影响了多个服务。

企业 Agent 也一样。

如果每个 Tool Call 都要实时访问中央 Authorization Service,一旦授权服务 P95 从 20ms 涨到 3 秒:

所有 Agent Step 一起卡住

可以考虑:

Signed Capability Token
Short-lived Credential
短期 Authorization Cache

降低每一步都回中心服务的压力。

高风险撤权再用更严格的失效机制。

我会提前写一张 Degradation Matrix

不是所有依赖挂了都应该返回 500。

依赖故障 降级方式
强模型不可用 低风险任务切备用模型
Vector DB 慢 减少 TopK 或关闭非关键 RAG
Judge 不可用 低风险继续,高风险暂停
Analytics 挂 主业务继续
Tool Registry 慢 使用短期缓存
Approval 挂 高风险写操作暂停
Audit 挂 高风险 Fail Closed

事故发生时再临时决定,通常来不及。

最值得主动演练的是“故障越大,请求越多”

我会在测试环境直接制造:

Provider 50% timeout

然后观察:

客户端 QPS
SDK Retry
Server Retry
Queue Depth
模型调用量

最关键的问题不是“系统能不能重试成功”,而是:

失败 10 分钟以后,系统内部流量是下降了,还是上升了?

如果故障越严重,QPS 越高,说明 Retry 设计有问题。

Chaos Test 可以很简单

Scenario 1:
10% 503

Scenario 2:
30% Timeout

Scenario 3:
429 + Retry-After

Scenario 4:
Dependency Slowly Recovers

Scenario 5:
Queue Backlog + Provider Recovery

每个场景检查:

是否自动降载
是否触发 Circuit Breaker
是否限制 Retry
是否平滑恢复

Circuit Breaker 不要只看“连续失败次数”

Agent 调用本身可能很慢。

如果等:

连续 20 次失败

才熔断,也许已经过去几分钟。

更适合用:

滑动窗口错误率
Timeout Rate
429 Rate
P95

例如:

circuit-breaker:
  window: 30s
  minimum-calls: 50
  open-if-error-rate: 0.35
  open-if-timeout-rate: 0.20

最后一个我会从 GitHub 事故里带走的指标:Recovery Amplification

定义:

恢复阶段总请求量
/
同时间正常基线请求量

如果长期看到:

2.5×
3.2×

说明恢复阶段有大量 Retry、Backlog 或同步行为需要治理。


这次 GitHub 事故持续 7 小时 47 分钟,根因是容量。

但对 Agent 工程最有启发的细节,是那条:

Copilot client-side retry loop
increased traffic during recovery

Agent 系统天然比普通应用有更多重试、循环、Fan-out 和异步任务。

只要其中一个没有预算,故障就很容易自我放大。

所以现在我看一个生产 Agent 系统,除了问:

正常情况下能跑多少 QPS?

还会再问一句:

当下游已经坏了,你的系统会自动变安静,还是会更疯狂地请求它?

后一个问题往往更重要。


更多企业级 AI 应用、Agent、RAG 与模型工程化内容,我会继续整理在 智元界

https://www.zyentor.com/