内容简介:Resilience 4j提供以下功能。如果您打算在Spring Boot中使用它,可以使用Starter。请注意,Spring Boot 1.x和2.x系列之间的artifactId似乎有所不同。另外,上面只包含CircuitBreaker和RateLimiter,在使用其他功能时需要单独添加依赖项。(由于未准备好AutoConfigure,您还需要自己定义bean。)这次我将总结如何在Spring Boot 2.x系列中使用CircuitBreaker和RateLimiter。
Resilience 4j提供以下功能。
- 断路器
- RateLimiter
- 舱壁
- 重试
- 高速缓存
- TimeLimiter
如果您打算在Spring Boot中使用它,可以使用Starter。请注意,Spring Boot 1.x和2.x系列之间的artifactId似乎有所不同。另外,上面只包含CircuitBreaker和RateLimiter,在使用其他功能时需要单独添加依赖项。(由于未准备好AutoConfigure,您还需要自己定义bean。)
这次我将总结如何在Spring Boot 2.x系列中使用CircuitBreaker和RateLimiter。
环境
- JDK 8
- Spring Boot 2.1.2.RELEASE
- Resilience 4j 0.13.2
断路器
当某些具有微服务的服务发生故障时,可以临时阻止对故障服务的访问并防止故障传播。
CircuitBreaker有三种状态:Closed,Open,HalfOpen。如果是正常的,则它是关闭的,如果处理失败超过一定数量,它将变为打开并且访问被阻止。当在打开状态下经过一段时间后,进入HalfOpen状态。如果处理在HalfOpen状态下失败超过一定量,则返回到关闭状态。
在Resilience 4j中,处理的成功和失败由环形缓冲器Ring Bit Buffer管理,并且当缓冲器中的故障数超过设定的速率时,状态转变。
断路器使用状态中的Ring Bit Buffer CLOSED来存储呼叫的成功或失败状态。成功的呼叫存储为0位,失败的呼叫存储为1位。Ring Bit Buffer具有(可配置的)固定大小。环位缓冲区在内部使用类似数据结构的 BitSet 来存储与布尔数组相比节省内存的位。BitSet使用long []数组来存储这些位。这意味着BitSet只需要一个包含16个长(64位)值的数组来存储1024个调用的状态。
例如,如果环形缓冲区的大小为10,则必须至少评估10个调用,然后才能计算故障率。如果仅评估了9个呼叫,即使所有9个呼叫都失败,断路器也不会打开。
用于Closed - > Open和HalfOpen - > Closed判断的环形缓冲区是不同的,可以定义大小,但使用相同的判断条件(错误率)。
在持续关闭时间结束后,断路器状态从OPEN更改为HALF_OPEN并允许调用以查看后端是否仍然不可用或已再次可用。
断路器使用另一个(可配置的)环位缓冲区来评估HALF_OPEN状态中的故障率。如果故障率高于配置的阈值,则状态将更改回OPEN。如果故障率低于或等于阈值,则状态变回CLOSED。
此外,处理的成功和失败由异常判断。默认情况下,如果任何异常抛出异常,则会将其视为处理失败,但您也可以指定要将其视为失败的条件。
设置
application.yml你可以设置定义多个断路器。
resilience4j: circuitbreaker: backends: circuitA: # #断路器名 truering-buffer-size-in-closed-state: 5 #环形缓冲区是在封闭状态下使用的大小 ring-buffer-size-in-half-open-state: 3 # HalfOpen 状态下的大小 wait-duration-in-open-state : 5000 # Open持续时间 failure-rate-threshold: 50 # 到打开状态的阈值 record-failure-predicate: com.example.resilience.RecordFailurePredicate ignore-exceptions: #没有失败#异常类和计数 - com.example.resilience.exception.BusinessException record-exceptions: #异常类失败和计数 - com.example.resilience.exception.SystemException circuitB: ・・・
如果你想只考虑一个特定的异常和故障使用RecordExceptions,当你不想忽视特定的异常时使用ignoreExceptions。
有两种方法可以使用Spring AOP并在函数中实现它。无论哪种实现,如果Circuit处于Open状态,它将生成CircuitBreakerOpenException。
在以下实现示例中,为简单起见,它不是微服务。最初RestTemplate,我认为这将是Service Class 调用其他服务API等使用等的过程。
Spring AOP实现
通过@CircuitBreaker(name = "hogehoge")注释到类或方法上则可以启用断路器。如果在类指定这个注释,则为所有公共方法启用断路器。
@Service @CircuitBreaker(name = <font>"circuitB"</font><font>) <b>public</b> <b>class</b> CircuitBreakerService { <b>public</b> String aop(String str) { <b>if</b> (str == <b>null</b>) { <b>throw</b> <b>new</b> RuntimeException(); } <b>return</b> </font><font>"success!!"</font><font>; } } </font>
调用者不用考虑任何事情,只需执行该方法即可。
@RestController @RequestMapping(<font>"/circuit"</font><font>) <b>public</b> <b>class</b> CircuitBreakerController { <b>private</b> <b>final</b> CircuitBreakerService service; <b>public</b> CircuitBreakerController(CircuitBreakerService service) { <b>this</b>.service = service; } @GetMapping(</font><font>"/aop"</font><font>) <b>public</b> String aop(@RequestParam(required = false) String str) { <b>return</b> service.aop(str); } } </font>
如何写业务函数?
@Service <b>public</b> <b>class</b> CircuitBreakerService { <b>public</b> String func(String str) { <b>if</b> (str == <b>null</b>) { <b>throw</b> <b>new</b> RuntimeException(); } <b>return</b> <font>"success!!"</font><font>; } } </font>
调用端使用断路器的decorate~方法修饰要调用的方法。
@RestController @RequestMapping(<font>"/circuit"</font><font>) <b>public</b> <b>class</b> CircuitBreakerController { <b>private</b> <b>final</b> CircuitBreaker circuitBreaker; <b>private</b> <b>final</b> CircuitBreakerService service; <b>public</b> CircuitBreakerController(CircuitBreakerRegistry registry, CircuitBreakerService service) { <b>this</b>.circuitBreaker = registry.circuitBreaker(</font><font>"circuitA"</font><font>); <b>this</b>.service = service; } @GetMapping(</font><font>"/func"</font><font>) <b>public</b> String func(@RequestParam(required = false) String str) { <b>return</b> CircuitBreaker.decorateSupplier(circuitBreaker, () -> service.func(str)).get(); } } </font>
后备处理
接下来,如果发生故障,执行回退过程怎么办?在Hystrix 的情况下,通过指定@HystrixCommand("hogeMethod"),由于Resilience4j没有设置的这样的功能,必须自己实现。
@RestController @RequestMapping(<font>"/circuit"</font><font>) <b>public</b> <b>class</b> CircuitBreakerController { <b>private</b> <b>final</b> CircuitBreaker circuitBreaker; <b>private</b> <b>final</b> CircuitBreakerService service; <b>public</b> CircuitBreakerController(CircuitBreakerRegistry registry, CircuitBreakerService service) { <b>this</b>.circuitBreaker = registry.circuitBreaker(</font><font>"circuitA"</font><font>); <b>this</b>.service = service; } @GetMapping(</font><font>"/func"</font><font>) <b>public</b> String func(@RequestParam(required = false) String str) { <b>return</b> Try.ofSupplier(CircuitBreaker.decorateSupplier(circuitBreaker, () -> service.func(str))) .recover(CircuitBreakerOpenException.<b>class</b>, </font><font>"Circuit is Open!!"</font><font>) .recover(RuntimeException.<b>class</b>, </font><font>"fallback!!"</font><font>).get(); } } </font>
完整的源代码位于下方。 https://github.com/d-yosh/spring-boot-resilience4j-example
RateLimiter
您可以限制每单位时间的执行次数。
单位时间是一个周期,并且可以在一个周期中执行的数量是有限的。如果它超过了可以在一个循环中执行的上限,则让它等待,如果等待时间超过超时时间,则发生RequestNotPermitted。
在application.yml可以定义多个RateLimiter。
resilience4j:
ratelimiter:
limiters:
limiterA: # #RateLimiter名称
limit-for-period: 1 # 每时间单位#可执行处理数
limit-refresh-period-in-millis: 10000 # #单位时间(毫秒)
timeout-in-millis: 10000 #timeout time(milliseconds)
limiterB:
・・・
它与断路器实现方式相同,有两种方法可以使用Spring AOP并在业务函数中编写它。实现方法也类似于断路器。
@Service @RateLimiter(name = <font>"limiterB"</font><font>) <b>public</b> <b>class</b> RateLimiterService { <b>public</b> String func() { <b>return</b> LocalDateTime.now().toString(); } } </font>
调用者不用考虑任何事情,只需执行该方法即可。
@RestController @RequestMapping(<font>"/ratelimiter"</font><font>) <b>public</b> <b>class</b> RateLimiterController { <b>private</b> <b>final</b> RateLimiterService service; <b>public</b> RateLimiterController(RateLimiterService service) { <b>this</b>.service = service; } @GetMapping(</font><font>"aop"</font><font>) <b>public</b> String aop() { <b>return</b> service.aop(); } } </font>
函数方法:
@Service <b>public</b> <b>class</b> RateLimiterService { <b>public</b> String func() { <b>return</b> LocalDateTime.now().toString(); } } @RestController @RequestMapping(<font>"/ratelimiter"</font><font>) <b>public</b> <b>class</b> RateLimiterController { <b>private</b> <b>final</b> RateLimiter rateLimiter; <b>private</b> <b>final</b> RateLimiterService service; <b>public</b> RateLimiterController(RateLimiterRegistry registry, RateLimiterService service) { <b>this</b>.rateLimiter = registry.rateLimiter(</font><font>"limiterA"</font><font>); <b>this</b>.service = service; } @GetMapping(</font><font>"func"</font><font>) <b>public</b> String func() { <b>return</b> Try.ofSupplier(RateLimiter.decorateSupplier(rateLimiter, service::func)) .recover(RequestNotPermitted.<b>class</b>, </font><font>"Request Not Permitted!!"</font><font>).get(); } } </font>
后备处理,与断路器一样,没有自动执行回退处理的机制,因此您需要自己实现它。
完整的源代码位于下方。 https://github.com/d-yosh/spring-boot-resilience4j-example
单位时间为5秒,超时时间为1秒,每单位时间的执行次数为1。如果同时发送多个请求,则会发出失败请求。(如果您同时请求三个,则至少一个将始终失败。)
$ curl http:<font><i>//localhost:8080/ratelimiter/func</i></font><font> 2019-01-22T23:09:35.612 $ curl http:</font><font><i>//localhost:8080/ratelimiter/func</i></font><font> Request Not Permitted!! </font>
以上所述就是小编给大家介绍的《使用Spring Boot + Resilience 4j实现断路器》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- SpringCloud学习系列之三----- 断路器(Hystrix)和断路器监控(Dashboard)
- 用断路器驯服数据质量
- SpringCloud 断路器(Hystrix)
- 云设计模式之: 断路器模式
- Java EE的断路器API设计
- 微服务断路器Istio与Hystrix比较
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
产品心经:产品经理应该知道的60件事(第2版)
闫荣 / 机械工业出版社 / 2016-4 / 69.00
本书第一版出版后广获好评,应广大读者要求,作者把自己在实践中新近总结的10个关于产品的最佳实践融入到了这本新书中。这"10件事"侧重于深挖产品需求和产品疯传背后的秘密,配合之前的"50件事",不仅能帮产品经理打造出让用户尖叫并疯传的产品,还能帮助产品经理迅速全方位提升自己的能力。 本书作者有超过10年的产品工作经验,在互联网产品领域公认的大咖,这本书从产品经理核心素养、产品认知、战略与规划、......一起来看看 《产品心经:产品经理应该知道的60件事(第2版)》 这本书的介绍吧!