共计 16553 个字符,预计需要花费 42 分钟才能阅读完成。
到目前为止,在本系列中,咱们曾经理解了 Resilience4j 及其 Retry, RateLimiter, TimeLimiter, 和 Bulkhead 模块。在本文中,咱们将摸索 CircuitBreaker 模块。咱们将理解何时以及如何应用它,并查看一些示例。
代码示例
本文附有 GitHub 上的工作代码示例。
什么是 Resilience4j?
请参阅上一篇文章中的形容,疾速理解 Resilience4j 的个别工作原理。
什么是断路器?
断路器的思维是,如果咱们晓得调用可能会失败或超时,则阻止对近程服务的调用。咱们这样做是为了不会在咱们的服务和近程服务中不必要地节约要害资源。这样的退出也给了近程服务一些工夫来复原。
咱们怎么晓得一个调用可能会失败?通过跟踪对近程服务收回的先前申请的后果。例如,如果前 10 次调用中有 8 次导致失败或超时,则下一次调用也可能会失败。
断路器通过包装对近程服务的调用来跟踪响应。在失常运行期间,当近程服务胜利响应时,咱们说断路器处于“闭合”状态。当处于敞开状态时,断路器失常将申请传递给近程服务。
当近程服务返回谬误或超时时,断路器会减少一个外部计数器。如果谬误计数超过配置的阈值,断路器将切换到“断开”状态。当处于断开状态时,断路器立刻向调用者返回谬误,甚至无需尝试近程调用。
通过一段配置的工夫后,断路器从断开状态切换到“半开”状态。在这种状态下,它容许一些申请传递到近程服务以查看它是否依然不可用或迟缓。如果错误率或慢呼叫率高于配置的阈值,则切换回断开状态。然而,如果错误率或慢呼叫率低于配置的阈值,则切换到敞开状态以恢复正常操作。
断路器的类型
断路器能够基于计数或基于工夫。如果最初 N 次调用失败或迟缓,则基于计数的断路器将状态从敞开切换为断开。如果最初 N 秒的响应失败或迟缓,则基于工夫的断路器将切换到断开状态。在这两个断路器中,咱们还能够指定失败或慢速调用的阈值。
例如,如果最近 25 次调用中有 70% 失败或须要 2 秒以上能力实现,咱们能够配置一个基于计数的断路器来“断开电路”。同样,如果过来 30 秒内 80% 的调用失败或耗时超过 5 秒,咱们能够通知基于工夫的断路器断开电路。
Resilience4j 的 CircuitBreaker 概念
resilience4j-circuitbreaker 的工作原理与其余 Resilience4j 模块相似。咱们提供想要作为函数结构执行的代码——一个进行近程调用的 lambda 表达式或一个从近程服务中检索到的某个值的 Supplier,等等——并且断路器用代码润饰它 如果须要,跟踪响应并切换状态。
Resilience4j 同时反对基于计数和基于工夫的断路器。
咱们应用 slidingWindowType()
配置指定断路器的类型。此配置能够采纳两个值之一 –SlidingWindowType.COUNT_BASED
或 SlidingWindowType.TIME_BASED
。
failureRateThreshold()
和 slowCallRateThreshold()
以百分比模式配置失败率阈值和慢速调用率。
slowCallDurationThreshold()
以秒为单位配置调用被认为慢的工夫。
咱们能够指定一个 minimumNumberOfCalls()
,在断路器能够计算错误率或慢速调用率之前须要它。
如前所述,断路器在肯定工夫后从断开状态切换到半断开状态,以查看近程服务的状况。waitDurationInOpenState()
指定断路器在切换到半开状态之前应期待的工夫。
permittedNumberOfCallsInHalfOpenState()
配置在半开状态下容许的调用次数,maxWaitDurationInHalfOpenState()
确定断路器在切换回开状态之前能够放弃在半开状态的工夫。
此配置的默认值 0 意味着断路器将有限期待,直到所有 permittedNumberOfCallsInHalfOpenState()
实现。
默认状况下,断路器将任何异样视为失败。然而咱们能够对此进行调整,以应用 recordExceptions()
配置指定应视为失败的异样列表和应用 ignoreExceptions()
配置疏忽的异样列表。
如果咱们在确定异样应该被视为失败还是疏忽时想要更精密的管制,咱们能够提供 Predicate<Throwable>
作为 recordException()
或 ignoreException()
配置。
当断路器回绝处于断开状态的呼叫时,它会抛出 CallNotPermittedException
。咱们能够应用 writablestacktraceEnabled()
配置管制 CallNotPermittedException
的堆栈跟踪中的信息量。
应用 Resilience4j CircuitBreaker 模块
让咱们看看如何应用
resilience4j-circuitbreaker 模块中可用的各种性能。
咱们将应用与本系列前几篇文章雷同的示例。假如咱们正在为一家航空公司建设一个网站,以容许其客户搜寻和预订航班。咱们的服务与 FlightSearchService
类封装的近程服务对话。
应用 Resilience4j 断路器时,CircuitBreakerRegistry
、CircuitBreakerConfig
和 CircuitBreaker
是咱们应用的次要形象。
CircuitBreakerRegistry
是用于创立和治理 CircuitBreaker
对象的工厂。
CircuitBreakerConfig
封装了上一节中的所有配置。每个 CircuitBreaker
对象都与一个 CircuitBreakerConfig
相关联。
第一步是创立一个 CircuitBreakerConfig
:
CircuitBreakerConfig config = CircuitBreakerConfig.ofDefaults();
这将创立一个具备以下默认值的 CircuitBreakerConfig:
配置 | 默认值 |
---|---|
slidingWindowType | COUNT_BASED |
failureRateThreshold | 50% |
slowCallRateThreshold | 100% |
slowCallDurationThreshold | 60s |
minimumNumberOfCalls | 100 |
permittedNumberOfCallsInHalfOpenState | 10 |
maxWaitDurationInHalfOpenState | 0s |
基于计数的断路器
假如咱们心愿断路器在最近 10 次调用中有 70% 失败时断开:
CircuitBreakerConfig config = CircuitBreakerConfig
.custom()
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(10)
.failureRateThreshold(70.0f)
.build();
而后咱们用这个配置创立一个 CircuitBreaker
:
CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config);
CircuitBreaker circuitBreaker = registry.circuitBreaker("flightSearchService");
当初让咱们表白咱们的代码以作为 Supplier
运行航班搜寻并应用 circuitbreaker
装璜它:
Supplier<List<Flight>> flightsSupplier =
() -> service.searchFlights(request);
Supplier<List<Flight>> decoratedFlightsSupplier =
circuitBreaker.decorateSupplier(flightsSupplier);
最初,让咱们调用几次润饰操作来理解断路器的工作原理。咱们能够应用 CompletableFuture
来模仿来自用户的并发航班搜寻申请:
for (int i=0; i<20; i++) {
try {System.out.println(decoratedFlightsSupplier.get());
}
catch (...) {// Exception handling}
}
输入显示前几次航行搜寻胜利,而后是 7 次航行搜寻失败。此时,断路器断开并为后续调用抛出 CallNotPermittedException
:
Searching for flights; current time = 12:01:12 884
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
Searching for flights; current time = 12:01:12 954
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
Searching for flights; current time = 12:01:12 957
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
Searching for flights; current time = 12:01:12 958
io.reflectoring.resilience4j.circuitbreaker.exceptions.FlightServiceException: Error occurred during flight search
... stack trace omitted ...
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
... other lines omitted ...
io.reflectoring.resilience4j.circuitbreaker.Examples.countBasedSlidingWindow_FailedCalls(Examples.java:56)
at io.reflectoring.resilience4j.circuitbreaker.Examples.main(Examples.java:229)
当初,假如咱们心愿断路器在最初 10 个调用中有 70% 须要 2 秒或更长时间能力实现:
CircuitBreakerConfig config = CircuitBreakerConfig
.custom()
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(10)
.slowCallRateThreshold(70.0f)
.slowCallDurationThreshold(Duration.ofSeconds(2))
.build();
示例输入中的工夫戳显示申请始终须要 2 秒能力实现。在 7 次迟缓响应后,断路器断开并且不容许进一步调用:
Searching for flights; current time = 12:26:27 901
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
Searching for flights; current time = 12:26:29 953
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
Searching for flights; current time = 12:26:31 957
Flight search successful
... other lines omitted ...
Searching for flights; current time = 12:26:43 966
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
... stack trace omitted ...
at io.reflectoring.resilience4j.circuitbreaker.Examples.main(Examples.java:231)
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
... stack trace omitted ...
at io.reflectoring.resilience4j.circuitbreaker.Examples.main(Examples.java:231)
通常咱们会配置一个具备故障率和慢速调用率阈值的断路器:
CircuitBreakerConfig config = CircuitBreakerConfig
.custom()
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(10)
.failureRateThreshold(70.0f)
.slowCallRateThreshold(70.0f)
.slowCallDurationThreshold(Duration.ofSeconds(2))
.build();
基于工夫的断路器
假如咱们心愿断路器在过来 10 秒内 70% 的申请失败时断开:
CircuitBreakerConfig config = CircuitBreakerConfig
.custom()
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(10)
.failureRateThreshold(70.0f)
.slowCallRateThreshold(70.0f)
.slowCallDurationThreshold(Duration.ofSeconds(2))
.build();
咱们创立了 CircuitBreaker
,将航班搜寻调用示意为 Supplier<List<Flight>>
并应用 CircuitBreaker
对其进行装璜,就像咱们在上一节中所做的那样。
以下是屡次调用润饰操作后的示例输入:
Start time: 18:51:01 552
Searching for flights; current time = 18:51:01 582
Flight search successful
[Flight{flightNumber='XY 765', ...}]
... other lines omitted ...
Searching for flights; current time = 18:51:01 631
io.reflectoring.resilience4j.circuitbreaker.exceptions.FlightServiceException: Error occurred during flight search
... stack trace omitted ...
Searching for flights; current time = 18:51:01 632
io.reflectoring.resilience4j.circuitbreaker.exceptions.FlightServiceException: Error occurred during flight search
... stack trace omitted ...
Searching for flights; current time = 18:51:01 633
... other lines omitted ...
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
... other lines omitted ...
前 3 个申请胜利,接下来的 7 个申请失败。此时断路器断开,后续申请因抛出 CallNotPermittedException
而失败。
当初,假如咱们心愿断路器在过来 10 秒内 70% 的调用须要 1 秒或更长时间能力实现:
CircuitBreakerConfig config = CircuitBreakerConfig
.custom()
.slidingWindowType(SlidingWindowType.TIME_BASED)
.minimumNumberOfCalls(10)
.slidingWindowSize(10)
.slowCallRateThreshold(70.0f)
.slowCallDurationThreshold(Duration.ofSeconds(1))
.build();
示例输入中的工夫戳显示申请始终须要 1 秒能力实现。在 10 个申请(minimumNumberOfCalls
)之后,当断路器确定 70% 的先前申请破费了 1 秒或更长时间时,它断开电路:
Start time: 19:06:37 957
Searching for flights; current time = 19:06:37 979
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 19:06:39 066
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 19:06:40 070
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 19:06:41 070
... other lines omitted ...
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
... stack trace omitted ...
通常咱们会配置一个具备故障率和慢速调用率阈值的基于工夫的断路器:
指定断开状态下的等待时间
假如咱们心愿断路器处于断开状态时期待 10 秒,而后转换到半断开状态并让一些申请传递到近程服务:
CircuitBreakerConfig config = CircuitBreakerConfig
.custom()
.slidingWindowType(SlidingWindowType.TIME_BASED)
.slidingWindowSize(10)
.minimumNumberOfCalls(10)
.failureRateThreshold(70.0f)
.slowCallRateThreshold(70.0f)
.slowCallDurationThreshold(Duration.ofSeconds(2))
.build();
示例输入中的工夫戳显示断路器最后转换为断开状态,在接下来的 10 秒内阻止一些调用,而后更改为半断开状态。起初,在半开状态时统一的胜利响应导致它再次切换到敞开状态:
Searching for flights; current time = 20:55:58 735
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 20:55:59 812
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 20:56:00 816
... other lines omitted ...
io.reflectoring.resilience4j.circuitbreaker.exceptions.FlightServiceException: Flight search failed
at
... stack trace omitted ...
2020-12-13T20:56:03.850115+05:30: CircuitBreaker 'flightSearchService' changed state from CLOSED to OPEN
2020-12-13T20:56:04.851700+05:30: CircuitBreaker 'flightSearchService' recorded a call which was not permitted.
2020-12-13T20:56:05.852220+05:30: CircuitBreaker 'flightSearchService' recorded a call which was not permitted.
2020-12-13T20:56:06.855338+05:30: CircuitBreaker 'flightSearchService' recorded a call which was not permitted.
... other similar lines omitted ...
2020-12-13T20:56:12.862362+05:30: CircuitBreaker 'flightSearchService' recorded a call which was not permitted.
2020-12-13T20:56:13.865436+05:30: CircuitBreaker 'flightSearchService' changed state from OPEN to HALF_OPEN
Searching for flights; current time = 20:56:13 865
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
... other similar lines omitted ...
2020-12-13T20:56:16.877230+05:30: CircuitBreaker 'flightSearchService' changed state from HALF_OPEN to CLOSED
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 20:56:17 879
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
... other similar lines omitted ...
指定回退办法
应用断路器时的常见模式是指定在电路断开时要调用的回退办法。 回退办法能够为不容许的近程调用提供一些默认值或行为 。
咱们能够应用 Decorators
实用程序类进行设置。Decorators
是来自 resilience4j-all
模块的构建器,具备 withCircuitBreaker()
、withRetry()
、withRateLimiter()
等办法,可帮忙将多个 Resilience4j 装璜器利用于 Supplier
、Function
等。
当断路器断开并抛出 CallNotPermittedException
时,咱们将应用它的 withFallback()
办法从本地缓存返回航班搜寻后果:
Supplier<List<Flight>> flightsSupplier = () -> service.searchFlights(request);
Supplier<List<Flight>> decorated = Decorators
.ofSupplier(flightsSupplier)
.withCircuitBreaker(circuitBreaker)
.withFallback(Arrays.asList(CallNotPermittedException.class),
e -> this.getFlightSearchResultsFromCache(request))
.decorate();
以下示例输入显示了断路器断开后从缓存中返回的搜寻后果:
Searching for flights; current time = 22:08:29 735
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 22:08:29 854
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 22:08:29 855
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Searching for flights; current time = 22:08:29 855
2020-12-13T22:08:29.856277+05:30: CircuitBreaker 'flightSearchService' recorded an error: 'io.reflectoring.resilience4j.circuitbreaker.exceptions.FlightServiceException: Error occurred during flight search'. Elapsed time: 0 ms
Searching for flights; current time = 22:08:29 912
... other lines omitted ...
2020-12-13T22:08:29.926691+05:30: CircuitBreaker 'flightSearchService' changed state from CLOSED to OPEN
Returning flight search results from cache
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
Returning flight search results from cache
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... }]
... other lines omitted ...
缩小 Stacktrace 中的信息
每当断路器断开时,它就会抛出 CallNotPermittedException
:
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
at io.github.resilience4j.circuitbreaker.CallNotPermittedException.createCallNotPermittedException(CallNotPermittedException.java:48)
... other lines in stack trace omitted ...
at io.reflectoring.resilience4j.circuitbreaker.Examples.timeBasedSlidingWindow_SlowCalls(Examples.java:169)
at io.reflectoring.resilience4j.circuitbreaker.Examples.main(Examples.java:263)
除了第一行,堆栈跟踪中的其余行没有减少太多价值。如果 CallNotPermittedException
产生屡次,这些堆栈跟踪即将在咱们的日志文件中反复。
咱们能够通过将 writablestacktraceEnabled()
配置设置为 false
来缩小堆栈跟踪中生成的信息量:
CircuitBreakerConfig config = CircuitBreakerConfig
.custom()
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(10)
.failureRateThreshold(70.0f)
.writablestacktraceEnabled(false)
.build();
当初,当 CallNotPermittedException
产生时,堆栈跟踪中只存在一行:
Searching for flights; current time = 20:29:24 476
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
Searching for flights; current time = 20:29:24 540
Flight search successful
[Flight{flightNumber='XY 765', flightDate='12/31/2020', from='NYC', to='LAX'}, ... ]
... other lines omitted ...
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'flightSearchService' is OPEN and does not permit further calls
...
其余有用的办法
与 Retry 模块相似,CircuitBreaker
也有像 ignoreExceptions()
、recordExceptions()
等办法,让咱们能够指定 CircuitBreaker
在跟踪调用后果时应该疏忽和思考哪些异样。
例如,咱们可能不想疏忽来自近程航行服务的 SeatsUnavailableException
– 在这种状况下,咱们真的不想断开电路。
与咱们见过的其余 Resilience4j 模块相似,CircuitBreaker
还提供了额定的办法,如 decorateCheckedSupplier()
、decorateCompletionStage()
、decorateRunnable()
、decorateConsumer()
等,因而咱们能够在 Supplier
之外的其余构造中提供咱们的代码。
断路器事件
CircuitBreaker
有一个 EventPublisher
能够生成以下类型的事件:
CircuitBreakerOnSuccessEvent
,CircuitBreakerOnErrorEvent
,CircuitBreakerOnStateTransitionEvent
,CircuitBreakerOnResetEvent
,CircuitBreakerOnIgnoredErrorEvent
,CircuitBreakerOnCallNotPermittedEvent
,CircuitBreakerOnFailureRateExceededEvent
以及CircuitBreakerOnSlowCallRateExceededEvent
.
咱们能够监听这些事件并记录它们,例如:
circuitBreaker.getEventPublisher()
.onCallNotPermitted(e -> System.out.println(e.toString()));
circuitBreaker.getEventPublisher()
.onError(e -> System.out.println(e.toString()));
circuitBreaker.getEventPublisher()
.onFailureRateExceeded(e -> System.out.println(e.toString()));
circuitBreaker.getEventPublisher().onStateTransition(e -> System.out.println(e.toString()));
以下是示例的日志输入:
2020-12-13T22:25:52.972943+05:30: CircuitBreaker 'flightSearchService' recorded an error: 'io.reflectoring.resilience4j.circuitbreaker.exceptions.FlightServiceException: Error occurred during flight search'. Elapsed time: 0 ms
Searching for flights; current time = 22:25:52 973
... other lines omitted ...
2020-12-13T22:25:52.974448+05:30: CircuitBreaker 'flightSearchService' exceeded failure rate threshold. Current failure rate: 70.0
2020-12-13T22:25:52.984300+05:30: CircuitBreaker 'flightSearchService' changed state from CLOSED to OPEN
2020-12-13T22:25:52.985057+05:30: CircuitBreaker 'flightSearchService' recorded a call which was not permitted.
... other lines omitted ...
CircuitBreaker 指标
CircuitBreake 裸露了许多指标,这些是一些重要的条目:
- 胜利、失败或疏忽的调用总数 (
resilience4j.circuitbreaker.calls
) - 断路器状态 (
resilience4j.circuitbreaker.state
) - 断路器故障率 (
resilience4j.circuitbreaker.failure.rate
) - 未被容许的调用总数 (
resilience4.circuitbreaker.not.permitted.calls
) - 断路器的迟缓调用 (
resilience4j.circuitbreaker.slow.call.rate
)
首先,咱们像平常一样创立 CircuitBreakerConfig
、CircuitBreakerRegistry
和 CircuitBreaker
。而后,咱们创立一个 MeterRegistry
并将 CircuitBreakerRegistry
绑定到它:
MeterRegistry meterRegistry = new SimpleMeterRegistry();
TaggedCircuitBreakerMetrics.ofCircuitBreakerRegistry(registry)
.bindTo(meterRegistry);
运行几次断路器润饰操作后,咱们显示捕捉的指标。这是一些示例输入:
The number of slow failed calls which were slower than a certain threshold - resilience4j.circuitbreaker.slow.calls: 0.0
The states of the circuit breaker - resilience4j.circuitbreaker.state: 0.0, state: metrics_only
Total number of not permitted calls - resilience4j.circuitbreakernot.permitted.calls: 0.0
The slow call of the circuit breaker - resilience4j.circuitbreaker.slow.call.rate: -1.0
The states of the circuit breaker - resilience4j.circuitbreaker.state: 0.0, state: half_open
Total number of successful calls - resilience4j.circuitbreaker.calls: 0.0, kind: successful
The failure rate of the circuit breaker - resilience4j.circuitbreaker.failure.rate: -1.0
在理论利用中,咱们会定期将数据导出到监控零碎并在仪表板上进行剖析。
论断
在本文中,咱们学习了如何应用 Resilience4j 的 Circuitbreaker
模块在近程服务返回谬误时暂停向其发出请求。咱们理解了为什么这很重要,还看到了一些无关如何配置它的理论示例。
您能够应用 GitHub 上的代码来演示一个残缺的应用程序。
本文译自:Implementing a Circuit Breaker with Resilience4j – Reflectoring