熔断机制(Circuit Breaker)指的是在股票市场的交易时间中,当价格的波动幅度达到某一个限定的目标(熔断点)时,对其暂停交易一段时间的机制。此机制如同保险丝在电流过大时候熔断,故而得名。熔断机制推出的目的是为了防范系统性风险,给市场更多的冷静时间,避免恐慌情绪蔓延导致整个市场波动,从而防止大规模股价下跌现象的发生。
同样的,在高并发的分布式系统设计中,也应该有熔断的机制。熔断一般是在客户端(调用端)进行配置,当客户端向服务端发起请求的时候,服务端的错误不断地增多,这时候就可能会触发熔断,触发熔断后客户端的请求不再发往服务端,而是在客户端直接拒绝请求,从而可以保护服务端不会过载。这里说的服务端可能是rpc服务,http服务,也可能是mysql,redis等。注意熔断是一种有损的机制,当熔断后可能需要一些降级的策略进行配合。
现代微服务架构基本都是分布式的,整个分布式系统是由非常多的微服务组成。不同服务之间相互调用,组成复杂的调用链路。在复杂的调用链路中的某一个服务如果不稳定,就可能会层层级联,最终可能导致整个链路全部挂掉。因此我们需要对不稳定的服务依赖进行熔断降级,暂时切断不稳定的服务调用,避免局部不稳定因素导致整个分布式系统的雪崩。
说白了,我觉得熔断就像是那些容易异常服务的一种代理,这个代理能够记录最近调用发生错误的次数,然后决定是继续操作,还是立即返回错误。
熔断器内部维护了一个熔断器状态机,状态机的转换关系如下图所示:
熔断器有三种状态:
Closed状态:也是初始状态,我们需要一个调用失败的计数器,如果调用失败,则使失败次数加1。如果最近失败次数超过了在给定时间内允许失败的阈值,则切换到Open状态,此时开启一个超时时钟,当到达超时时钟时间后,则切换到Half Open状态,该超时时间的设定是给了系统一次机会来修正导致调用失败的错误,以回到正常的工作状态。在Closed状态下,错误计数是基于时间的。在特定的时间间隔内会自动重置,这能够防止由于某次的偶然错误导致熔断器进入Open状态,也可以基于连续失败的次数。
Open状态:在该状态下,客户端请求会立即返回错误响应,而不调用服务端。
Half-Open状态:允许客户端一定数量的去调用服务端,如果这些请求对服务的调用成功,那么可以认为之前导致调用失败的错误已经修正,此时熔断器切换到Closed状态,同时将错误计数器重置。如果这一定数量的请求有调用失败的情况,则认为导致之前调用失败的的问题仍然存在,熔断器切回到断开状态,然后重置计时器来给系统一定的时间来修正错误。Half-Open状态能够有效防止正在恢复中的服务被突然而来的大量请求再次打挂。
下图是Netflix的开源项目Hystrix中的熔断器的实现逻辑:
从这个流程图中,可以看到:
有请求来了,首先allowRequest()函数判断是否在熔断中,如果不是则放行,如果是的话,还要看有没有达到一个熔断时间片,如果熔断时间片到了,也放行,否则直接返回错误。
每次调用都有两个函数makeSuccess(duration)和makeFailure(duration)来统计一下在一定的duration内有多少是成功还是失败的。
判断是否熔断的条件isOpen(),是计算fai