Polly-暂态故障处理和主动恢复工程

本文探讨了Polly如何通过重试、断路器、超时、批量头和缓存策略,为基于云的应用提供故障恢复和主动资源管理,以增强系统弹性和稳定性。这些策略包括在遇到网络问题时的自动重试、防止过度负载的断路器机制,以及预先管理负载以防止资源耗尽。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当今基于云、微服务或物联网的应用程序常常依赖不可靠的网络与其他系统进行通信。 由于网络问题和超时等短暂故障,或子系统离线、负载不足或无响应等原因,这样的系统可能不可用或不可达。 Polly提供的弹性策略提供了一系列应对瞬时故障的响应式策略,以及提高系统弹性与稳定性的主动预防策略。

通过重试和断路器处理瞬时错误

瞬时故障是指由可预期的临时情况引起的错误,如临时服务不可用或网络连接问题。

重试(Retry)

Retry允许调用方重试操作,因为许多错误是暂时的,可能会自我纠正:如果在短时间延迟之后重试,操作可能会成功。

在重试之间的等待是为了系统有时间自我纠正错误。诸如指数后退和抖动等实践通过调度重试来改进这一点,以防止它们成为更高负载或峰值的来源。

断路器(Circuit-Breaker)

断路器会检测调用时所发生的故障次数,并在超过可配置的故障阈值时阻止调用。

当想要通过重试来达到业务成功的目的时,如果此时子系统完全脱机或在高负载下时,此时重试不太可能成功甚至可能产生反效果,这时当前系统就会出错。

在这种情况下,再重试就不合适了,因为它们没有成功的可能性,甚至会给被调用的系统增加额外的负载压力。

除此之外,这还会导致进一步的后果:上游调用方失败。如果当前系统无法检测到下游系统不可用,它本身可能会排队等待大量的请求和重试。 然后,当前系统中的资源可能会耗尽或过度阻塞,一直在等待永远不会到来的响应。 在最坏的情况下,这可能会消耗大量资源,从而导致当前系统返回失败——这是一种上游级联失败。

因此调用方需要有办法检测和响应下游系统不是瞬时故障的情况。而断路器为这种情况提供了一种应对策略。

断路器是如何工作的?

断路器会检测调用时所发生的故障次数,并在超过可配置的故障阈值时阻止调用。

当故障超过阈值时,电路断路(开路) 。当断路器打开时,通过电路进行的调用,不是被执行,而是快速失败,立即抛出异常 。 (根本没有尝试调用。) 这既保护了严重故障的下游系统不受额外负载的影响,又避免了上游系统发出不太可能成功的调用。 相对于一直等待然后返回错误,在这种情况下快速失败通常也会给用户带来更好的体验。

经过一段时间(系统配置的时间段)后,电路进入半打开状态,在此状态下,下一个调用将被视为一次尝试,以确定下游系统的健康状况。 断路器根据这次尝试调用决定是否合路(恢复正常运行)或再次断路。

这与电气线路中的断路器类似:重大故障将“跳闸”电路,保护由电路控制的系统。

回退

Fallback策略定义了在基础操作失败时,即使重试或由于电路损坏,系统应该如何应对。与重试和断路器一样,回退策略是反应性的,因为它对定义的错误做出响应。可以使用回退策略为失败的呼叫返回提供替代的、预先设定好的响应或者更复杂的补救行为。

通过积极主动的、以稳定为导向的方法提高系统弹性

重试和断路器是恢复暂态故障的主要策略,但两者都是反应性的,因为只有在调用收到失败返回时他们才会生效。

但是,如果系统收不到响应——或者被拖延到我们不愿继续等待的程度,那该怎么办? 如果这种延迟——等待,等待做出反应——本身就会积累问题,那该怎么办? 我们能否在系统资源管理和弹性方面采取更积极主动的方法? 考虑到在高吞吐量系统中,在接收到第一个超时之前,可以将许多调用连接到最近发生故障的系统。 例如,如果对施加10秒超时的下游系统每秒进行50次调用,那么在接收到第一个超时之前,可以并行执行500次调用(假设没有其他限制)。 一旦收到足够多的故障,断路器就会对这种情况作出反应,但在此之前系统肯定会出现资源膨胀。

尽管Retry和Circuit-Breaker是被动响应式的,但Timeout、Bulkhead和Caching策略提供了先发制人的策略:它们通过显式地管理负载来提高高吞吐量系统的弹性以提高系统稳定性。

Timeout(超时)

超时允许调用方离开挂起的调用。 这一策略的主要好处是在通过在响应似乎不太可能时释放调用方来提高弹性和用户体验。

此外,正如上面示例所示,在一个有故障的高吞吐量系统中,选择超时策略的可能会影响资源消耗。考虑到线程或连接的阻塞(以及那些挂起的调用消耗的内存)这时候通常会导致进一步的系统问题,所以请考虑你希望让这些挂起的调用消耗系统资源多长时间。

Bulkhead(隔离仓)

超负荷是导致系统不稳定和故障的主要原因。因此,构建弹性系统包括显式地管理负载和/或主动地扩容以支持高负载。

负载过高可能是由于真正的外部需求(例如用户流量峰值),也可能是由于前面描述的大量调用拥堵的故障场景。

舱壁策略通过直接管理负载以控制资源消耗来提高系统稳定性。 Polly Bulkhead是一个简单的并行节流器:它限制了通过它放置的调用的并行性,可以选择排队和/或拒绝多余的调用。

舱壁的隔离

舱壁是船上可以与其他部分隔离的部分。如果船在一个地方破洞了,然后把这个舱壁 密封了,其他部分就不会淹水,整个船就不会沉。

类似地,在一个调用流周围放置隔离策略(并行性限制),可以限制调用流可以使用的资源。如果该流出现故障,它将无法消耗主机上的所有资源,也就不会导致整个主机宕机。

舱壁作为负载隔离和相对应的资源分配

同一应用进程中还可以使用多个隔离策略,以实现负载隔离和相关资源分配。

这里有一个很好的比喻:超市或杂货店的结账通道:通常有单独的通道,只允许“购物篮”(或“8件或更少的商品”),而不是满满当当的购物车。例如,两条车道可以分配给“篮子专用”,而六条车道可以分配给满载的手推车。

这种隔离让那些只带篮子的人总能快速结账。如果不这样做,他们可能就没有选择,只能在满满的购物车后面排队等待。

使用多个隔离策略来分离软件操作提供了类似的好处,无论是在为不同的调用流分配相对应资源方面;还是在保证一种功能不会过多占用了资源而影响另一个功能 (甚至导致另一个功能无法使用)。

舱壁用作负载消减

隔舱策略也可以用于在达到一定负载时主动切断额外负载(拒绝调用)。

当主机可能还有更多容量可以使用时为什么要主动拒绝调用呢? 答案:这取决于你喜欢管理失败还是不管理失败。 这些明文规定的限制(同时设置这些限制以充分利用可用资源)使您的系统能够以可预测的、可测试的方式失败。让系统无界并不意味着他的负载没有极限:它只是意味着你不知道极限在哪里;相反,这样会使你的系统容易出现不可预测的、未知的故障。

舱壁用作扩展的触发器

虽然负载削减是一种强大的主动恢复实践,可以抢占资源耗尽的先机, 这当然不是对日益增长的负载的唯一处理方式。 监控隔板利用率或队列大小以便在需要时增加系统资源(水平扩展)的触发器,就像超市可能在需求高的时候开设额外的通道一样。 这里的关键是检测不断增长的负载不单单是对调用故障的响应:需要同时监视负载和故障率。

用一个航空公司离港大厅的比喻来概括舱壁的不同方面:在符合过大时第一反应可能是水平扩展(打开另一个柜台),但如果所有空间已经耗尽(所有通道都已使用)后负载仍过大(候机大厅有太多的人),通过预先及计划主动进行负载削减(问一些人在外面排队)总比没有计划要好些,如果不处理则有可能出现潜在的更危险的失败(比如,候机室人满为患的危险)。

缓存

任何可以削减网络流量和整体调用时间的方法都可以提高系统弹性并改善用户体验。 如果您可能已经知道答案,那么利用缓存就可以完全不进行调用或从附近的网络资源获取答案。

缓存策略可以与多个缓存结合使用——内存/本地缓存和分布式缓存。Polly CachePolicy支持使用PolicyWrap在同一个调用中调用多个缓存。

回退(Fallback)

虽然前面已经介绍过回退策略,因为它确实是一种响应性策略,但既然我们现在在介绍所有的弹性策略,所以现在有必要在回顾一下它。

无论系统的弹性设计有多好,故障仍可能会发生。回退意味着规定发生故障时要做的事情:为失败制定计划,而不是让它对系统产生不可预知的影响 。

翻译自Polly-Wiki:Transient fault handling and proactive resilience engineering · App-vNext/Polly Wiki · GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值