Spring cloud 之 CircuitBreaker 篇
一. 概述
在微服务之间互相调用,一旦某个服务出现异常,容易引起上游服务所提供的其他服务能力,市场是说的服务雪崩就是微服务架构上常见的异常场景;也就是说一个服务出现宕机时,其他依赖其服务的上游服务就会受到牵连。
为了避免服务雪崩的出现,提出了熔断机制,可以有效的避免服务雪崩的出现。
熔断机制的原理,上游服务要向下游服务发起调用时,会经过熔断器。熔断器会决策是否需要发起。如图:
熔断器是如何决策的,不可能平白无故拍脑袋下决策的,必须是依赖于现有的数据进行分析,从而进行决策的;在这里,这篇主要针对的 resilience4j 框架来进行分析。
在 resilience4j 下的熔断是基于两个指标进行决定是否拒绝向下游服务发起调用的;
慢调用率=慢调用的次数/总调用次数
失败率=总调用失败次数/总调用次数
那么相关指标的数据通过采集进行的。接下来就仔细分析其实现原理。
二. resilience4j 熔断
resilience4j 是通过状态机模式进行切换不同的策略,从而对请求进行不同的决策;其切换不同模式是基于数据采集后而进行的。
2.1 状态机
其有 6 种状态机,然而只有三种是有效的;我们简单来介绍一下;
当服务刚启动时,会处于 close 状态,这个情况下,所有的请求都会允许通过。
当超过指定的指标时,会切换到 open 状态。这个时候,会拒绝所有请求。
在 open 状态时,会经过一定时间后自动切换 half-open 状态,这个时候是允许指定的请求量通过的;
当分析数据,指标依然超过指定阈值,由切回 open 状态。如果指标低于阈值,则切换到 close 状态。
在这里说明,当请求发送出去后,会采集其相关数据,如成功时响应的时间以及响应结果,失败时响应时间以及异常信息。
接下来会介绍数据采集的相关细节。
2.2 采集器
resilience4j 有两种数据采集模式,一种是基于计数的滑动窗口,例外一种是基于时间滑动窗口
基于计数的滑动窗口
其原理是采集最近指定笔数的数据。例如,我们配置的是 100 笔,那么就会着采集最近 100 笔请求的相关信息。其具体实现代码,可以查阅 FixedSizeSlidingWindowMetrics 类
基于时间滑动窗口
其原理是采集最近时间范围内的数据。例如,我们配置的是 100s,那么就会最近 100s 内的所有请求的相关信息。其具体实现代码,可以查阅 SlidingTimeWindowMetrics 类。
2.3 整理
上面介绍的整体的原理,还有一些细节的没有提出来。例如,哪些异常不算失败,哪些异常可以忽略,哪些异常可以算成功;哪些正常响应算失败的。我们看一下其提供的配置项:
failureRateThreshold 失败率阈值,当超过该阈值时会切换到 open 状态
slowCallRateThreshold 慢调用率阈值,当超过该阈值时会切换到 open 状态
permittedNumberOfCallsInHalfOpenState 在 half-open 状态允许多少个请求通过
slidingWindowType 采集器类型,目前只有两个,基于计数的滑动窗口和基于时间滑动窗口
slidingWindowSize 滑动窗口大小,基于计数的滑动窗口下是窗口大小,基于时间滑动窗口下是时间,其单位是为秒
minimumNumberOfCalls 最小调用次数,当总次数低于该阈值时,不做任何处理。
slowCallDurationThreshold 慢调用响应时间,当请求响应时间超过该值时,则认为是慢调用。
maxWaitDurationInHalfOpenState 在 half-open 状态下,定时切换到 open 状态;
waitIntervalFunctionInOpenState 在 open 状态下等待指定内,自动切换到 half-open 状态。这个是当请求过来时,才会触发。
automaticTransitionFromOpenToHalfOpenEnabled 是否允许 open 状态下,定时得去切换到 open 状态
automaticTransitionFromOpenToHalfOpenEnabled 是否在 open 状态下,定时切换到 half-open 状态。这个是主动切换的;
writableStackTraceEnabled 是否允许打印堆栈信息
ignoreExceptions 需要忽略的异常列表
recordExceptions 需要记录为失败的异常列表
recordExceptionPredicate 自定义的谓词逻辑用于判断正常响应报文中是否将其响应归为异常
相关源码,可以查阅相关类。这里简单列一下类之间处理得时序图
三. 使用
在 spring cloud 中,我们直接引入即可。
在业务代码中,可以注入。其相关代码如下:
这里还有另外一个知识点,Bulkhead 是并发控制,这个是辅助熔断器处理,其原理是基于信号量来控制并发,要使用该并发控制得限制,则需要额外引入 resilience4j-bulkhead 包。
另外,当我们直接引入这个默认得 jar 包来引入熔断器时,其不单单只有 circuit breaker,同时还有 timelimiter 这个比较简单,就是很简单得超时限制,
四. 额外
resilience4j 大体有几大模块,梳理如下:
resilience4j-circuitbreaker: 熔断
resilience4j-ratelimiter: 频率控制
resilience4j-bulkhead: 并发控制
resilience4j-retry: 重试机制
resilience4j-cache: 结果缓存
resilience4j-timelimiter: 超时限制
spring cloud 中只引入了熔断,要想使用其他特性,仍需引入其他包。
个人感觉 spring cloud 包中熔断特性,并没有采用一贯得作风,通过 @注解得形式去使用,而是通过声明式方式去使用。有可能是 resilience4j 本身有了注解方式使用得相关实现,所以并没有再进一步处理。
版权声明: 本文为 InfoQ 作者【邱学喆】的原创文章。
原文链接:【http://xie.infoq.cn/article/45b2c194f2286dc302b9c3383】。文章转载请联系作者。
评论