熔断器
当某个机器接口失败率达到某一条件(比如失败率>50%),就可以采用熔断器将服务器从集群机器中移除,或者采用自定义的业务逻辑降级方案,比如从一个接口转到另一个接口。熔断器只是一个工具,重要的是业务逻辑。
Resilience4j是什么?
Resilience4j 是受Netflix的Hysrix项目启发,专门为Java 8 和函数式编程设计的轻量级容错框架。Resilicenes4j 仅使用了一个第三方开源库Vavr,Vavr不依赖其他库。相比较而言,Netflix Hysrix对Archaius存在编译依赖,Archaius有许多外部依赖,比如Guava和Apache Commons Configuration。Resilience4j 按模块发布,可以有选择的使用其中某些功能而无需引入全部的Resilience4j 组件。
resilience4j是一款受hystrix启发的容错组件,提供了如下几款核心组件:
- resilience4j-circuitbreaker: Circuit breaking
- resilience4j-ratelimiter: Rate limiting
- resilience4j-bulkhead: Bulkheading
- resilience4j-retry: Automatic retrying (sync and async)
- resilience4j-cache: Response caching
Resilience4j的使用
1. CircuitBreaker(熔断器)
CircuitBreaker主要是实现针对接口异常的断路统计以及断路处理。
@Test
public void testCircuitBreaker(){
// Create a CircuitBreaker (use default configuration)
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig
.custom()
.enableAutomaticTransitionFromOpenToHalfOpen()
.build();
CircuitBreaker circuitBreaker = CircuitBreaker
.of("backendName",circuitBreakerConfig);
String result = circuitBreaker.executeSupplier(() -> backendService.doSomethingWithArgs("world"));
System.out.println(result);
}
2. Timelimiter
主要是实现超时的控制。
@Test
public void testTimelimiter(){
ExecutorService executorService = Executors.newSingleThreadExecutor();
TimeLimiterConfig config = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofMillis(600))
.cancelRunningFuture(true)
.build();
TimeLimiter timeLimiter = TimeLimiter.of(config);
Supplier<Future<String>> futureSupplier = () -> {
return executorService.submit(backendService::doSomethingThrowException);
};
Callable<String> restrictedCall = TimeLimiter.decorateFutureSupplier(timeLimiter,futureSupplier);
Try.of(restrictedCall::call)
.onFailure(throwable -> System.out.println("We might have timed out or the circuit breaker has opened."));
}
3. Bulkhead
Bulkhead目前来看是用来控制并行(parallel)调用的次数。
/**
* A Bulkhead can be used to limit the amount of parallel executions
*/
@Test
public void testBulkhead(){
Bulkhead bulkhead = Bulkhead.of("test", BulkheadConfig.custom()
.maxConcurrentCalls(1)
.build());
Supplier<String> decoratedSupplier = Bulkhead.decorateSupplier(bulkhead, backendService::doSomethingSlowly);
IntStream.rangeClosed(1,2)
.parallel()
.forEach(i -> {
String result = Try.ofSupplier(decoratedSupplier)
.recover(throwable -> "Hello from Recovery").get();
System.out.println(result);
});
}
4. RateLimiter
用来做流控。
public void testRateLimiter(){
// Create a custom RateLimiter configuration
RateLimiterConfig config = RateLimiterConfig.custom()
.timeoutDuration(Duration.ofMillis(100))
.limitRefreshPeriod(Duration.ofSeconds(1))
.limitForPeriod(1)
.build();
// Create a RateLimiter
RateLimiter rateLimiter = RateLimiter.of("backendName", config);
// Decorate your call to BackendService.doSomething()
Supplier<String> restrictedSupplier = RateLimiter
.decorateSupplier(rateLimiter, backendService::doSomething);
IntStream.rangeClosed(1,5)
.parallel()
.forEach(i -> {
Try<String> aTry = Try.ofSupplier(restrictedSupplier);
System.out.println(aTry.isSuccess());
});
}
5. Fallback
fallback基本上是高可用操作的标配。
@Test
public void testFallback(){
// Execute the decorated supplier and recover from any exception
String result = Try.ofSupplier(() -> backendService.doSomethingThrowException())
.recover(throwable -> "Hello from Recovery").get();
System.out.println(result);
}
@Test
public void testCircuitBreakerAndFallback(){
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName");
Supplier<String> decoratedSupplier = CircuitBreaker
.decorateSupplier(circuitBreaker, backendService::doSomethingThrowException);
String result = Try.ofSupplier(decoratedSupplier)
.recover(throwable -> "Hello from Recovery").get();
System.out.println(result);
}
6. Retry
retry用来控制重试。
@Test
public void testRetry(){
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName");
// Create a Retry with at most 3 retries and a fixed time interval between retries of 500ms
Retry retry = Retry.ofDefaults("backendName");
// Decorate your call to BackendService.doSomething() with a CircuitBreaker
Supplier<String> decoratedSupplier = CircuitBreaker
.decorateSupplier(circuitBreaker, backendService::doSomething);
// Decorate your call with automatic retry
decoratedSupplier = Retry
.decorateSupplier(retry, decoratedSupplier);
// Execute the decorated supplier and recover from any exception
String result = Try.ofSupplier(decoratedSupplier)
.recover(throwable -> "Hello from Recovery").get();
System.out.println(result);
}