-->

左耳听风_049_48_弹力设计篇之熔断设计

你好,我是陈浩网名左耳朵耗子。

那这节课呢我们来讲熔断设计熔断机制这个词呢对你来说肯定不陌生,它的灵感来源于我们电闸上的保险丝。

那电压有问题的时候自动跳闸。

那这个时候呢电路就会断开,我们的电器呢就会受到保护,不然呢就会导致电器被烧坏。

那如果人没有在家,或者人在熟睡中呢还会导致火灾。

所以在电路世界呢通常都会有这样的自我保护装置。

同样在我们的分布式系统设计中啊,也应该有这样的方式。

你前面说过重试几释,那如果错误太多了,或者在短时间内得不到修复,那么我们重试啊也没有意义了。

那此时呢应该开启我们的熔断操作,尤其是后端太忙的时候,使用熔断设计呢可以保护后端不会过载。

那熔断器模式啊可以防止应用程序不断的尝试执行,可能会失败的操作,使得应用程序继续执行,而不用等待修正错误,或者浪费CPU时间去等待长时间的超时产生。

那熔断器模式呢也可以使应用程序能够诊断错误,已经修正了。

那如果已经修正了应用程序,会再次尝试调用操作。

那换一句话来说呢,我觉得熔断器模式啊就像是那些容易导致错误操作的一种代理。

这种代理能够记录最近调用发生错误的次数,然后决定是继续操作还是立即返回错误。

那具体过程呢,你可以参考文中我放的这张图熔断器呢可以使用状态机来实现内部模拟这样几种状态。

那第一种呢是闭合状态,我们需要一个调用失败的计数器。

那如果调用失败了啊,就让失败次数加一。

那如果最近失败的次数超过了在给定时间内允许失败的阈值,就切换到断开状态。

那此时呢就会开启一个超时时钟,当这个时钟超过了这个时间就切换到半断开状态。

那这个超时时间的设定呢是给了系统一次机会来修正,导致调用失败的错误,来回到正常工作的状态。

在close状态下呢,错误计数器是基于时间的,在特定的时间间隔内会自动重置。

那这样呢能够防止由于某次的偶然错误,导致熔断器进入断开的状态。

那当然呢也可以基于连续失败的次数。

那第二种呢是断开的状态,在这个状态下对应用程序的请求啊会立即返回错误的响应,而不调用后端的服务。

那这样呢也许比较粗暴。

有些时候呢,我们可以cat住上次成功的请求直接返回缓存。

那如果没有缓存啊,再返回错误,那缓存的机制啊最好用在全站一样的数据,而不是用在不同的用户间不同的数据。

因为后者需要缓存的数据有可能会很多。

那第三种呢是半开状态,也就是允许应用程序中一定数量的请求啊去调用服务。

那如果这些请求对服务的调用成功了,那么就可以认为啊之前导致调用失败的错误已经修正了。

那此时熔断器切换到闭合状态,那同时呢将错误计数器重置。

那如果这一定数量的请求啊有调用失败的情况则认为导致之前调用失败的问题啊,仍然存在熔断器切回到断开状态,然后重置计时器来给系统一定的时间来修正错误。

那半断开状态啊,能够有效防止正在恢复中的服务被突然而来的大量请求再次拖垮。

那这里呢我同样在文中用了一张图来帮助你理解实现熔断期模式啊,可以让系统更加稳定,会有弹性。

在系统从错误中恢复的时候提供稳定性,并且减少了错误对系统性能的影响。

它快速的拒绝那些有可能导致错误的服务调用。

而不会去等待操作超时,或者永远不返回结果,来提高系统的响应时间。

那如果熔断器设计模式在每次状态切换的时候会发出一个事件,那这种信息啊可以用来监控服务的运行状态,能够通知管理员在熔断器切换到断开状态的时候进行处理。

我们再来看文中这个netflix的开源项目,histics当中的熔断的实现逻辑图。

那从这个流程图中啊,你可以看到这么几点。

首先呢,当有请求来了,allo request函数啊会先判断是否在熔断中。

那如果不是呢则放行啊,如果是的话,还要看有没有到达一个熔断的时间片。

那如果熔断时间片到了啊,也放行,否则呢直接返回出错。

那其次呢每次调用都有两个函数,mark success和mark failure来统计一下,在一定的duration之内有多少调用是成功的还是失败的。

另外呢,判断是否熔断的条件is open计算一下failure除以success failure啊,也就是当前的错误率。

那如果高于一个阈值呢,那么就打开熔断啊,否则呢就关闭。

最后呢histics会在内存中维护一个数组,其中记录着每一个周期请求结果的统计。

那超过时长长度的元素呢会被删除掉。

在实现熔断器模式的时候呢,还可能需要考虑一些因素。

那第一呢是错误的类型,需要注意的。

是啊,请求失败的原因会有很多种,你需要根据不同的错误情况来调整相应的策略。

所以啊熔断和重试一样,需要对返回的错误进行识别。

那一些错误啊,先走重试的策略,比如限流或者超时重试几次后啊再打开熔断。

那一些错误呢是远程服务挂掉了,恢复时间比较长。

那这种错误啊不必走重试啊,就可以直接打开熔断策略。

那第二呢是日志监控熔断器啊,应该能够记录所有失败的请求啊和一些可能会尝试成功的请求,使得管理员啊能够监控使用熔断器保护服务的执行情况。

那第三呢是测试服务是否可用。

在断开状态下呢,熔断器可以采用定时的ping下远程服务的健康检查接口来判断服务是否恢复,而不是使用计时器来自动切换到半开的状态。

那这样做的一个好处呢,是在服务恢复的情况下,不需要真实的用户流量,就可以把状态从半开状态切回关闭状态。

否则呢在半开状态下,即使服务已经恢复了也需要用户真实的请求来恢复。

那这样呢会影响用户的真实请求。

第四呢是手动重置。

在系统中对于失败操作的恢复时间啊是很难确定的那提供一个手动重置功能呢,能够使得管理员可以手动的强制将熔断器切换到闭合的状态啊。

同样如果受熔断器保护的服务暂时不可用的话,管理员啊能够强制的将熔断器设置为断开的状态。

那第五呢是并发问题相同的熔断器啊,有可能被大量并发请求同时访问。

那熔断器的实现啊不应该阻塞并发的请求,或者增加每次请求调用的负担,尤其是其中对调用结果的统计。

那一般来说呢会成为一个共享的数据结构,它呢会导致有锁的情况。

在这种情况下,最好使用一些无锁的数据结构或者atomomc原子操作。

那这样呢会带来更好的性能。

那第六呢是资源分区。

有时候啊我们会把资源分布在不同的分区上,比如数据库的分库分表,某个分区啊可能出现问题。

而其他分区呢还可用。

在这种情况下呢,单一的熔断器啊会把所有的分区访问给混为一谈。

从而一旦开始熔断,那么所有的分区啊都会受到熔断影响,或者呢出现一会儿熔断,一会儿又好来来回回的情况。

所以呢熔断器需要考虑这样的问题,只对有问题的分区进行熔断,而不是整体。

那最后呢第七个考虑因素是重事错误的请求。

有时候呢错误和请求的数据和参数有关系,所以记录下出错的请求在半开状态。

下城试能够准确的知道服务是否真的恢复了。

那当然呢这需要被调用端支持密等调用,否则呢就会出现一个操作被执行多次的副作用。

好了,我们来总结一下今天分享的主要内容。

首先呢熔断设计是受了电路设计中保险丝的启发,它需要实现三个状态,闭合断开和半开分别对应于正常故障和故障后检测故障是否已经被修复的场景。

并且我介绍了netflix的histricx对熔断的实现。

最后呢我总结了熔断设计的几个重点。

在下节课呢我们会讲述限流设计,希望能对你有帮助。

也欢迎你分享一下你实现过的熔断使用了怎样的算法呢?实现的过程中遇到过什么坑呢?文末呢我给出了分布式系统模式系列文章的目录,希望你能在这个列表里啊找到自己感兴趣的内容。