在微服务架构中,服务之间的通信是非常频繁的。而使用OpenFeign可以极大简化微服务之间的HTTP通信。但在复杂的分布式系统中,服务之间的调用可能会因为网络问题、服务故障等原因而失败。因此,实现服务调用的重试机制显得尤为重要。Resilience4j是一个功能强大的库,它提供了多种容错机制,包括重试(Retry)、熔断(CircuitBreaker)、限流(RateLimiter)等。本篇文章将详细介绍如何在Spring Cloud中使用Resilience4j Retry对OpenFeign进行重试。
一、Resilience4j Retry原理
Resilience4j的Retry模块允许在调用失败时进行自动重试。它支持以下几种特性:
- 自定义重试次数:可以配置最大重试次数。
- 自定义等待时间:可以配置每次重试之间的等待时间。
- 重试条件:可以配置哪些异常类型触发重试。
Resilience4j Retry的工作流程如下:
- 方法调用:对目标方法进行调用。
- 异常捕获:如果目标方法抛出配置的异常,则捕获该异常。
- 重试判断:判断是否满足重试条件以及重试次数是否已达到上限。
- 重试等待:如果满足重试条件且重试次数未达到上限,则等待配置的时间后再次尝试调用。
- 降级处理:如果重试次数达到上限,依然无法成功调用,则执行降级处理逻辑。
二、项目准备
首先,确保你的Spring Cloud项目中已经引入了必要的依赖,包括Spring Cloud OpenFeign和Resilience4j。
1. 引入依赖
在pom.xml
中添加以下依赖:
<!--resilience4j-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- 由于resilience4j需要AOP的包,所以必须导入AOP包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 启用Feign Clients
确保你的Spring Boot应用程序主类上或者配置类上有@EnableFeignClients
注解:
@Configuration
@EnableFeignClients(basePackages = "com.springcloud.sample.service")
@Import(FeignClientsConfiguration.class)
public class FeignConfiguration {
/**
* Set the Feign specific log level to log client REST requests.
*/
@Bean
feign.Logger.Level feignLoggerLevel() {
return feign.Logger.Level.BASIC;
}
}
三、配置Resilience4j Retry
在你的application.yml
或application.properties
文件中配置Resilience4j的Retry策略。例如:
resilience4j.retry:
configs:
default:
maxRetryAttempts: 3
waitDuration: 2s
retryExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
- feign.FeignException
解释:
maxRetryAttempts
: 最大重试次数,这里设置为3次。waitDuration
: 每次重试之间的等待时间,这里设置为2秒。retryExceptions
: 配置哪些异常类型触发重试,这里包括HttpServerErrorException、IOException和FeignException
。
四、创建Feign客户端接口
创建一个Feign客户端接口来定义服务间的调用。例如:
@FeignClient("pay-service")
public interface PayService {
@GetMapping("/pay/{id}")
String payOrder(@PathVariable("id") Integer id);
}
五、使用Retry注解
在调用Feign客户端的方法上添加@Retry
注解,并创建一个fallback方法,用于定义服务调用失败后的降级处理逻辑。例如:
@RestController
public class OrderController {
private static final Logger log = LoggerFactory.getLogger(OrderController.class);
@Autowired
private PayService payService;
@GetMapping("/order/{id}")
@Retry(name = "paymentService", fallbackMethod = "fallback")
public String order(@PathVariable("id") Integer id){
log.info("Request Pay For Order id: {}", id);
//通过open feign远程调用支付服务
return payService.payOrder(id);
}
//fallback就是服务降级后的兜底处理方法
public String fallback(Integer id,Throwable t) {
log.info("Pay Service invoke failed for order ID: {}", id);
log.error("Error: {}", t.getMessage());
return "Pay Service Was Busy Now. Please try again later!";
}
}
通过上述步骤,当payOrder方法调用失败时,Resilience4j的Retry机制将自动进行重试。如果重试次数超过配置的最大重试次数,Fallback类中的降级逻辑将会被执行。
六、测试
我我们通过关闭目标服务(pay-service)来测试重试机制是否正常工作。在目标服务不可用的情况下,请求/order/1
接口,应该会看到系统进行多次重试,然后返回降级信息。
1. 在浏览器中访问order接口
http://localhost:8082/order/1
在访问以上地址后,浏览器并没有立刻返回结果,应该正在进行重试。因为我们已经关闭了目标服务,在等待几秒之后,浏览器返回了降级后的结果。如下:
2. 在控制台中验证是否重试过
从上面的log中我们可以看出,一共请求了3次,和我们配置的maxRetryAttempts:3 一致,每次请求间隔2s,是我们在配置文件中指定的。并且,在最后一次重试任然失败后,走到了降级的方法 fallback中去,返回默认的降级结果。和我们预期的一样,retry能够正常工作。并且在retryExceptions中我们可以选择下游返回哪些异常时进行重试,我们在进行业务逻辑处理时可以灵活应用。
七、总结
通过上述配置和代码示例,我们在Spring Cloud项目中成功集成了Resilience4j的Retry机制,为OpenFeign的服务调用提供了自动重试功能。Resilience4j提供的灵活配置使得我们可以根据实际需求,精细控制重试策略,从而提高系统的可靠性和稳定性。
希望这篇文章能帮助你更好地理解和使用Resilience4j Retry对OpenFeign进行重试。如果你有任何问题或建议,欢迎在评论区留言交流。