Spring Cloud 使用 Resilience4j 实现服务熔断的方法
简介
在微服务架构中,服务之间的调用是通过网络通信实现的,当前服务如果调用其他服务时发生异常,这可能会导致雪崩效应,严重影响整个系统的稳定性和可用性。为了解决这个问题,可以引入服务熔断机制,当某个服务异常达到一定的阀值时,取消对该服务的调用,直接返回给调用方一个错误响应,从而减小对该服务的压力,保证整个系统的可用性。
在 Spring Cloud 框架中,Resilience4j 提供了一套完善的服务熔断解决方案,本文将介绍如何在 Spring Cloud 中使用 Resilience4j 实现服务熔断。
环境准备
在开始编写代码之前,需要准备以下环境:
- JDK 8 或以上版本
- Maven 3.2.5 或以上版本
- Spring Boot 2.3.0.RELEASE 或以上版本
Maven 依赖
在 Maven pom.xml 文件中添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
</dependencies>
上述依赖包含了 Spring Cloud Eureka 客户端和 Resilience4j 熔断器的相关依赖。
编写服务调用方法
假设有一个名为 "example-service" 的服务提供了一个 "/api/examples" 接口供其他服务调用,我们需要编写调用该接口的方法,并使用 Resilience4j 实现服务熔断。
- 在 application.yml 或 application.properties 文件中,配置调用服务的地址:
yaml
example-service:
url: http://localhost:8080
上述配置指定了 example-service 服务的 URL 地址。
- 在服务中新建一个 Service 类,并编写调用 example-service 的方法:
```java
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
@Service
public class ExampleService {
private final RestTemplate restTemplate;
private final String exampleServiceUrl;
public ExampleService(RestTemplateBuilder restTemplateBuilder,
@Value("${example-service.url}") String exampleServiceUrl) {
this.restTemplate = restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
this.exampleServiceUrl = exampleServiceUrl;
}
@CircuitBreaker(name = "exampleService", fallbackMethod = "getExamplesFallback")
public String getExamples() {
return restTemplate.getForObject(exampleServiceUrl + "/api/examples", String.class);
}
public String getExamplesFallback(Throwable throwable) {
return "Fallback Response";
}
}
```
上述代码中,我们使用 RestTemplate 向 example-service 发送一个 GET 请求,并获取响应内容。CircuitBreaker 注解指定了熔断器的相关配置,其中 name 表示该熔断器的名称,fallbackMethod 表示当服务不可用时会执行的方法的名称。
- 在服务的 Controller 中注入 ExampleService,并调用 getExamples 方法:
```java
@RestController
public class ExampleController {
private final ExampleService exampleService;
public ExampleController(ExampleService exampleService) {
this.exampleService = exampleService;
}
@GetMapping("/examples")
public String getExamples() {
return exampleService.getExamples();
}
}
```
- 启动服务,访问 "/examples" 接口,测试调用 example-service 服务是否正常。
示例一:测试服务熔断
在上一步中,我们已经实现了调用 example-service 服务的方法,并使用了 Resilience4j 熔断器机制,现在我们需要模拟 example-service 服务不可用的情况,测试服务熔断机制的效果。
- 在 example-service 服务中,添加一个 "/api/fail" 接口,该接口会抛出一个异常:
java
@GetMapping("/fail")
public void fail() {
throw new RuntimeException("Fail");
}
- 在服务调用方法上修改 CircuitBreaker 注解,设置熔断器阀值为 1,这里只需要一次异常就会触发服务熔断:
```java
@CircuitBreaker(name = "exampleService", fallbackMethod = "getExamplesFallback",
circuitBreakerConfig = "exampleServiceCircuitBreakerConfig")
public String getExamples() {
return restTemplate.getForObject(exampleServiceUrl + "/api/examples", String.class);
}
private CircuitBreakerConfig createCircuitBreakerConfig() {
return CircuitBreakerConfig.custom()
.failureRateThreshold(1)
.waitDurationInOpenState(Duration.ofSeconds(5))
.ringBufferSizeInHalfOpenState(2)
.ringBufferSizeInClosedState(2)
.build();
}
private CircuitBreakerRegistry createCircuitBreakerRegistry() {
CircuitBreakerConfig circuitBreakerConfig = createCircuitBreakerConfig();
return CircuitBreakerRegistry.of(circuitBreakerConfig);
}
@Bean
public Customizer
return factory -> factory.configureDefault(id -> createCircuitBreakerRegistry().circuitBreaker(id));
}
@Bean
public CircuitBreakerConfig exampleServiceCircuitBreakerConfig() {
return createCircuitBreakerConfig();
}
```
上述代码中,我们重新定义了一个方法 createCircuitBreakerConfig 来创建 CircuitBreakerConfig 对象,用于指定熔断器的相关配置。我们还定义了一个方法 createCircuitBreakerRegistry,用于创建 CircuitBreakerRegistry 对象,该对象用于管理熔断器。最后,通过 customizer 方法和 exampleServiceCircuitBreakerConfig 方法,为服务调用方法指定了熔断器的配置。
-
启动服务,访问 "/fail" 接口,模拟 example-service 服务不可用的情况。
-
再次访问 "/examples" 接口,会立即返回 "Fallback Response",证明服务熔断机制已经生效。
示例二:恢复服务调用
在服务熔断机制生效后,需要等待一段时间,熔断器才会自动切换到半开状态,尝试恢复对服务的调用。在半开状态下,熔断器会允许发送少量的请求,如果请求成功,则熔断器会切换到关闭状态,否则重新切换到打开状态。
- 在 example-service 服务中,添加一个 "/api/ok" 接口,该接口返回一个正常的响应:
java
@GetMapping("/ok")
public String ok() {
return "OK";
}
- 在 ExampleService 类中添加一个新方法,用于测试在半开状态下调用 example-service 服务:
java
@CircuitBreaker(name = "exampleService", fallbackMethod = "getExamplesFallback",
circuitBreakerConfig = "exampleServiceCircuitBreakerConfig")
public String getExamplesWithHalfOpen() {
CircuitBreaker circuitBreaker = CircuitBreakerRegistry
.of(createCircuitBreakerConfig())
.circuitBreaker("exampleService");
circuitBreaker.transitionToHalfOpenState();
try {
return restTemplate.getForObject(exampleServiceUrl + "/api/ok", String.class);
} catch (Exception e) {
return "Fallback Response";
}
}
上述代码中,我们使用 CircuitBreakerRegistry 创建了一个新的熔断器,然后将其切换到半开状态。在 try 块中,我们使用 RestTemplate 发送一个 GET 请求,获取 "/api/ok" 接口的响应。在 catch 块中,我们处理异常情况。
- 在 ExampleController 中添加一个新的接口,调用 getExamplesWithHalfOpen 方法:
java
@GetMapping("/examples-with-half-open")
public String getExamplesWithHalfOpen() {
return exampleService.getExamplesWithHalfOpen();
}
-
启动服务,访问 "/fail" 接口,模拟 example-service 服务不可用的情况。
-
等待 5 秒钟,熔断器将自动切换到半开状态。访问 "/examples-with-half-open" 接口,可以看到响应内容为 "OK",证明服务调用已经成功。
结论
本文介绍了如何在 Spring Cloud 中使用 Resilience4j 实现服务熔断机制。通过触发服务不可用的状态,我们成功测试了熔断器的生效和恢复机制,保证了整个系统的良好运行。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Cloud 使用 Resilience4j 实现服务熔断的方法 - Python技术站