一、Resilience4j 断路器应用场景
断路器模式是微服务架构中最重要的容错机制之一,主要用于解决:
-
防止服务雪崩:当某个下游服务因过载、故障或网络问题导致响应缓慢或失败时,上游服务的线程会因等待响应而被大量占用,最终导致自身也瘫痪,这种故障蔓延现象称为“雪崩”。断路器可以在失败率达到阈值时“跳闸”,快速失败(直接拒绝请求或执行降级逻辑),从而保护上游系统和网络资源。
-
实现优雅服务降级:当断路器打开时,不会真正发出请求,而是执行一个预设的降级方法(Fallback Method),返回一个默认值或友好提示,保证主逻辑的可用性。
-
自动恢复:断路器会定期尝试放行部分请求(进入半开状态),如果这些请求成功,则认为下游服务已恢复,会关闭断路器,恢复正常调用。
典型场景:用户服务(User-Service)需要调用订单服务(Order-Service)获取用户订单列表。如果订单服务突然宕机或响应极慢,用户服务的线程池会被挂起的请求迅速占满。此时,为“获取订单列表”这个接口配置断路器,可以快速失败并返回降级信息(如:“订单服务暂不可用”),从而保证用户服务的其他功能(如获取用户基本信息)依然可用。
二、项目配置与依赖
Resilience4j 与 Spring Boot 2.x+ 有非常好的集成。主要依赖如下:
1. Maven 依赖 (pom.xml
)
<!-- Spring Boot Starter AOP (必需,因为 Resilience4j 使用 AOP 进行切面) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Resilience4j CircuitBreaker 核心模块 -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-circuitbreaker</artifactId>
</dependency>
<!-- Resilience4j Spring Boot 2 适配器 (简化配置) -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
</dependency>
<!-- 如果你还想使用重试、限流等其他功能,可以引入所有模块 -->
<!-- <dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-all</artifactId>
</dependency> -->
<!-- Spring Boot Actuator (可选,用于提供监控端点) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Resilience4j Actuator 集成 (可选,用于监控) -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-micrometer</artifactId>
</dependency>
三、配置方式 (YAML)
# application.yml
management:
endpoints:
web:
exposure:
include: health,metrics,circuitbreakers # 暴露actuator端点,用于监控断路器状态
resilience4j:
circuitbreaker:
configs:
default: # 定义一个名为‘default’的共享配置
slidingWindowType: COUNT_BASED # 滑动窗口类型: COUNT_BASED(基于次数)/TIME_BASED(基于时间)
slidingWindowSize: 10 # 滑动窗口大小。COUNT_BASED下代表统计最近10次调用。
minimumNumberOfCalls: 5 # 计算错误率前所需的最小调用次数。即使只调了5次,有3次失败,成功率40%,也会触发。
failureRateThreshold: 50 # 失败率阈值百分比。达到此阈值,断路器打开。
waitDurationInOpenState: 10s # 断路器从OPEN到HALF-OPEN状态的等待时间。
permittedNumberOfCallsInHalfOpenState: 3 # 半开状态下允许的调用次数。
automaticTransitionFromOpenToHalfOpenEnabled: false # 是否自动从OPEN过渡到HALF_OPEN。设为true时,等待时间后自动切换。
recordExceptions: # 记录为失败的异常列表
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
- java.util.concurrent.TimeoutException
- call.MyBusinessException # 自定义业务异常
ignoreExceptions: # 应被忽略不计入失败的异常列表
- com.example.IgnorableException
sharedOrderServiceConfig: # 可以定义多个命名的共享配置
slidingWindowType: TIME_BASED
slidingWindowSize: 10
minimumNumberOfCalls: 10
failureRateThreshold: 60
waitDurationInOpenState: 15s
instances: # 为具体的断路器实例配置属性
orderServiceCircuitBreaker: # 实例名,与代码中的@CircuitBreaker(name="...")对应
baseConfig: sharedOrderServiceConfig # 继承名为‘sharedOrderServiceConfig’的配置
# 也可以在这里直接覆盖baseConfig中的属性
# failureRateThreshold: 70
userServiceCircuitBreaker:
baseConfig: default
# 覆盖默认的等待时间
waitDurationInOpenState: 5s
ps:对应的 application.properties
配置会显得冗长一些,例如:
resilience4j.circuitbreaker.configs.default.slidingWindowType=COUNT_BASED
resilience4j.circuitbreaker.configs.default.slidingWindowSize=10
resilience4j.circuitbreaker.instances.orderServiceCircuitBreaker.baseConfig=default
...
四、代码示例
我们将创建一个简单的服务,模拟调用远程的订单服务。
1. 模拟远程服务客户端 (OrderServiceClient.java)
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpServerErrorException;
import java.util.Random;
@Component
public class OrderServiceClient {
// 模拟一个不稳定的远程调用
public String getOrders(String userId) {
Random random = new Random();
int randomNum = random.nextInt(100);
// 50% 的概率模拟成功
if (randomNum < 50) {
return String.format("[Order1, Order2] for user: %s", userId); // 成功返回
}
// 25% 的概率模拟慢调用/超时
else if (randomNum < 75) {
try {
Thread.sleep(5000); // 模拟超时
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Slow response...";
}
// 25% 的概率模拟服务器错误(5xx)
else {
throw new HttpServerErrorException(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, "Order Service is down!");
}
}
}
2. 应用层服务 (OrderService.java) - 使用 @CircuitBreaker
注解
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Autowired
private OrderServiceClient orderServiceClient;
// 重点:使用 @CircuitBreaker 注解
// name 属性指向配置文件中定义的断路器实例 'orderServiceCircuitBreaker'
// fallbackMethod 属性指定降级方法名 ‘getOrdersFallback’
@CircuitBreaker(name = "orderServiceCircuitBreaker", fallbackMethod = "getOrdersFallback")
public String getOrdersForUser(String userId) {
// 这是受保护的主逻辑
return orderServiceClient.getOrders(userId);
}
// 降级方法 (Fallback Method)
// 它的返回类型必须与主方法兼容,并且必须包含原方法的参数(可额外添加一个 Throwable 参数来接收异常)
private String getOrdersFallback(String userId, Throwable t) {
// 记录日志
System.err.println("CircuitBreaker triggered! Fallback called due to: " + t.getMessage());
// 返回友好的降级响应
return "Order service is temporarily unavailable. Please try again later. (UserId: " + userId + ")";
}
}
3. 控制器 (OrderController.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/users/{userId}/orders")
public String getUserOrders(@PathVariable String userId) {
// 调用被断路器保护的服务方法
return orderService.getOrdersForUser(userId);
}
}
五、测试与监控
-
测试:启动应用,快速多次访问
http://localhost:8080/users/123/orders
。根据OrderServiceClient
中的模拟逻辑,失败率达到阈值(如50%)后,断路器会打开。后续的请求将不再执行getOrdersForUser
主逻辑,而是直接调用getOrdersFallback
方法返回降级信息。等待配置的waitDurationInOpenState
(如10秒)后,断路器会进入半开状态,尝试放行少量请求,根据这些请求的成功与否决定是关闭断路器还是再次打开。 -
监控 (Actuator):如果你引入了 Actuator 依赖并暴露了端点,可以访问以下 URL 查看断路器状态:
-
状态信息:
http://localhost:8080/actuator/health
-
所有断路器详情:
http://localhost:8080/actuator/circuitbreakers
-
特定断路器状态与指标:
http://localhost:8080/actuator/circuitbreakers/orderServiceCircuitBreaker
-
总结
方面 | 基于 Spring Boot + Resilience4j 的实现 |
---|---|
核心注解 | @CircuitBreaker(name = "instanceName", fallbackMethod = "methodName") |
关键概念 | 状态机 (CLOSED, OPEN, HALF_OPEN)、滑动窗口、失败率阈值、降级 |
优点 | 配置简单、功能强大、与 Spring 生态无缝集成、轻量级、监控支持完善。 |
通过上述步骤,你可以在 Spring Boot 应用中轻松地为任何可能失败的接口(尤其是远程调用)添加强大的断路器保护,极大地提升系统的弹性和容错能力。