内容简介: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实现断路器》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Filter Bubble
Eli Pariser / Penguin Press / 2011-5-12 / GBP 16.45
In December 2009, Google began customizing its search results for each user. Instead of giving you the most broadly popular result, Google now tries to predict what you are most likely to click on. Ac......一起来看看 《The Filter Bubble》 这本书的介绍吧!