Spring Cloud Circuit breaker提供了一个跨越不同断路器实现的抽象。它提供了一个一致的API,可以在你的应用程序中使用,允许你的开发者选择最适合你的应用程序需求的断路器实现。它还支持的实现有如下几种
利用Circuit Breaker实现接口熔断和自动恢复
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-circuit-breaker</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
</project>
name
:
fallbackMethod
:
Throwable
参数以捕获异常。关闭(Closed):断路器允许调用服务并监控结果。如果失败率超过配置的阈值,断路器将转为打开状态。
打开(Open):断路器会短路对服务的调用,立即返回失败或调用备用方法。经过配置的等待时间后,断路器将转为半开状态。
半开(Half-Open):断路器允许有限数量的测试调用。如果这些调用成功,断路器将转回关闭状态;如果失败,则返回到打开状态。
package com.et.controller;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
@RestController
@RequestMapping("/annotation")
public class MyController {
private final io.github.resilience4j.circuitbreaker.CircuitBreaker circuitBreaker;
private boolean simulateFailure = true;
public MyController(CircuitBreakerRegistry circuitBreakerRegistry) {
this.circuitBreaker = circuitBreakerRegistry.circuitBreaker("order-service");
}
@GetMapping("/my-service")
@CircuitBreaker(name = "order-service", fallbackMethod = "fallbackMethod")
public String myService() {
System.out.println("Circuit Breaker State: " + circuitBreaker.getState());
System.out.println("Circuit Breaker name: " + circuitBreaker.getName());
System.out.println("Circuit Breaker config: " + circuitBreaker.getCircuitBreakerConfig().toString());
if (simulateFailure) {
throw new RuntimeException("Simulated failure");
}
return "Service is up";
}
public String fallbackMethod(Throwable throwable) {
if (throwable instanceof CallNotPermittedException) {
return "Circuit Breaker is OPEN, request not permitted";
}
return "Fallback response";
}
@GetMapping("/toggle-failure")
public String toggleFailure() {
simulateFailure = !simulateFailure;
return "Failure simulation is now " + (simulateFailure ? "ON" : "OFF");
}
}
自定义实现
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<String> 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
myCircuitBreaker
slidingWindowSize: 10
: This sets the size of the sliding window, which is used to record the outcome of calls. In this case, it records the last 10 calls.
failureRateThreshold: 50
: This sets the failure rate threshold as a percentage. If the failure rate is equal to or greater than 50%, the circuit breaker transitions to the open state.
waitDurationInOpenState: 30s
: This specifies the time that the circuit breaker should stay open before transitioning to half-open. Here, it is set to 30 seconds.
permittedNumberOfCallsInHalfOpenState: 3
: This sets the number of calls that are allowed to pass through when the circuit breaker is in the half-open state. If these calls are successful, the circuit breaker transitions back to closed.
order-service
sliding-window-type: COUNT_BASED
: This specifies the type of sliding window. COUNT_BASED
means the window is based on a fixed number of calls.
failure-rate-threshold: 10
: This sets a lower failure rate threshold of 10%. If the failure rate reaches this level, the circuit breaker will open.
minimum-number-of-calls: 5
: This sets the minimum number of calls that must be recorded before the failure rate can be calculated. This prevents the circuit breaker from opening prematurely.
automatic-transition-from-open-to-half-open-enabled: true
: This enables automatic transition from open to half-open state after the wait duration has elapsed.
wait-duration-in-open-state: 5s
: This specifies a shorter wait duration of 5 seconds for the circuit breaker to stay open before transitioning to half-open.
permitted-number-of-calls-in-half-open-state: 3
: Similar to myCircuitBreaker
, this sets the number of test calls allowed in the half-open state.
sliding-window-size: 10
: This sets the sliding window size to 10 calls, similar to myCircuitBreaker
.
register-health-indicator: true
: This enables the registration of a health indicator for the circuit breaker, which can be used for monitoring purposes.
@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);
}
}
/my-service
,确保在 simulateFailure
为 true
时抛出异常。/my-service
,以达到失败率阈值,触发断路器进入 OPEN
状态。OPEN
。/toggle-failure
:切换 simulateFailure
为 false
。waitDurationInOpenState
时间后,再次访问 /my-service
,观察断路器状态变化和请求结果。/my-service
,确保在 simulateFailure
为 true
时抛出异常。/my-service
,以达到失败率阈值,触发断路器进入 OPEN
状态。OPEN
。/toggle-failure
:切换 simulateFailure
为 false
。waitDurationInOpenState
时间后,再次访问 /annotation/my-service
,观察断路器状态变化和请求结果。