早些时候,我们在代码中使用了 Bulkhead、CircuitBreaker 和 Retry,一切都按预期工作。现在我们想使用 TimeLimiter,我们修改了代码以一起使用 ThreadPoolBulkhead、TimeLimiter、CircuitBreaker、Retry 和 Fallback。以下是我们目前的配置:
配置文件:
resilience4j.thread-pool-bulkhead:
configs:
default:
maxThreadPoolSize: 50
coreThreadPoolSize: 10
queueCapacity: 100
keepAliveDuration: 5000
instances:
backendA:
baseConfig: default
resilience4j.timelimiter:
configs:
default:
timeoutDuration: 45000
instances:
backendA:
baseConfig: default
fallbackA:
timeoutDuration: 10000
...
Similar configurations for cicuitBreakers and Retry.
下面是我们如何在代码中使用它:
Decorators
.ofSupplier(() -> test.hello())
.withThreadPoolBulkhead(getThreadPoolBulkheadInstanceFromRegistry())
.withTimeLimiter(getTimeLimiterInstanceFromRegistry(), Executors.newSingleThreadScheduledExecutor())
.withCircuitBreaker(getCircuitBreakerFromRegistry())
.withRetry(getRetryInstanceFromRegistry(), Executors.newSingleThreadScheduledExecutor())
.withFallback(exception -> handleFallback(exception, transaction))
.get()
.toCompletableFuture()
.get();
Fallback 机制与上面相同,唯一的区别是它使用fallbackA
了 timelimiter 的实例,该实例被配置为在 10 秒后超时。
在测试系统时(20 tps,5-10 分钟),一切都按预期工作。但是当我们以相同的 20tps 将负载持续时间增加到 3-4 小时时,我们注意到系统在 40-45 分钟内按预期工作并且交易正在进行;但在那之后所有的交易开始失败。
在没有 TimeLimter 和 ThreadPoolBulkhead 的情况下,同样的事情。
上面的配置有问题吗?另外,当我们有线程池隔板时,为什么我们需要提供单独的 Scheduled Executor 服务?它不应该采用分配给隔板的线程吗?
此外,我们尝试在班级级别更改Executors.newSingleThreadScheduledExecutor()
为。Executors.newScheduledThreadPool(10)
然后一切都按预期在积极的情况下工作,但是当我们在 hello() 上延迟 45 秒并且回退也有延迟(它也应该从那里超时)并且负载保持不变,即 20 tps。我们注意到最初的 2 个事务是成功的,而其余的事务则失败了。但我们不确定为什么这 2 笔交易有效(它们花了大约 1 分 40 秒),它们也应该失败。