10年老架构3000字就把微服务高并发熔断降级熔断器讲得明明白白
熔断器
从Sentinel 1.8.0开始,无论使用DegradeRuleManager的loadRules API还是使用动态数据源加载熔断降级规则,当熔断降级规则更新时,Sentinel会为每个熔断降级规则都创建一个熔断器并与熔断降级规则绑定,并且不同的熔断降级策略对应不同类型的熔断器。
熔断器接口的定义如下。
• getRule:获取熔断器绑定的熔断降级规则。
• tryPass:完成can pass check逻辑,若返回false,则表示拒绝当前请求。
• currentState:获取当前熔断器的状态(OPEN、HALF_OPEN、CLOSED)。
•onRequestComplete:在请求完成时调用,请求完成包括正常完成、被拒绝或发生异常。
对DegradeSlot类的源码也进行了更改,由DegradeSlot在entry方法中遍历熔断器,调用熔断器的tryPass方法;在exit方法中遍历熔断器,调用熔断器的onRequestComplete方法。 抽象熔断器
虽然不同熔断降级策略的熔断器实现逻辑不同,但差异只是阈值的判断不同或需要统计的指标数据不同,而是否放行请求只需要根据当前熔断器的状态判断,因此,Sentinel为不同熔断降级策略的熔断器提供了一个统一的抽象类——AbstractCircuitBreaker。
AbstractCircuitBreaker类定义的字段及构造方法的源码如下。
• rule:熔断器绑定的熔断降级规则,在构造方法中被传入。
• recoveryTimeoutMs:熔断器开启的持续时间,单位为毫秒,对应熔断降级规则配置的timeWindow。
• observerRegistry:熔断器状态改变监听器的注册器,在熔断器发生状态改变时通过注册器获取注册的所有监听器并回调onStateChange方法。
• currentState:记录当前熔断器的状态。
• nextRetryTimestamp:允许熔断器关闭的时间。
nextRetryTimestamp等于熔断器开启时的时间加上recoveryTimeoutMs,源码如下。
updateNextRetryTimestamp方法在熔断器从CLOSED状态变为OPEN状态时或从HALF_OPEN状态变为OPEN状态时被调用。
1. CLOSED→OPEN
fromCloseToOpen方法可实现将熔断器从CLOSED状态变为OPEN状态,源码如下。
• 方法参数为触发值,即达到阈值时触发熔断器开启的当前值。
• 方法可实现开启熔断器,更新下一次允许将熔断器关闭的时间,并通知状态改变观察者。
2. HALF_OPEN→OPEN
fromHalfOpenToOpen方法可实现将熔断器从HALF_OPEN状态变为OPEN状态,源码如下。
• 方法参数为触发值,即达到阈值时触发熔断器开启的当前值。
• 方法可实现开启熔断器,更新下一次允许将熔断器关闭的时间,并通知状态改变观察者。
3. HALF_OPEN→CLOSED
fromHalfOpenToClose方法可实现将熔断器从HALF_OPEN状态变为CLOSED状态,源码如下。
该方法可实现关闭熔断器并重置滑动窗口,重新统计熔断指标数据,最后通知状态改变观察者。其中调用的resetStat方法是一个抽象方法,由子类实现,用于重置滑动窗口。
4. OPEN→HALF_OPEN
fromOpenToHalfOpen方法可实现将熔断器从OPEN状态变为HALF_OPEN状态,源码如下。
• 方法参数为调用链上下文。
• 方法可实现将熔断器从OPEN状态变为HALF_OPEN状态,先通知状态改变观察者,再从Context实例中获取当前资源的Entry实例,向Entry实例注册一个exit回调处理器。该处理器在Entry实例的exit方法被调用时回调。
• exit回调处理器实现:如果当前请求被拒绝(不仅包括熔断器拒绝的,也包括限流、系统自适应等拒绝的),将熔断器从HALF_OPEN状态变为OPEN状态。
思考:为什么要在fromOpenToHalfOpen方法中注册exit回调处理器?
fromOpenToHalfOpen方法在tryPass方法中被调用。tryPass方法的源码如下。
① 如果当前熔断器处于CLOSED状态,则放行请求。
②如果当前熔断器处于OPEN状态,且当前时间大于nextRetryTimestamp,则放行请求,并将熔断器状态改为HALF_OPEN。
③ 如果当前熔断器处于HALF_OPEN状态,则拒绝请求。
从tryPass方法中可以看出,当熔断器已经处于OPEN状态或已经处于HALF_OPEN状态时,当前请求将被拒绝。特殊地,只有触发熔断器从OPEN状态变为HALF_OPEN状态的那个请求才允许被放行。
注册exit回调处理器用于修复在某种情况下熔断器永远保持半开启状态的Bug,可在GitHub的Sentinel主页下查看编号为1638的Issue对此Bug的描述,如图6.4所示。
图6.4 编号为1638的Issue详情
Bug描述:当请求被其他规则阻止时,熔断器不会从半开启状态中恢复。
例如,同一资源有两个熔断降级规则:R1(熔断器状态=OPEN,
recoveryTimeout=10s)和R2(熔断器状态=OPEN,recoveryTimeout=20s)。由于R2比R1的timeWindow时间长,因此在某些情况下,R1已达到recoveryTimeout,但R2还未达到recoveryTimeout,如果此时有请求进来,则熔断器将进行以下转换。
• R1已达到recoveryTimeout,将从OPEN状态变为HALF_OPEN状态。
• R2未达到recoveryTimeout,依然保持OPEN状态。
因此,该请求将会被R1允许,但会被R2拒绝,请求最终被拒绝,熔断器R1的onRequestComplete方法将不会被调用。
当下一个请求进来时,由于R1关联的熔断器状态为HALF_OPEN,请求将会被该熔断器拒绝,导致R1、R2关联的熔断器的onRequestComplete方法都不会被调用,最终导致R1关联的熔断器状态将永远为HALF_OPEN状态。
实际上,当R1之后有任何规则(不仅包括熔断降级规则)阻止请求时,都可能会发生这种情况。
熔断器的onRequestComplete方法是在DegradeSlot#exit方法中调用的,当发生BlockException时,就不会调用熔断器的onRequestComplete方法。DegradeSlot#exit方法的源码如下。
从DegradeSlot#exit方法的源码中可以看出,如果当前请求已经被拒绝,则该资源绑定的所有熔断器的onRequestComplete方法都不会被调用。而熔断器从HALF_OPEN状态变为OPEN状态或从HALF_OPEN状态变为CLOSED状态都是在熔断器的onRequestComplete方法中完成的,当熔断器处于HALF_OPEN状态时,如果当前请求正常,则onRequestComplete方法会将熔断器变为CLOSED状态。
为了解决这个Bug,Sentinel才选择在熔断器变为HALF_OPEN状态时给Entry注册一个exit回调处理器,在发生BlockException时由exit回调处理器将熔断器打开,由后续请求触发熔断器的CLOSED状态或者使其重新变为OPEN状态。 异常熔断器
异常熔断器用于实现ERROR_RATIO、ERROR_COUNT这两种熔断降级策略,因此异常熔断器关心的是异常指标数据。
异常熔断器的字段定义及构造方法的源码如下。
• strategy:熔断降级策略,由于ExceptionCircuitBreaker支持两种熔断降级策略,因此需要strategy区分ERROR_RATIO和ERROR_COUNT。
•minRequestAmount:最小请求数,当当前时间窗口总请求数大于minRequestAmount时,才能判断异常比率或异常总数是否达到阈值。
• threshold:熔断阈值,当strategy配置为ERROR_RATIO时表示异常比率,当strategy配置为ERROR_COUNT时表示异常总数。
• stat:独立收集指标数据的滑动窗口。
异常熔断器创建的滑动窗口只收集异常总数和总请求数,源码如下。
ExceptionCircuitBreaker实现的onRequestComplete方法的源码如下。
① 如果当前请求异常,则统计异常指标数据。
② 统计总请求数。
③ 根据当前时间窗口统计的指标数据是否达到阈值来改变熔断器的状态。
handleStateChangeWhenThresholdExceeded方法的源码如下。
① 如果当前熔断器状态为HALF_OPEN,则当请求发生异常时重新打开熔断器,否则直接关闭熔断器。
② 计算异常总数与总请求数,如果总请求数大于minRequestAmount,那么当熔断降级策略为EXCEPTION_RATIO时,若异常总数与总请求数的比值大于熔断降级规则配置的阈值,则开启熔断器;而当熔断降级策略为ERROR_COUNT时,若异常总数大于熔断降级规则配置的阈值,则开启熔断器。
handleStateChangeWhenThresholdExceeded方法调用transformToOpen方法将熔断器状态设置为OPEN,该方法由父类AbstractCircuitBreaker实现,其源码如下。
该方法的作用是根据当前熔断器状态调用不同的方法开启熔断器。 慢请求熔断器
慢请求熔断器用于实现SLOW_REQUEST_RATIO熔断策略,因此慢请求熔断器关心的是耗时指标数据。
慢请求熔断器的字段定义及构造方法的源码如下。
• maxAllowedRt:如果请求耗时超过该值,则将其视为慢请求。
•maxSlowRequestRatio:慢请求比率阈值,如果慢请求总数与总请求数的比值超过该值,则开启熔断器。
•minRequestAmount:最小请求数,即使慢请求比率已经达到阈值,但总请求数小于minRequestAmount的情况下也不能开启熔断器。
• slidingCounter:独立收集指标数据的滑动窗口。
慢请求熔断器创建的滑动窗口只收集慢请求总数和总请求数,源码如下。
ResponseTimeCircuitBreaker实现的onRequestComplete方法的源码如下。
① 计算当前请求的执行耗时。
② 统计慢请求总数和总请求数。
③ 根据当前时间窗口统计的指标数据是否达到阈值来改变熔断器的状态。
handleStateChangeWhenThresholdExceeded方法的源码如下。
① 如果当前熔断器处于HALF_OPEN状态,那么,若当前请求是慢请求,则开启熔断器,否则直接关闭熔断器。
② 根据慢请求总数与总请求数计算出当前的慢请求比率,当慢请求比率大于阈值且总请求数大于minRequestAmount时,开启熔断器。 小结
本篇主要分析Sentinel 1.7.x与Sentinel 1.8.0的熔断降级功能的实现原理,并详细介绍了使用熔断器实现熔断降级功能的实现原理,以及Sentinel提供的两种熔断器的实现原理。 本文给大家讲解的内容是深度解析微服务高并发熔断降级 :熔断器下篇文章给大家讲解的内容是深度解析微服务高并发授权与系统自适应 :授权功能的实现原理 感谢大家的支持!
中外科学家揭开密西西比亚纪珊瑚礁崩溃之谜腕足类壳体单偏光(A,C)及其对应的阴极发光(B,D)图片。南古所供图中新网南京1月3日电(记者杨颜慈)记者3日从中国科学院南京地质古生物研究所获悉,该所参与的国际研究团队利用腕足
一个人的报应,会在50到60岁这十年,逐渐来到身边人这一生,每个阶段,都有自己要发愁的事。年少时,发愁自己的成绩如何,上什么学校成年后,发愁自己,赚不赚得到钱。而到了五六十岁,自然就很现实的,开始考虑生死了。其实,人在五六十岁的时
S30赛季首位T0。5英雄诞生,肉铠的亲爹,该如何克制莱西奥?1月3日,新英雄莱西奥正式上线,接下来,我会基于抢先服,总结几点莱西奥的核心细节分享给大家。莱西奥有哪些技能机制?莱西奥相比于马可波罗和公孙离,操作至少简单一档,一般情况下,只要你
S30赛季首位恶霸诞生,出场率飙升17,不死流白起真香!今天,想和大家聊聊白起。先给大家看看我在赛季初的第一天,也就是昨天所打出来的战绩。评分14。1,输出30。6,13个击杀,很难想象,这是一名坦克。打了一晚上的白起,有打野也有对抗路
天游接手王者荣耀第三个新赛季了,氪金摆烂现象会继续么?现状自从王者荣耀被天美公司转让给天游公司之后,隔三差五的就会有皮肤活动,经过统计,去年一年平均三天就要出一款新皮肤或者返厂一个限定皮肤。既然是限定皮肤或者新年皮肤返场的目的在何?明眼人
詹姆斯43611,布莱恩特1815!湖人力克黄蜂终结1连败北京时间2023年1月3日讯,黄蜂以115121,6分分差不敌对手湖人。首节比赛托马斯布莱恩特与戈登海沃德两个人成为了球队的进攻活力输出点,托马斯布莱恩特拿到8分,戈登海沃德5分,
渣女头过时了?2023仙女烫才是真的火!头条创作挑战赛离春节只有不到一个月的时间了,想着一年的工作不久即将收尾,内心还是有点小兴奋的,是时候该好好地准备下,给新的一年一个足够的仪式感仪式感的方式有很多,换个新发型就是其中
口服美容液再次兴起,新税品牌如何入场?近年来,随着颜值经济的盛行,消费者对美的需求增长,同时越来越注重绿色健康消费,美容饮品的市场需求逐渐扩大,LUMl汤臣倍健碧生源等保健品品牌纷纷加入口服美容液的赛道,今天对口服美容
香奈儿变臭奈儿,奢侈品也要蹭依托答辩的热度了?如果说2022年时尚界最会搞事的人是侃爷,那么最会整活(或被整活)的时尚品牌无疑就是香奈儿了。从上千元的奶奶款水晶凉鞋,到4万块的垃圾袋,信守奢侈品从不坑穷人的原则。原以为2022
简单告诉你什么是GMT手表浏览任何奢侈制表商的网站,您一定会看到GMT手表。欧米茄劳力士和帝舵?他们都做GMT腕表。但什么是GMT手表,它与标准的三针时计有何不同?简而言之,GMT手表有第四根指针。是的,您
守心自静,安度流年守心自静,抒写生命的安然,能够温暖自己的,是自己安逸的内心。内心是安逸的,万物不扰,在这个喧嚣的世界里,保持一份淡定,按照适合自己的生命节奏,不慌不乱,把生活调成静音模式,一切都变