大规模微服务系统中的雪崩故障防治
导读
在大规模微服务架构中,雪崩故障是极具破坏力却又难以预防的系统性威胁。本文基于百度搜索架构与运维团队的实战经验,深入解析雪崩从“非稳态”到“自强化崩溃”的微观演化机制,揭示重试风暴、容量退化等正反馈回路的形成过程。文章提出系统化的治理思路,并详细介绍百度落地的多项核心实践,包括重试预算、队列限流、全局TTL控制等自愈机制,以及秒级流量调度与降级预案。通过真实案例与生产数据,为行业提供了一套可借鉴的雪崩预防与治理框架。
说明:本文是由2025 SRECon会议的《Preventing Avalanche Failures in Large-Scale Microservice Systems》的演讲者翻译并整理而成。
01 摘要
大规模微服务系统在享受分布式架构带来的灵活性和扩展性的同时,也面临着雪崩故障的严重威胁。雪崩是一种系统性故障模式,破坏力极大,难以预防,会给企业带来巨大损失。
本文深入分析雪崩的形成机理和演进模式,建立理论模型,从微观层面推导灾变过程,并通过真实生产案例验证了雪崩的快速演化路径。接着,通过系统化的思辨,探讨可能的治理方法。然后,介绍了百度的系统性的雪崩治理框架及一系列的核心实践机制。最后总结了近几年的治理成果,为行业提供了可借鉴的实践经验。
02 背景
大规模微服务系统本质是一张由大量节点和依赖交织而成的网络。请求从入口gateway进入系统,再层层向下形成深度调用链,往往还伴随着交叉依赖与高扇出。这种特点虽然带来了灵活性与扩展性,但天然埋着三类稳定性风险:其一是“未知中的未知”,如冷门链路、冷门代码在突发场景被激活;其二是容量级联风险,任一节点变慢都会把反压沿链路放大回传;其三是重试风暴,自我强化的流量会指数级扩散。在这种架构中,任何局部抖动都会以毫秒级在系统中传播。理解这张网络,就为理解‘雪崩’发生的原因奠定了基础。
大规模微服务系统依靠多种高可用机制来提升性能,表现为:
-
分布式架构避免单点故障并带来弹性扩展能力;
-
缓存抵挡流量激增并降低延迟;
-
重试实现瞬时恢复并提高成功率;
-
请求队列平滑流量尖刺并维持稳定吞吐量。
然而,在雪崩条件下,同样的机制会翻转到另一面,表现为:
-
分布式架构引入复杂依赖和更大的爆炸半径;
-
缓存失效引发流量洪峰和延迟激增;
-
不受控的重试导致指数级流量风暴;
-
后端变慢导致队列超时和入队失败。
03 直观感受雪崩的威力
这里举一个真实的例子给大家直观感受雪崩的威力。在一个IDC中,少量实例出现轻微健康退化,引发中等程度的延迟上升和轻微的可用性下降——没什么令人担忧的,只是典型的小波动。几乎同时,随着上游重试机制启动指数退避策略,流量迅速激增,导致服务在几秒内变得不可用。
然后,根据预定义的SLA执行自动预案,将大量负载从受影响的IDC转移到其他健康的IDC。但这些"健康"的IDC,只能在正常容量范围内运行,此时突然遭受显著的放大了的流量冲击,也变得过载。
紧急扩容马上被触发,扩充并启动更多的实例,但级联过载的蔓延的速度仍然比我们扩容策略的响应速度更快。
紧接着,多项尝试止损的动作被并行执行——流量比例调整、缓存命中率优化、超时时间缩减——然而它们在呈指数级的故障放大效应面前仍然无效。此刻,系统处理的主要是重试流量,其数量远超设计容量,线程池完全耗尽,请求队列被已超过SLA阈值并且注定要失败的请求填满。
这进一步引发了所有IDC的级联故障,最终导致系统级的完全崩溃,影响了大量用户。
在这个案例中,起初只是一个影响了少量实例的小问题,最终演变成了完全的系统崩溃。整个过程在仅仅2分钟内发生——这是大规模微服务系统在雪崩场景下如何自我毁灭的可怕呈现。
04 雪崩的特点
以上,我们直观感受到了雪崩的威力。那么,什么是雪崩?让我们从4个雪崩的特点来介绍雪崩。雪崩发生前,系统都会首先进入“非稳定”状态,这种状态“貌似正常、实则脆弱”。各项指标也许还在阈值内,但可用余量极少,表现为:负载上升,延迟上涨……此时的系统对扰动极为敏感,任何轻微扰动都会使它偏离稳定状态。
第二个特点是需要小的触发源扭转状态。触发源可能是多种多样的,比如,流量尖刺、网络瞬时抖动、硬件故障、软件冷门逻辑被触发……。它们本身并不致命,但在不稳定状态边缘,哪怕微小的触发都足以把系统推过临界点。真正导致系统边界违规的不是触发的强度,而是系统自身余量不足。然而,微小触发仍然是必要条件。
一旦越过临界点,系统会迅速进入自强化阶段,这是雪崩最典型的一个特点。在这种情形下,高可用优化机制统统都站到了反面。系统每增加一点恶化,高可用机制就产生一些正向反馈,从而导致进一步恶化。这条恶化-反馈循环持续加强,复杂且迅速。图中展示了几个例子。回路一:请求失败导致重试,然后导致负载上升,进而导致更多失败,最终形成指数级的重试风暴;回路二:少量实例略不健康导致被摘除,然后导致剩余实例更忙,进而导致更多实例被判不健康,最终引起容量指数级退化;回路三:错误事件导致大量的日志和监控,然后导致I/O用量上升,进而导致更多错误,最终使性能进一步恶化。
随着自强化阶段的持续,系统很快进入到失控和崩溃状态,这种状态最大的特点是无法靠自身恢复。线程池被耗尽,请求队列被已超时或必然失败的请求塞满,后端被无意义工作占满并拖慢,上游开始全面超时。
常见修复措施并不能奏效,甚至适得其反。比如,临时扩容往往慢于正反馈的加速导致资源就绪时系统早已熔毁,调cache难以解决重试反馈带来的流量放大,等等。需要专用的机制才能缓解,就像不能灭火器扑灭一颗正在爆炸中的核弹。唯有改变微观机制上的反馈结构,才能真正抑制雪崩。
让我们简要回顾雪崩的4个特征来理解雪崩的定义:
-
非稳态:系统看似正常但余量极少,对扰动高度敏感;
-
微小触发:流量尖刺或网络抖动等轻微扰动就能推动系统越过临界点;
-
自强化:高可用机制创建正反馈循环,通过重试风暴和容量损失放大恶化;
-
无法自我恢复:系统崩溃,资源耗尽。常见修复措施适得其反,需要专门干预。
05 理论模型
让我们从微观层面看一下雪崩。首先,我们看一个基本的模型。在这个模型中,流量以rps的吞吐流经一个服务的请求队列;然后,该服务的workers以concurrency的并发度处理队列中的请求,并发向后端进一步处理。在正常情况下,发向后端的吞吐也是rps。从请求到达本服务到本服务处理完成,所用的时间是latency。
基于Little's Law,我们有这样的公式:rps <= concurrency / latency。
真实的系统可以看做基础模型的管道似的级联连接。在这套连接系统中,需要保持任意位置的吞吐在实际流量之上,即在任意位置,都要维持这个rps <= concurrency / latency式子满足。
整个系统的吞吐受限于最薄弱的环节。需要精心地维持各环节脆弱的平衡。若任何位置的平衡哪怕短时间被打破,也会迅速触发级联反应,使系统雪崩。
06 微观灾变过程
接下来,让我带大家从微观层面看一下雪崩过程发生了什么。在这个抽象例子中,拓扑结构为 gateway → A → B → C,其中服务C变慢并成为触发点。
这张图使用“状态聚焦”的视角展示雪崩的快速微观演化过程。首先说明图中颜色的含义:红色代表恶化;灰色表示此阶段暂无新增变化。我们仅高亮当前需要重点关注的信号。
-
在健康状态下:系统延迟低,排队最少,吞吐量最优。
-
在触发阶段:C开始变慢,其延迟明显上升。
-
随着问题扩散,B和A的线程利用率和延迟几乎同时激增,而吞吐量和队列长度保持相对不变,显示出典型的’严重积压前的快速传播’行为。
-
随即来到堆积阶段:当并发达到上限后,B 和 A 的队列开始快速堆积,表明排队机制已被触发。
-
很快系统进入重试状态,B的超时触发上游重试。B接收到更多流量,而好吞吐比例下降,显示服务质量正在恶化。
-
接下来,流量开始放大,gateway级重试被触发,在A处造成流量激增,在B处造成第二次流量激增。对B产生的压力导致好吞吐进一步下降。
-
最终迅速坍塌到雪崩阶段:重试的重试形成正反馈循环,线程与队列被大量无效工作占满,系统彻底崩溃。
请注意三个关键点:线程利用率首先增加,队列长度快速跟进,吞吐量表现出两次或更多的快速跃升。
07 真实案例验证
让我们用真实的生产数据来验证前面的模型。由于这个故障发生在几年前,我们现在展示的这些指标是当时能够获取到的最完整的一组,尽管未能把前面模型里提到的所有指标都收集到。左边这个小图把B的总时间拆成了三部分:排队时间、本地处理时间、以及后端时间;右边的三张曲线的时间轴是对齐的。
这次故障仍然是C变慢了。首先,B的后端时间、整体延迟、线程使用量几乎同时抬升,与此同时,A的整体延迟也开始上涨。紧接着,B的排队时间开始上涨,很快,A的排队时间也跟着抬头——这正对应前一页的“扩散到堆积”的阶段转换。
接着我们发现一个有趣的现象:B的本地处理时间不增反降。其实原因很简单:线程更多时间在等后端返回,CPU空出来了,局部被处理到的请求就显得更快,这是常见的“局部变快错觉”。
再看吞吐曲线:A和B的RPS先出现一次阶跃,这是gateway的重试流量被激发;随后B的RPS再次跃升,这是A触发了二次重试。虽然我们没有直接画出“重试率”和“好吞吐占比”,但“排队时间增长”和“RPS两次阶跃”的组合,足以验证雪崩过程中由重试的驱动的故障放大路径。
整个过程大约发生在三分钟之内。
08 系统性思辨
既然我们理解了什么是雪崩以及它们在微观机制层面是如何工作的,让我们采用系统性方法来分析我们的选择。我想通过一个结构化的框架带着你来思考。在这个框架中,我们将检查雪崩的每个特征,并问:“我们能在这里干预吗?”通过这种系统性分析,我们能发现应该在哪些地方进行发力,以及哪些方法是现实的而非理想化的。
首先,是非稳态的避免。对于大规模分布式系统来说,完全避免非稳态是不现实的。系统本质上是面临无限触发源的复杂网络,其中HA机制更是一把双刃剑。它们从根本上是具有内在不稳定性的脆弱管道的级联。
尽管如此,我们仍然可以通过一些措施提升系统进入不稳定状态的阈值,使其更难进入不稳定状态,在面对更多触发源时能从容地运行。
接下来,我们思考能否消除所有触发源。实际上,这是完全不可行的。触发源对应的是一个无限的开放空间,不可枚举——包括网络抖动、流量尖刺、软件缺陷、硬件故障以及无数其他不可预测的因素。
虽然我们可以通过设计冗余机制来减轻干扰对系统稳定性的影响,但这种方法有两个主要局限性:首先是巨大的成本。例如,在网络基础设施层实施冗余链路聚合,在数据中心基础设施层面建设多套制冷系统,等等。而且,建设冗余机制往往涉及跨职能基础设施工程工作,实施困难且超出SRE的职责范畴。
接下来,我们能否消除自强化反馈回路呢?不可行!因为这些回路与HA机制内在相关,迫使我们必须做出权衡。
然而,将缓解机制嵌入到反馈回路内部,通过改变微观层面的反馈结构,可以将指数级放大转化为线性、可控的影响,大大降低其破坏力。就像用控制棒来阻止核反应中失控的中子放大。
最后,我们来探讨能否防止系统崩溃。这是可行的,主要通过两种互补的方法:最大化可用吞吐量与构建弹性恢复机制。即使系统超越临界阈值,我们仍可通过建立内部容错机制与外部干预预案,避免系统全面崩溃,并为系统创造多次恢复机会。
经过以上分析,我们发现可以在这些关键点实施雪崩治理工作,如右图所示。接下来,我们将详细介绍我们的核心实践。
09 我们的实践
前面说过,由于触发源众多,无法逐一验证系统在各种触发源下的行为,因此我们将所有触发源抽象为有限的几类场景,确保系统在这些场景下保持稳定——最大限度保持好吞吐。
这些场景分为两个维度:第一个维度是流量压力:包括流量逐步上升和瞬时激增。第二个维度是系统容量变化:包括绝对容量减少(如服务下线)和相对容量退化(如响应变慢)。
针对这四类场景,我们直接在生产环境中进行系统化验证:对于流量风险,我们在生产环境执行全链路压测,模拟流量的渐进式增长和瞬时尖刺。对于容量问题,我们在生产环境开展混沌工程,在真实环境下模拟服务容量缩减和延迟注入。
通过生产环境验证,我们提前发现潜在风险,确保系统在雪崩场景下保持最大可用吞吐的预期行为,结果可信且能代表实际系统性能。
早期检测对雪崩预防至关重要。我们建立了全面的监控系统,跟踪先导指标:
-
端到端失败数量
-
所有服务的通用指标,包括实例健康状态、实例CPU/内存/磁盘/IO利用率,以及coredump计数,等等
-
核心服务关键指标:包括请求队列长度、线程利用率、分位点延迟,等等
-
分片服务:分片丢失率
所有指标都是以秒级实时进行监控,并建立预警策略,使我们能第一时间感知到异常。
我们对系统自身的改进是建设一系列的"自愈"能力。首先是"重试预算",用于在client侧就地收敛重试风暴。每个请求携带"全链路重试状态"信息,RPC组件据此识别两类重试:直接重试(本服务对下游)与间接重试(上游祖先节点发起)。RPC组件维护一个"预算池",对两类重试流量配置不同的预算阈值,超过预算即快速失败。预算策略会随后端服务容量自适应调整,以充分使用后端容量。该机制把自增负载限制在可控范围内,避免指数级扩散。
在服务器端,我们还构建了一个称为“队列限流”的吞吐保护机制。我们将服务侧的请求队列做成多级优先级队列,并设置限流器。请求入队前先经过优先级过滤,在拥塞时,高优先级的请求允许通过,低优先级的请求被丢弃;限流器则根据实际处理速率自适应放行,同时,对于队列中超时的请求也会及时排出。在server侧容量到达瓶颈时,这套机制让有限的算力用于处理“好吞吐”。
我们也在系统中建设了更精细化的减少无谓的算力浪费的机制,即,全局TTL控制。每个请求在入口获得初始TTL,并随着请求在全链路传递;在各处理阶段结束后,按实际消耗的时间扣减TTL,并判断剩余值。若剩余TTL仍然大于0,则将这个新TTL作为后续阶段的TTL继续传递;否则,立即在此位置结束并返回。
虽然自愈机制已经将雪崩风险降至非常低的水平,但我们仍然为极其罕见的雪崩场景设计了多维度的秒级干预系统。
第一个维度是跨数据中心流量切换。我们实时监控多个敏感指标,当发生异常时,全局流量控制器在一秒内将流量从受影响的IDC迁移到其他IDC。
第二个维度是系统流量降级。流量分为不同等级,非用户流量(缓存刷新、预取等)按层级逐步减少直至关闭,为更高价值的用户请求让路。
第三个维度是架构裁剪。服务被分为不同级别(L2:低价值召回,L1:精确排序,L0:核心召回)。当损失发生时,我们做出秒级决策并按优先级逐步关闭服务级别。
第四个维度是超时套餐切换。多套系统级超时套餐根据损害程度自动适配,在吞吐和质量之间精妙地平衡。
10 治理结果
最后总结一下我们在治理雪崩上的成果。几年前,雪崩给我们的系统带来了比较多的PV损失,经过以上深入分析和系统治理,近几年完全没发生过雪崩,并且也几乎没有雪崩引起的PV损失。