5分钟学点架构模式 - 断路器模式
可靠性至关重要,特别是当服务互连时,一个组件中的故障可能会导致对其他服务产生级联效应。 断路器模式(Circuit Breaker Pattern,也可以翻译为熔断模式?),是一种重要的设计模式,用于构建容错的、弹性的系统。尤其是在微服务架构中。本文介绍了断路器模式的基本原理、其优点以及如何实现它以保护系统免受故障影响。
什么是断路器模式
断路器模式实际上是受到您在家中看到的断路器的启发,它旨在通过检测故障并在出现问题时停止电流来防止系统故障。在软件中,此模式监视服务交互,防止对失败的服务进行连续调用/重试,这可能会使服务过载。通过“断开”服务之间的电路,此模式允许系统正常处理故障并避免级联问题。
它是如何工作的?
图1:断路器模式的状态图
断路器有三种不同的状态:Closed、 Open 和 Half-Open。
- 关闭状态 :通常,断路器处于“关闭”状态,这意味着(循环已关闭)请求在服务之间照常流动。(在电气术语中,电线连接以允许电流流动)
- 打开状态 : 当断路器打开时,它会立即拒绝对失败服务的请求,从而防止对服务造成进一步压力并为其提供恢复时间。在此期间,可以触发回退机制,例如返回缓存数据或默认响应。
- 半开状态 : 在定义的超时后,断路器切换到半开状态,并允许来自终端节点的不同数量的请求,以确定服务是否已恢复。如果请求成功,则断路器将再次关闭,但在其他情况下,它会返回到 open 状态。
此设计模式背后的主要思想是防止失败的服务拉取整个系统,并提供一种在服务恢复正常后恢复的方法。
图2:类比的电气结构
插播近期思考,分享给对监控、可观测性感兴趣的朋友:十年磨一剑,运维监控、可观测性领域创业,拼的是产品细节和交付迭代能力
为啥使用断路器模式
在复杂的分布式系统中,故障是不可避免的。以下是断路器模式必不可少的一些真正原因:
- 防止级联故障 :在微服务架构中,如果一项服务出现故障,而其他服务依赖于它,则故障可能会蔓延到整个系统。断路器通过隔离故障服务来阻止这种情况。
- 提高系统稳定性 :通过停止对失败服务的请求,防止资源消耗并降低依赖服务的负载,有助于稳定系统。
- 更好的用户体验 :断路器不会让请求停滞太久或返回未处理的错误,而是通过提供回退响应来实现优雅的降级,从而改善即使在故障期间的用户体验。
- 自动恢复 :半开状态允许系统自动测试服务的运行状况并在没有人工干预的情况下进行恢复。
如何实现断路器模式
断路器模式的实现取决于您使用的特定堆栈,但标准方法保持不变。以下是如何实施它的高级概述:
- Set Failure Thresholds(设置故障阈值 ):定义断路器应打开的条件。这可以基于连续失败、错误率或超时。
- Monitor Requests(监控请求):持续跟踪对服务的请求是成功还是失败。如果达到故障阈值,则使断路器跳闸。
- Handle Open State(处理打开状态):当断路器打开时,拒绝对服务的进一步请求并触发回退机制。
- Implement Half-Open State(实现半开状态):在一段时间超时后,让有限的请求访问服务以测试它是否已恢复。如果成功,请合闸断路器。
- Provide Fallback Mechanisms(提供回退机制):在发生故障时,回退机制可以提供默认响应、使用缓存数据或切换到备用服务。
以下示例演示了如何使用广泛采用的 Resilience4j
库在 Java 中实现断路器:
Resilience4j
是一个功能强大的 Java 库,旨在帮助您实施弹性模式,例如 Circuit Breaker、Rate Limiter、Retry、Bulkhead 和 Time Limiter 模式。Resilience4j 的主要优势之一是其灵活性和易于配置。正确配置这些弹性模式使开发人员能够微调系统,以实现最大的容错能力、提高稳定性和更好的错误性能。
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import java.time.Duration;
public class CircuitBreakerExample {
public static void main(String[] args) {
// Create a custom configuration for the Circuit Breaker
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(5))
.ringBufferSizeInHalfOpenState(5)
.ringBufferSizeInClosedState(20)
.build();
// Create a CircuitBreakerRegistry with a custom global configuration
CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config);
// Get or create a CircuitBreaker from the CircuitBreakerRegistry
CircuitBreaker circuitBreaker = registry.circuitBreaker("myService");
// Decorate the service call with the circuit breaker
Supplier<String> decoratedSupplier = CircuitBreaker
.decorateSupplier(circuitBreaker, myService::call);
// Execute the decorated supplier and handle the result
Try<String> result = Try.ofSupplier(decoratedSupplier)
.recover(throwable -> "Fallback response");
System.out.println(result.get());
}
}
在此示例中,断路器配置为在 50% 的请求失败时打开。在进入半开状态之前,它会保持打开状态 5 秒,在此期间,它允许 5 个请求来测试服务。如果请求成功,它将关闭断路器,从而恢复正常作。
断路器的重要配置选项
Resilience4j 提供了灵活而健壮的断路器模式实现,允许开发人员配置各个方面,以根据其应用程序的需求定制行为。正确的配置对于平衡容错能力、系统稳定性和恢复机制至关重要。以下是 Resilience4j 断路器的关键配置选项:
1、Failure Rate Threshold(故障率阈值):这是导致断路器从 Closed 状态(正常作)转换为 Open 状态(请求被阻止)的失败请求的百分比。其目的是控制断路器何时应停止将请求转发到失败的服务。例如,阈值 50% 表示断路器将在一半请求失败后打开。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // Open the circuit when 50% of requests fail
.build();
2、Wait Duration in Open 状态:断路器在转换为 Half-Open 状态之前保持 Open 状态的时间,此时它开始允许有限数量的请求来测试服务是否已恢复。这可以防止立即重试失败的服务,从而允许下游服务在再次测试之前有时间恢复。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.waitDurationInOpenState(Duration.ofSeconds(30)) // Wait for 30 seconds before transitioning to Half-Open
.build();
3、Ring Buffer Size in Closed 状态: 熔断器在 Closed 状态下(评估故障率之前)记录的请求数。这充当了错误监控的滑动窗口。帮助熔断器根据最近的请求确定故障率。较大的 Ring buffer 大小意味着在决定是否打开 circuit 时考虑更多的数据点。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.ringBufferSizeInClosedState(50) // Consider the last 50 requests to calculate the failure rate
.build();
4、Half Open 状态下的 Ring Buffer Size:在根据成功率或失败率决定是关闭电路还是恢复到 Open 状态之前,允许的处于 Half-Open 状态的请求数。确定将在 half-open 状态下测试多少个请求,以确定服务是稳定 以关闭电路还是仍然失败。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.ringBufferSizeInHalfOpenState(5) // Test with 5 requests in Half-Open state
.build();
5、Sliding Window Type and Size 滑动窗口类型和大小:定义如何测量故障率:通过基于计数的滑动窗口或基于时间的滑动窗口。提供处理灵活性 计算故障率。基于计数的窗口在高流量系统中很有用,而基于时间的窗口在低流量环境中效果很好。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(100) // Use a count-based window with the last 100 requests
.build();
6、Minimum Number of Calls 指定在评估失败率之前所需的最小请求数:防止断路器在没有足够的数据来计算有意义的故障率时过早断开,尤其是在低流量期间。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.minimumNumberOfCalls(20) // Require at least 20 calls before evaluating failure rate
.build();
7、Allownumber of Calls in Half-Open 状态:Half-Open 状态下允许通过的检查服务是否已恢复的请求数。在转换为 half-open 状态后,此配置控制允许多少个请求来评估服务恢复。较小的值可以更快地捕获问题,而较大的值可以保证临时问题不会导致重新打开电路。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.permittedNumberOfCallsInHalfOpenState(5) // Test recovery with 5 requests
.build();
8、Slow Call Duration Threshold 慢调用持续时间阈值:定义慢调用的阈值。超过此阈值的调用被视为“慢”,并且可能导致失败率。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.slowCallDurationThreshold(Duration.ofSeconds(2)) // Any call over 2 seconds is considered slow
.build();
9、Slow Call Rate Threshold 触发熔断器打开的“慢”调用的百分比,类似于失败率阈值。在性能下降的服务彻底失败之前检测它们,使系统能够及早响应性能问题。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.slowCallRateThreshold(50) // Open the circuit when 50% of calls are slow
.build();
10、Automatic Transition from Open to Half-Open 从开路到半开的自动转换: 控制断路器如何在设定的等待持续时间后自动从开路状态转换为半开状态。通过定期测试服务,使系统能够自动恢复,无需人工干预。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.automaticTransitionFromOpenToHalfOpenEnabled(true) // Enable automatic transition
.build();
11、Fallback Mechanism 回退机制:帮助配置在熔断器打开且请求被阻止时的回退动作。防止级联故障,并通过提供缓存数据/默认响应来改善我们的产品体验。
Try<String> result = Try.ofSupplier(
CircuitBreaker.decorateSupplier(circuitBreaker, service::call)
).recover(throwable -> "Fallback response");
总结
Circuit Breaker Pattern 是构建弹性、容错系统的重要工具。通过防止级联故障、提高系统稳定性和实现正常恢复,它在现代软件架构中发挥着至关重要的作用,尤其是在微服务环境中。无论您是构建大型企业应用程序还是较小的分布式系统,断路器都可以在故障条件下保持可靠运行方面改变游戏规则。
本文由 快猫星云 团队翻译,原文链接:Understanding the Circuit Breaker: A Key Design Pattern for Resilient Systems