Java 中的断路器模式:增强系统弹性
大约 4 分钟
也称为
- 容错开关
断路器设计模式的意图
断路器模式是一种重要的 Java 设计模式,它有助于在微服务和分布式系统中确保容错和弹性。使用断路器,可以阻止系统反复尝试执行可能失败的操作,从而使其能够从故障中恢复并防止级联故障。
断路器模式的详细解释,并附带真实案例
真实案例
考虑一个依赖多个外部支付网关来处理交易的电子商务网站的真实案例。如果其中一个支付网关变得无响应或速度缓慢,断路器模式可用于检测故障并阻止系统反复尝试使用有问题的网关。相反,它可以快速切换到备用支付网关或向用户显示错误消息,确保网站的其余部分保持功能正常且响应迅速。这避免了资源耗尽,并通过允许交易通过其他可用服务处理来提供更好的用户体验。通过这种方式,断路器模式处理外部 API 故障,确保系统保持功能正常。
通俗易懂
断路器允许优雅地处理失败的远程服务。当我们的应用程序的所有部分彼此高度解耦时,它尤其有用,并且一个组件的故障并不意味着其他部分将停止工作。
维基百科说
断路器是一种用于现代软件开发的设计模式。它用于检测故障,并封装了防止故障不断发生的逻辑,在维护、临时外部系统故障或意外系统故障期间。
Java 中断路器模式的编程示例
此 Java 示例演示了断路器模式如何管理远程服务故障并保持系统稳定性。
想象一个使用本地文件/图像和远程服务来获取数据的 Web 应用程序。远程服务可能会变得缓慢或无响应,这可能会导致应用程序因线程饥饿而挂起。断路器模式可以帮助检测此类故障,并使应用程序能够优雅地降级。
- 模拟延迟的远程服务
// The DelayedRemoteService simulates a remote service that responds after a certain delay.
var delayedService = new DelayedRemoteService(serverStartTime, 5);
- 设置断路器
// The DefaultCircuitBreaker wraps the remote service and monitors for failures.
var delayedServiceCircuitBreaker = new DefaultCircuitBreaker(delayedService, 3000, 2, 2000 * 1000 * 1000);
- 监控服务以处理请求
// The MonitoringService is responsible for calling the remote services.
var monitoringService = new MonitoringService(delayedServiceCircuitBreaker, quickServiceCircuitBreaker);
// Fetch response from local resource
LOGGER.info(monitoringService.localResourceResponse());
// Fetch response from delayed service 2 times to meet the failure threshold
LOGGER.info(monitoringService.delayedServiceResponse());
LOGGER.info(monitoringService.delayedServiceResponse());
- 处理断路器状态
// Fetch current state of delayed service circuit breaker after crossing failure threshold limit
LOGGER.info(delayedServiceCircuitBreaker.getState()); // Should be OPEN
// Meanwhile, the delayed service is down, fetch response from the healthy quick service
LOGGER.info(monitoringService.quickServiceResponse());
LOGGER.info(quickServiceCircuitBreaker.getState());
- 从故障中恢复
// Wait for the delayed service to become responsive
try {
LOGGER.info("Waiting for delayed service to become responsive");
Thread.sleep(5000);
} catch (InterruptedException e) {
LOGGER.error("An error occurred: ", e);
}
// Check the state of delayed circuit breaker, should be HALF_OPEN
LOGGER.info(delayedServiceCircuitBreaker.getState());
// Fetch response from delayed service, which should be healthy by now
LOGGER.info(monitoringService.delayedServiceResponse());
// As successful response is fetched, it should be CLOSED again.
LOGGER.info(delayedServiceCircuitBreaker.getState());
- 完整示例
public static void main(String[] args) {
var serverStartTime = System.nanoTime();
var delayedService = new DelayedRemoteService(serverStartTime, 5);
var delayedServiceCircuitBreaker = new DefaultCircuitBreaker(delayedService, 3000, 2,
2000 * 1000 * 1000);
var quickService = new QuickRemoteService();
var quickServiceCircuitBreaker = new DefaultCircuitBreaker(quickService, 3000, 2,
2000 * 1000 * 1000);
//Create an object of monitoring service which makes both local and remote calls
var monitoringService = new MonitoringService(delayedServiceCircuitBreaker,
quickServiceCircuitBreaker);
//Fetch response from local resource
LOGGER.info(monitoringService.localResourceResponse());
//Fetch response from delayed service 2 times, to meet the failure threshold
LOGGER.info(monitoringService.delayedServiceResponse());
LOGGER.info(monitoringService.delayedServiceResponse());
//Fetch current state of delayed service circuit breaker after crossing failure threshold limit
//which is OPEN now
LOGGER.info(delayedServiceCircuitBreaker.getState());
//Meanwhile, the delayed service is down, fetch response from the healthy quick service
LOGGER.info(monitoringService.quickServiceResponse());
LOGGER.info(quickServiceCircuitBreaker.getState());
//Wait for the delayed service to become responsive
try {
LOGGER.info("Waiting for delayed service to become responsive");
Thread.sleep(5000);
} catch (InterruptedException e) {
LOGGER.error("An error occurred: ", e);
}
//Check the state of delayed circuit breaker, should be HALF_OPEN
LOGGER.info(delayedServiceCircuitBreaker.getState());
//Fetch response from delayed service, which should be healthy by now
LOGGER.info(monitoringService.delayedServiceResponse());
//As successful response is fetched, it should be CLOSED again.
LOGGER.info(delayedServiceCircuitBreaker.getState());
}
示例摘要
- 使用参数初始化断路器:
timeout
、failureThreshold
和retryTimePeriod
。 - 从
closed
状态开始。 - 在成功调用时,重置状态。
- 如果故障次数超过阈值,则转换为
open
状态以阻止进一步调用。 - 在重试超时后,转换为
half-open
状态以测试服务。 - 如果
half-open
状态成功,则转换回closed
状态。如果失败,则返回到open
状态。
程序输出
16:59:19.767 [main] INFO com.iluwatar.circuitbreaker.App -- Local Service is working
16:59:19.769 [main] INFO com.iluwatar.circuitbreaker.App -- Delayed service is down
16:59:19.769 [main] INFO com.iluwatar.circuitbreaker.App -- Delayed service is down
16:59:19.769 [main] INFO com.iluwatar.circuitbreaker.App -- OPEN
16:59:19.769 [main] INFO com.iluwatar.circuitbreaker.App -- Quick Service is working
16:59:19.769 [main] INFO com.iluwatar.circuitbreaker.App -- CLOSED
16:59:19.769 [main] INFO com.iluwatar.circuitbreaker.App -- Waiting for delayed service to become responsive
16:59:24.779 [main] INFO com.iluwatar.circuitbreaker.App -- HALF_OPEN
16:59:24.780 [main] INFO com.iluwatar.circuitbreaker.App -- Delayed service is working
16:59:24.780 [main] INFO com.iluwatar.circuitbreaker.App -- CLOSED
此示例演示了断路器模式如何通过管理远程服务故障来帮助维护应用程序的稳定性和弹性。
何时在 Java 中使用断路器模式
断路器模式适用
- 在分布式系统中,单个服务的故障会导致系统范围内的级联故障
- 对于与可能变得无响应或速度缓慢的第三方服务或数据库交互的应用程序
- 在微服务架构中,一个服务的故障会影响其他服务的可用性
Java 中断路器模式的实际应用
- 云服务,以优雅地处理外部服务的故障
- 电子商务平台,以管理大量交易和对外部 API 的依赖
- 微服务架构,以维护系统稳定性和响应能力
- Spring 断路器模块
- Netflix Hystrix API
断路器模式的优点和权衡
优点
- 阻止系统执行可能失败的无用操作,从而节省资源
- 有助于在部分系统故障期间维护系统的稳定性和应用程序的性能
- 通过避免因重复请求而压垮失败的服务,从而促进系统更快恢复
权衡
- 由于该模式需要额外的逻辑来检测故障和管理断路器的状态,因此系统的复杂性会增加
- 如果配置不当,可能会导致系统降级,因为如果电路处于打开状态,合法的请求可能会被阻止
- 需要仔细调整阈值和超时时间,以在响应能力和保护之间取得平衡
相关模式
- 舱壁模式:可用于隔离系统的不同部分,以防止故障在整个系统中蔓延
- 重试模式:可与断路器模式结合使用,在打开电路之前重试失败的操作