鉴于 Hystrix 进入维护模式,我一直致力于将(相当大的)代码库迁移到 Resilience4j。
我在 Hystrix 中大量使用以下模式:
new HystrixCommand<SomeReturnValue>(DependencyKeys.DEPENDENCY) {
@Override
protected SomeReturnValue run() {
return someExpensiveCall();
}
}
.observe()
Run Code Online (Sandbox Code Playgroud)
我想用 Resilience4j 复制 Hystrix 的一些功能。
到目前为止,我有以下语法来连接外部调用:
resilience.single(DependencyKeys.DEPENDENCY, this::someExpensiveCall);
Run Code Online (Sandbox Code Playgroud)
其中Resilience
类提供single
方法:
public <T> Single<T> single(ResilienceKey key, Callable<T> callable) {
return Completable.complete()
.subscribeOn(Schedulers.computation())
.observeOn(configuration.scheduler(key))
.andThen(Single.defer(() -> Single.fromCallable(callable)
.lift(CircuitBreakerOperator.of(configuration.circuitBreaker(key)))
.lift(RateLimiterOperator.of(configuration.rateLimiter(key)))
.lift(BulkheadOperator.of(configuration.bulkhead(key)))
))
.observeOn(Schedulers.computation());
}
Run Code Online (Sandbox Code Playgroud)
在断路和在不同线程池上运行代码方面,这看起来如何更好地类似于 Hystrix,但以更理智的方式。我真的不喜欢用 just 来启动链,这样我就可以在实际的可调用对象被包装之前Completable.complete()
强制使用 a 。observeOn
我是断路器的新手,最近在我的一项服务中实现了它们。我正在浏览Resilience 4J 官方文档,发现我们可以为断路器配置两个属性。
上述两个属性都指定必须对服务进行的调用次数,以确定断路器是否应保持打开状态或应关闭状态。我需要了解这两个属性之间的细微差别以及它们之间可能存在的任何关系?它们应该相互独立配置还是两者之间应该存在关系?
另外,以上两者之间是否有关系permittedNumberOfCallsInHalfOpenState
。例如,如果我配置permittedNumberOfCallsInHalfOpenState
为 5,但我的slidingWindowSize
/minimumNumberOfCalls
配置为 10,那么如何重新验证断路器状态?因为它至少需要 10 个请求才能重新评估断路器的新状态,但当它处于打开状态时我们只允许 5 个请求?
我在Spring Boot项目中添加了以下依赖项
implementation 'io.github.resilience4j:resilience4j-spring-boot2:0.14.1'
Run Code Online (Sandbox Code Playgroud)
当断路器断开时,我在执行器/运行状况端点上收到以下响应,状态代码为503 Service Unavailable:
{
"status": "DOWN",
"details": {
"diskSpace": {
"status": "UP",
"details": {
"total": 499963174912,
"free": 432263229440,
"threshold": 10485760
}
},
"refreshScope": {
"status": "UP"
},
"getFlightInfoCircuitBreaker": {
"status": "DOWN",
"details": {
"failureRate": "100.0%",
"failureRateThreshold": "2.0%",
"maxBufferedCalls": 1,
"bufferedCalls": 1,
"failedCalls": 1,
"notPermittedCalls": 1,
"state": "OPEN"
}
}
}
Run Code Online (Sandbox Code Playgroud)
}
我的AWS ECS容器运行状况检查使用此端点来确定其运行状况,并在非200响应时重启容器。
由于我不希望在断路器打开时重新启动服务,是否有办法在不导致服务状态下降的情况下打开断路器?
我知道registerHealthIndicator: false
可以解决此问题的属性,但这仍会删除执行器上的断路器统计信息,我仍然希望看到。
应用程序未启动,但我只添加了一个版本的resilience4j
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.3.1</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
这是日志:
***************************
APPLICATION FAILED TO START
***************************
Description:
An attempt was made to call a method that does not exist. The attempt was made from the following location:
io.github.resilience4j.circuitbreaker.configure.CircuitBreakerConfiguration.createCircuitBreakerRegistry(CircuitBreakerConfiguration.java:141)
The following method did not exist:
io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry.of(Ljava/util/Map;Lio/github/resilience4j/core/registry/RegistryEventConsumer;Lio/vavr/collection/Map;)Lio/github/resilience4j/circuitbreaker/CircuitBreakerRegistry;
The method's class, io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry, is available from the following locations:
jar:file:/Users/Smit/.m2/repository/io/github/resilience4j/resilience4j-circuitbreaker/1.1.0/resilience4j-circuitbreaker-1.1.0.jar!/io/github/resilience4j/circuitbreaker/CircuitBreakerRegistry.class
It was loaded from the following location:
file:/Users/Smit/.m2/repository/io/github/resilience4j/resilience4j-circuitbreaker/1.1.0/resilience4j-circuitbreaker-1.1.0.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry
Process finished …
Run Code Online (Sandbox Code Playgroud) 我正在使用 Resilience4j 进行大量测试并监视线程的行为。
我使用的是 spring-boot 2.2.5,resilience4j 1.4.0。Ga特林(加载工具)、VisualVM(分析线程)
我意识到:
当我使用舱壁类型 = SEMAPHORE 时。
我意识到异步执行将使用默认的 ExecutorService,在这种情况下,ForkJoinPool 和此配置将起作用:
maxConcurrentCalls, maxWaitDuration
Run Code Online (Sandbox Code Playgroud)
如果您使用的是bulkhead type = THREADPOOL,上述配置将被忽略。
当我使用批量 THREADPOOL 时,这些配置将起作用:
maxThreadPoolSize, coreThreadPoolSize, queueCapacity, keepAliveDuration
Run Code Online (Sandbox Code Playgroud)
这些配置将被忽略:
maxConcurrentCalls, maxWaitDuration
Run Code Online (Sandbox Code Playgroud)我的代码:
@CircuitBreaker(name = MyServiceCommand.BEAN_NAME, fallbackMethod = "fallback")
@TimeLimiter(name = MyServiceCommand.BEAN_NAME)
@Bulkhead(name = MyServiceCommand.BEAN_NAME, type = Bulkhead.Type.THREADPOOL)
@Component
@AllArgsConstructor
@Slf4j
public class MyServiceCommand extends ResilienceAbstractCommand {
protected static final String BEAN_NAME = "MyService";
private SlowService slowService;
public CompletableFuture<String> perform() {
return CompletableFuture.completedFuture(slowService.get());
}
private CompletableFuture<String> fallback() {
return CompletableFuture.completedFuture("fallback");
} …
Run Code Online (Sandbox Code Playgroud) 我有一个通过 REST 调用依赖项的服务。服务和依赖是微服务架构的一部分,所以我想使用弹性模式。我的目标是:
下面是我目前的代码。它有效,但理想情况下我想使用TimeLimiter
和Bulkhead
类,因为它们似乎可以协同工作。
我怎样才能更好地写这个?
@Component
class FooService(@Autowired val circuitBreakerRegistry: CircuitBreakerRegistry)
{
...
// State machine to take load off the dependency when slow or unresponsive
private val circuitBreaker = circuitBreakerRegistry
.circuitBreaker("fooService")
// Limit parallel requests to dependency
private var semaphore = Semaphore(maxParallelRequests)
// The protected function
private suspend fun makeHttpCall(customerId: String): Boolean {
val client = webClientProvider.getCachedWebClient(baseUrl)
val response = client
.head()
.uri("/the/request/url")
.awaitExchange()
return when (val status = response.rawStatusCode()) { …
Run Code Online (Sandbox Code Playgroud) 我正在使用 Resilience4j 断路器版本:'1.4.0 和 Spring boot 版本 2.0.6,我的问题是 - 回退方法不起作用。该调用不会转到后备方法。下面是我的代码:
@Override
@CircuitBreaker(name="mainService",fallbackMethod = "callFallback")
public JSONObject callService(JSONObject rawRequest) throws TimeoutException {
...
throw new TimeoutException("Time occured while calling
service");
...
}
Run Code Online (Sandbox Code Playgroud)
-- 和后备方法:
private JSONObject callFallback(JSONObject rawRequest,Throwable t){
System.out.println("Inside fallback method callNsFallback,
cause"+t.toString());
logger.info("Inside fallback method callFallback,
cause - {}",t.toString());
return rawRequest;
}
Run Code Online (Sandbox Code Playgroud)
--application.yml中的配置
resilience4j:
circuitbreaker:
configs:
default:
registerHealthIndicator: true
ringBufferSizeInClosedState: 5
ringBufferSizeInHalfOpenState: 3
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 1s
failureRateThreshold: 50
eventConsumerBufferSize: 10
recordExceptions:
- …
Run Code Online (Sandbox Code Playgroud) 请帮助我找到断路器和隔板模式在 Spring Reactor 应用程序中有用的原因。
由于 Reactor 中的操作将是非阻塞的,并且这两种模式旨在节省对资源(主要是线程)的潜在影响,因此在什么情况下我可以使 Spring Reactor 应用程序中的模式受益。我此时看到的唯一一件事是,如果请求量非常大,以至于将它们保留在内存中,那么在等待超时(而不是断路器启动并回落)时,我们会运行 OOM。
我在 Spring Boot 项目中使用 Resilience4J 来调用 REST 客户端,如下所示:
@Retry(name = "customerService")
public Customer getCustomer(String customerNumber) {
restTemplate.exchange("https://customer-service.net", HttpMethod.GET, ..., customerNumber);
}
Run Code Online (Sandbox Code Playgroud)
使用此配置:
resilience4j.retry:
instances:
customerService:
maxAttempts: 3
waitDuration: 10s
retryExceptions:
- org.springframework.web.client.HttpServerErrorException
Run Code Online (Sandbox Code Playgroud)
我的期望是,如果restTemplate.exchange()
调用 且客户服务以 a 响应HttpServerErrorException
,则该getCustomer()
方法将在等待 10 秒后再调用 3 次。
然而,这种情况并非如此。
该方法不会再被调用,并且会立即抛出异常。
看到示例中包含后备方法,我决定添加它,即使我真的不想调用不同的方法,我只想再次调用我的原始方法。
无论如何,我指定了一个回退:
@Retry(name = "customerService", fallback = "customerFb")
public Customer getCustomer(String customerNumber) {
return getCustomer();
}
private Customer customerFb(String customerNumber, HttpServerErrorException ex) {
log.error("Could not retrieve customer... retrying...");
return getCustomer();
}
private …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用Resilience4j功能。
我的用例是将这 3 个模块结合起来:
我想组合所有这些模块并仅执行该方法一次。
这是我尝试过的。
Supplier<R> supplier = this::doSomething;
timeLimiter.executeFutureSupplier(() -> CompletableFuture.supplyAsync(supplier));
return Decorators.ofSupplier(supplier)
.withCircuitBreaker(circuitBreaker)
.withRetry(retry)
.withBulkhead(bulkhead)
.decorate();
Run Code Online (Sandbox Code Playgroud)
我的doSomething()
方法执行了两次,而不是预期的一次。
有人之前见过这个问题吗?
execution circuit-breaker time-limiting resilience4j resilience4j-retry
resilience4j ×10
spring-boot ×6
java ×3
spring ×2
execution ×1
hystrix ×1
maven ×1
rx-java2 ×1