Uber 工程团队在官方博客中详解重试风暴的成因:单点故障沿深层调用链被逐跳重试放大,最终演变成全站级事故。除了现有的重试预算机制,Uber 提出用"错误归属"区分症状与病因,让系统判断该由哪个节点重试、哪个节点该放弃,把重试风暴的影响范围限制在故障源附近。文章配图显示,该机制曾在一次重大服务降级事件中拦截950万次多余请求。
一次请求沿 A→B→C→D→E→F→G 的调用链向下传递,如果下游某服务(比如 D)开始报错,且每一跳都配置"失败重试一次",总请求量会随调用链深度呈指数级增长,可写成公式 Rᵈ×Ƞ(R 为重试次数,ɗ 为节点深度,Ƞ 为原始请求量)。故障哪怕只发生在 D 一个节点,A、B、C 的每次重试都会把请求量层层放大,一路压向 E、F、G,最终把局部故障推成全站级事故——这就是重试风暴(retry storm)。
Uber 官方工程博客指出,问题根源在于重试行为"不感知上下文":系统能控制重试次数,却难以判断该何时重试,因为很难区分错误是服务自己产生的,还是从下游传递上来的。结果重试被无差别套用在所有错误上,服务中度或严重降级期间,会让下游雪上加霜。
Uber 现有手段是"重试预算"(retry budget):给每一跳设置重试上限比例 B,把请求量增长公式压低到 (1+B)ᵈ×Ƞ,从指数级变成线性可控。以 10% 预算为例,只允许故障处(NodeD)与其直接调用方(NodeC)之间重试,同时禁止 NodeA、NodeB 跟着重试,能保住链路可用性又不压垮下游节点。
但这类配置需要人工设定,缺乏对跨服务放大效应的可见性,依赖链越深越难靠人工调参兜底。测算显示,下游可用性下降到一定幅度后,重试带来的可用性提升会打折;服务过载、数据库宕机、分片故障这类场景里,重试未必能换来恢复,单靠重试预算并非彻底解法。
Uber 的核心思路是"错误归属"(error ownership),用症状与病因作类比:一个服务若因下游报错才返回错误,它本身只是"症状",病因在下游;若所有下游调用都正常,它却依然返回错误,这个错误就该算它自己头上。
围绕这个判断,Uber 用内部 Service Dependency Analysis 方案关联入站失败与对应的出站失败,按规则判定错误该"认领"给谁,调用方据此决定是否重试。第一个发现下游"没有认领错误"的节点会主动放弃重试资格,把风暴影响范围限制在离故障最近的几跳,仍保留对出错服务的重试。
Uber 在文章配图中给出了这套机制的实际效果:一次重大服务降级事件中,该机制拦截了950万次多余请求。

图:Uber 工程博客配图展示的调用链与错误归属机制,标注该机制在一次重大降级事件中拦截了950万次多余请求,来源:uber.com
博客原文之后进入"决策矩阵"与"巧合性错误"两节,但原文在此处被截断,Uber 尚未说明该机制是否已推广到全部服务。
免费获取企业 AI 成熟度诊断报告,发现转型机会
关注公众号

扫码关注,获取最新 AI 资讯
3 步完成企业诊断,获取专属转型建议
已有 200+ 企业完成诊断