- 作者:老汪软件技巧
- 发表时间:2024-11-08 17:01
- 浏览量:
1.什么是Spring Cloud Circuit Breaker?
Spring Cloud Circuit breaker提供了一个跨越不同断路器实现的抽象。它提供了一个一致的API,可以在你的应用程序中使用,允许你的开发者选择最适合你的应用程序需求的断路器实现。
它还支持的实现有如下几种
Resilience4j概述
Resilience4J 是一个针对 Java 8 应用程序的轻量级容错和弹性库。它设计用于在分布式系统中的服务之间提供弹性和容错性。Resilience4J 的名字来源于它提供的核心功能,即让系统(服务)能够“弹性”(resilient)地应对各种失败情况,包括网络问题、第三方服务故障等。 Resilience4J 提供了以下功能:
断路器(Circuit Breaker):当检测到服务异常或超时,断路器会打开,阻止进一步的请求发送到该服务。一段时间后(通常是秒级),断路器会进入半开状态,允许一个测试请求通过以检查服务是否恢复。如果请求成功,断路器关闭;如果失败,断路器会再次打开。限流(Rate Limiter):限制进入系统的请求速率,防止系统过载。这可以通过令牌桶算法或滑动窗口算法实现。隔离(Isolation):通过信号量或线程池隔离不同的服务调用,防止一个服务的失败影响到其他服务。超时(Timeouts):为服务调用设置超时时间,超过时间后会触发超时异常。重试(Retry):在遇到特定异常时自动重试服务调用,可以配置重试次数和间隔。缓存(Caching):提供缓存机制,以避免重复执行计算密集型或远程调用。Resilience4j 的 CircuitBreaker 实现原理如下**断路器的状态:**CircuitBreaker 具有三种正常状态:CLOSED(关闭)、OPEN(打开)和 HALFOPEN(半开),以及两个特殊状态:DISABLED(禁用)和 FORCEDOPEN(强制打开)。这些状态通过有限状态机进行管理。
**打开和关闭逻辑:**当被保护的服务或资源发生故障或长时间不可用时,断路器会迅速切换到 OPEN 状态,阻止更多的请求发送到该服务或资源。在 OPEN 状态下,系统会定期发送测试请求,以检查故障是否已经解决。如果测试请求成功,断路器会切换到 HALFOPEN 状态,允许一个请求发送到该服务或资源。如果这个请求成功,断路器会切换到 CLOSED 状态,否则会重新切换到 OPEN 状态。**故障率计算:**为了判断是否打开断路器,需要收集一定数量的请求数据。在 Resilience4j 中,需要至少填充一个环形缓冲区(Ring Bit Buffer),才能开始计算故障率。环形缓冲区的大小决定了需要多少次请求才能进行故障率的计算。环形缓冲区:Resilience4j 使用环形缓冲区来存储请求状态的数据结构,这与 Hystrix 使用的滑动窗口不同。环形缓冲区使用位集合(BitSet)实现,每个位代表一个请求的状态(成功或失败)。环形缓冲区的大小决定了能够存储的请求数量。例如,一个大小为 10 的缓冲区可以存储 1024 个请求状态。**配置选项:**Resilience4j 提供了丰富的配置选项,如故障率阈值、打开状态下的等待时间、半开状态下允许的最大请求数等,开发者可以根据需求进行灵活配置。
通过上述原理,Resilience4j 的 CircuitBreaker 能够有效地保护分布式系统免受故障的影响,提高系统的可用性和健壮性。
2.代码工程实验目的
利用Circuit Breaker实现接口熔断和自动恢复
pom.xml
"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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-demoartifactId>
<groupId>com.etgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>spring-cloud-circuit-breakerartifactId>
<properties>
<maven.compiler.source>17maven.compiler.source>
<maven.compiler.target>17maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4jartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
dependencies>
project>
controller注解实现关键组件
name:
fallbackMethod:
断路器状态
自定义实现
package com.et.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import java.util.function.Supplier;
@RestController
public class DemoController {
private final CircuitBreaker circuitBreaker;
private boolean simulateFailure = true;
public DemoController(CircuitBreakerRegistry circuitBreakerRegistry) {
this.circuitBreaker = circuitBreakerRegistry.circuitBreaker("myCircuitBreaker");
}
@GetMapping("/my-service")
public String myService() {
System.out.println("Circuit Breaker State: " + circuitBreaker.getState());
Supplier decoratedSupplier = CircuitBreaker.decorateSupplier(circuitBreaker, () -> {
if (simulateFailure) {
throw new RuntimeException("Simulated failure");
}
return "Service is up";
});
try {
return decoratedSupplier.get();
} catch (CallNotPermittedException e) {
return "Circuit Breaker is OPEN, request not permitted";
} catch (Exception e) {
return "Fallback response";
}
}
@GetMapping("/toggle-failure")
public String toggleFailure() {
simulateFailure = !simulateFailure;
return "Failure simulation is now " + (simulateFailure ? "ON" : "OFF");
}
}
配置文件
resilience4j.circuitbreaker:
instances:
myCircuitBreaker:
slidingWindowSize: 10
failureRateThreshold: 50
waitDurationInOpenState: 30s
permittedNumberOfCallsInHalfOpenState: 3
order-service:
sliding-window-type: COUNT_BASED
failure-rate-threshold: 10
minimum-number-of-calls: 5
automatic-transition-from-open-to-half-open-enabled: true
wait-duration-in-open-state: 5s
permitted-number-of-calls-in-half-open-state: 3
sliding-window-size: 10
register-health-indicator: true
myCircuitBreakerorder-service启动类
Spring AOP在使用注解风格的切面时,需要AspectJ的支持,确保在Spring Boot应用中启用了AOP支持,并启用@EnableAspectJAutoProxy注解
package com.et;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库3.测试
启动应用程序
非注解方式初始请求:访问 /my-service,确保在 simulateFailure 为 true 时抛出异常。多次失败请求:连续多次访问 /my-service,以达到失败率阈值,触发断路器进入 OPEN 状态。检查状态:在控制台中观察断路器状态输出,确保状态变为 OPEN。访问 /toggle-failure:切换 simulateFailure 为 false。等待并测试:等待 waitDurationInOpenState 时间后,再次访问 /my-service,观察断路器状态变化和请求结果。注解方式初始请求:访问 /annotation/my-service,确保在 simulateFailure 为 true 时抛出异常。多次失败请求:连续多次访问 /annotation/my-service,以达到失败率阈值,触发断路器进入 OPEN 状态。检查状态:在控制台中观察断路器状态输出,确保状态变为 OPEN。访问 /annotation/toggle-failure:切换 simulateFailure 为 false。等待并测试:等待 waitDurationInOpenState 时间后,再次访问 /annotation/my-service,观察断路器状态变化和请求结果。4.引用