写点什么

Spring cloud 之 CircuitBreaker 篇

作者:邱学喆
  • 2022 年 3 月 12 日
  • 本文字数:2233 字

    阅读完需:约 7 分钟

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 中,我们直接引入即可。

<dependency> 	<groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId></dependency>
复制代码

在业务代码中,可以注入。其相关代码如下:

// 1. 注入熔断器工厂对象@Autowiredprivate CircuitBreakerFactory circuitBreakerFactory;
// 2. 创建熔断器CircuitBreaker circuitBreaker = circuitBreakerFactory.create("熔断器名称");
// 3. 业务代码-远程调用circuitBreaker.run(()->{ return null;//远程调用},Throwable ->{ return null; //当熔断发生时,回调方法});
复制代码

这里还有另外一个知识点,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 本身有了注解方式使用得相关实现,所以并没有再进一步处理。


发布于: 刚刚阅读数: 2
用户头像

邱学喆

关注

计算机原理的深度解读,源码分析。 2018.08.26 加入

在IT领域keep Learning。要知其然,也要知其所以然。原理的爱好,源码的阅读。输出我对原理以及源码解读的理解。个人的仓库:https://gitee.com/Michael_Chan

评论

发布
暂无评论
Spring cloud 之 CircuitBreaker篇_Spring Cloud_邱学喆_InfoQ写作平台