Spring Cloud(Kilburn 2022.0.2版本)系列教程(四) 服务容错处理(断路器Resilience4JCircuitBreaker)
一、服务容错处理Resilience4JCircuitBreaker
在⾼并发访问下,流量持续不断的涌⼊,服务之间的相互调⽤频率突然增加,引发系统负载过⾼,这时系统所依赖的服务的稳定性对系统的影响⾮常⼤,⽽且还有很多不确定因素引起雪崩,如⽹络连接中断,服务宕机等。⼀般微服务容错组件提供了限流、隔离、降级、熔断等⼿段,可以有效保护我们的微服务系统。
Spring Cloud 2020
版本之后废弃了对大部分 Netflix
组件的支持,其中就包括最常用的 熔断
组件 Hystrix
,取而代之的就是 resilience4j
、 sentinel
、Spring Retry
等。
Resilience4J是一个轻量级的容错组件,为Java8和函数式编程所设计的轻量级容错框架。提供了提供了⼀组⾼阶函数,包括断路器,限流器,重试机制,隔离机制。
二、引入Resilience4JCircuitBreaker依赖
复制项目openfeignClientConsumer
,并修改为resilience4jClientConsumer
,修改artifactId
、name
、description
为resilience4jClientConsumer
。
<artifactId>resilience4jClientConsumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>resilience4jClientConsumer</name>
<description>resilience4jClientConsumer</description>
增加resilience4j
依赖
<!-- 引入断路器依赖resilience4j -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
pom
文件如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cc.huerpu</groupId>
<artifactId>resilience4jClientConsumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>resilience4jClientConsumer</name>
<description>resilience4jClientConsumer</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2022.0.2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入断路器依赖resilience4j -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2022.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>netflix-candidates</id>
<name>Netflix Candidates</name>
<url>https://artifactory-oss.prod.netflix.net/artifactory/maven-oss-candidates</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
三、Resilience4JCircuitBreaker配置
修改application.yml
文件,修改端口为8004
,打开circuitbreaker
,并设置其配置项,还有openfeignClientConsumer
替换成resilience4jClientConsumer
。
spring:
cloud:
openfeign:
circuitbreaker:
enabled: true
resilience4j:
circuitbreaker:
configs:
default:
failureRateThreshold: 30 #失败请求百分⽐,超过这个⽐例,CircuitBreaker变为OPEN状态
slidingWindowSize: 10 #滑动窗⼝的⼤⼩,配置COUNT_BASED,表示10个请求,配置TIME_BASED表示10秒
minimumNumberOfCalls: 5 #最⼩请求个数,只有在滑动窗⼝内,请求个数达到这个个数,才会触发CircuitBreader对于断路器的判断
slidingWindowType: TIME_BASED #滑动窗⼝的类型
permittedNumberOfCallsInHalfOpenState: 3 #当CircuitBreaker处于HALF_OPEN状态的时候,允许通过的请求个数
automaticTransitionFromOpenToHalfOpenEnabled: true #设置true,表示⾃动从OPEN变成HALF_OPEN,即使没有请求过来
waitDurationInOpenState: 2s #从OPEN到HALF_OPEN状态需要等待的时间
recordExceptions: #异常名单
- java.lang.Exception
instances:
hepResilience4j:
failureRateThreshold: 50
slowCallDurationThreshold: 2s #慢调⽤时间阈值,⾼于这个阈值的呼叫视为慢调⽤,并增加慢调⽤⽐例。
slowCallRateThreshold: 30 #慢调⽤百分⽐阈值,断路器把调⽤时间⼤于 slowCallDurationThreshold,视为慢调⽤,当慢调⽤⽐例⼤于阈值,断路器打开,并进⾏服务降级
slidingWindowSize: 10
slidingWindowType: TIME_BASED
minimumNumberOfCalls: 2
permittedNumberOfCallsInHalfOpenState: 2
waitDurationInOpenState: 2s #从OPEN到HALF_OPEN状态需要等待的时间
创建一个Resilience4jController
,并把UserService
注入进去,然后定义了一个getUserById
,并去调用userService.getUserById();
package cc.huerpu.eurekaclient.controller;
import cc.huerpu.eurekaclient.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResilienceController {
@Autowired
private UserService userService;
@RequestMapping("/getUserById")
@CircuitBreaker(name = "hepResilience4j")
public String getUserById(){
String res = userService.getUserById();
return "ResilienceController:" + res;
}
}
创建ResilienceFallbackController
,用来熔断处理操作。
package cc.huerpu.eurekaclient.controller;
import cc.huerpu.eurekaclient.service.UserService;
import org.springframework.stereotype.Component;
@Component
public class ResilienceFallbackController implements UserService {
public String getUserById(){
return "ResilienceFallbackController: call interface error....circuitbreaker open";
}
}
修改UserService接口,设置熔断处理类为ResilienceFallbackController.class
package cc.huerpu.eurekaclient.service;
import cc.huerpu.eurekaclient.controller.ResilienceFallbackController;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "EUREKACLIENT",fallback = ResilienceFallbackController.class)
public interface UserService {
@RequestMapping("/getUserById")
public String getUserById();
}
把原来eurekaClient
服务中的接口增加Thread.sleep(60000);
,模拟服务挂掉了。当然也可以不注册原来eurekaClient
服务来模拟服务挂掉了也可以。
@RestController
public class UserController {
@RequestMapping("/getUserById")
public String getUserById() throws Exception{
Thread.sleep(60000);
return "{id:1,name:jason,age:23,sex: man}";
}
}
Resilence4j对于微服务容错的处理,分别为熔断,隔离,限流。
四、CircuitBreaker断路器
断路器CircuitBreaker
通常存在三种状态(CLOSE、OPEN、HALF_OPEN)
,并通过一个时间或数量窗口来记录当前的请求成功率或慢速率,从而根据这些指标来作出正确的容错响应。
启动项目resilience4jClientConsumer
,在浏览器调用http://localhost:8004/getUserById
,可以看到ResilienceController:ResilienceFallbackController: call interface error....circuitbreaker open
。
本文参考SpringCloud Resilience4JCircuitBreaker链接:
https://docs.spring.io/spring-cloud-circuitbreaker/docs/3.0.2/reference/html/