一、Resilience4j简介
Resilience4j是一个轻量级的容错库,可以帮助开发人员构建弹性和可靠的Java应用程序。其核心概念是“函数式编程”,允许开发人员使用Java 8的函数式编程特性来定义和组合容错策略,使得容错逻辑更加灵活、可读性更高,并且易于测试和维护。
Resilience4j提供了一系列的模块,每个模块都用于解决不同类型的容错问题,以保护应用程序免受故障和异常的影响。以下是其核心模块:
- Circuit Breaker:提供了断路器功能,可以阻止故障的传播和持续的失败调用。
- Rate Limiter:提供了限流功能,可以控制调用的速率,以避免资源耗尽。
- Retry:提供了重试功能,可以在发生错误时重试失败的操作。
- Time Limiter:提供了超时功能,可以设置操作的最大执行时间。
二、各模块工作原理
2.1 断路器(Circuit Breaker)
断路器用于保护系统免受远程服务故障的影响。它通过监控服务调用的健康状况,并在必要时自动中断服务调用,以防止故障蔓延。断路器有三个主要状态:关闭(CLOSED)、打开(OPEN)和半开(HALF_OPEN),通过这些状态的转换来动态调整对服务的调用行为。
- 关闭状态:所有请求都会被正常处理,直到失败率超过阈值。
- 打开状态:一旦失败率超过阈值,断路器进入打开状态,拒绝所有后续请求,以保护系统。
- 半开状态:经过一段时间后,断路器会短暂地进入半开状态,允许少量请求通过以检测服务是否已恢复正常。如果这些请求成功,断路器关闭;如果失败,则重新打开。
2.2 限流器(Rate Limiter)
限流器用于控制对服务的并发请求数量,以防止资源耗尽和系统过载。Resilience4j的限流器主要的限流算法实现:基于原子计数器的限流器(AtomicRateLimiter)和基于信号量的限流器(SemaphoreBasedRateLimiter),默认实现的是AtomicRateLimiter。
- AtomicRateLimiter 算法: 通过原子引用管理其状态,该状态是不可变的,并且包含了周期号、可用权限计数和等待时间等信息。这种算法通过计算当前周期和上一次调用后的可用权限计数来决定是否授予权限。如果可用权限不足以立即执行请求,则请求将等待直至有足够的权限。
- SemaphoreBasedRateLimiter 算法:使用信号量机制来控制对共享资源的访问。信号量有一个内部计数器,用于跟踪可用的许可证数量。当请求到达时,它会尝试获取一个许可证。如果许可证可用,请求将被处理;如果许可证不可用,请求将等待直到有许可证释放。这种算法类似于固定并发数限流,但它是通过信号量实现的,可以动态地管理许可证的分配和回收。
2.3 重试策略(Retry)
重试策略主要是通过设置最大重试次数、重试间隔、重试条件和退避策略等参数,在发生错误或故障时,自动重试请求,直到请求成功或达到最大重试次数。下是重试策略的一些关键特性和原则:
- 最大重试次数(Max Retry Attempts):如果达到最大次数仍然未成功,则重试失败。
- 重试间隔(Wait Interval):在每次重试之间设置一个固定的等待时间,以避免过于频繁地重试。
- 重试条件(Retry Conditions):可以根据特定的错误类型或异常来决定是否重试。
- 退避策略(Backoff Policy):在重试过程中,可以使用退避策略来逐渐增加重试间隔的时间,以避免过度加载服务或资源。
- 重试监听器(Retry Listeners):可以注册重试监听器来监听和记录重试的过程和结果。
2.4 超时控制(Time Limiter)
超时控制主要是防止长时间运行的操作占用资源,确保系统的响应性和稳定性。其核心是内部使用调度器来调度一个超时任务。如果原始操作在超时时间内完成,Time Limiter会取消内部的超时任务。如果操作超时,Time Limiter会抛出一个TimeoutException
来完成CompletableFuture
的任务。
三、Resilience4j 优缺点
优点:
- 轻量级设计:Resilience4j不依赖于任何外部库,只使用Vavr库,这降低了项目的复杂性和依赖风险。
- 功能丰富:除了限流,Resilience4j还提供断路器、缓存、限时和请求重试等多种容错机制,帮助开发者应对分布式系统中的各种挑战。
- 易于使用:Resilience4j采用模块化设计,开发者可以根据需要选择相应的模块进行集成,便于快速上手和定制化。
- 高性能:Resilience4j注重实时性能,能够在高并发、低延迟的场景下提供良好的表现。
- 兼容性好:Resilience4j可以与Spring Cloud等现代Java框架无缝集成,支持基于注解的配置,简化了容器化部署。
- 配置灵活性:Rate Limiter可以通过代码、配置文件或运行时参数进行配置,支持细粒度的限流策略定制,满足复杂的业务场景。
缺点:
- 社区支持:作为一个相对较新的项目,Resilience4j的社区规模和成熟度可能不如一些长期存在的框架,这可能影响到问题解决和功能迭代的速度。
- 监控和管理:Resilience4j本身不提供控制台或集中式管理界面,虽然可以集成其他监控系统,但这可能增加了监控和管理的复杂性。
- 复杂性管理:虽然Resilience4j旨在简化容错逻辑,但在处理非常复杂的容错需求时,可能需要结合其他工具或库来实现。
- 学习曲线:虽然Resilience4j提供了丰富的功能,配置灵活,但毕竟是一个较新的框架,新用户可能需要一定的学习时间来熟悉其配置和使用方式。
四、RateLimiter集成Spring Boot
(1)在pom文件引入相关依赖
<!--resilience4j-ratelimiter-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
</dependency>
<!--resilience4j-circuitbreaker-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- 由于断路保护等需要AOP实现,所以必须导入AOP包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
(2)编辑yml配置文件
resilience4j:
ratelimiter:
configs:
default:
limitForPeriod: 2 #在一次刷新周期内,允许执行的最大请求数
limitRefreshPeriod: 1s # 限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod
timeout-duration: 1 # 线程等待权限的默认等待时间
instances:
cloud-payment-service:
baseConfig: default
(3)在接口上使用@RateLimiter注解
@GetMapping(value = "/feign/pay/{id}")
@RateLimiter(name = "payment-service",fallbackMethod = "myFallback")
public String pay(@PathVariable("id") Integer id) {
return paymentApi.pay(id);
}
public String myFallback(Integer id,Throwable t) {
return "服务器繁忙,请稍后访问!";
}