设计模式之【 断路器模式】

张开发
2026/4/14 14:24:42 15 分钟阅读

分享文章

设计模式之【 断路器模式】
断路器模式实现在微服务架构中服务间的依赖调用无处不在一旦某个依赖服务出现故障如响应超时、服务宕机若持续向其发送请求会导致自身服务资源被耗尽如线程池满、连接泄漏进而引发级联故障最终导致整个系统崩溃。断路器模式Circuit Breaker Pattern正是为解决这一问题而生的容错设计模式它如同现实中的电路断路器当检测到“故障电流”依赖服务频繁失败时会自动“跳闸”切断故障依赖的调用链路避免故障扩散同时定期尝试“合闸”恢复正常的服务调用。简单来说断路器模式的核心价值的是防雪崩、保资源、促恢复是微服务容错体系中不可或缺的核心组件——很多人常说的“微服务熔断”本质上就是断路器模式的落地实现。一、实现思路拆解断路器的实现核心围绕「状态管理」展开配合参数配置、计数控制和超时机制确保在多线程环境下安全、高效地完成故障隔离与服务恢复。具体可拆解为「状态定义」「核心参数」「逻辑流程」三个核心模块。1. 核心状态定义三种状态循环切换断路器的整个工作周期就是在三种核心状态之间切换每种状态对应明确的行为逻辑避免无效调用和资源浪费。我们可以用枚举清晰定义这三种状态对应实际开发中的“断开、半断、闭合”关闭状态CLOSED闭合断路器的正常工作状态此时依赖服务被认为是可用的。所有请求会正常转发到依赖服务同时内部会实时记录请求的失败次数成功则重置失败计数为状态切换提供依据。打开状态OPEN断开故障状态当依赖服务的失败次数达到预设阈值时断路器会“跳闸”进入打开状态。此时所有请求会被直接拒绝不转发到依赖服务直接返回失败响应可自定义降级逻辑如返回缓存数据、默认值避免持续请求耗尽自身服务资源。半开状态HALF_OPEN半断过渡状态是连接“打开”与“关闭”的桥梁。打开状态持续一段时间超时时间后断路器会自动切换到半开状态目的是安全地尝试恢复依赖服务——此时会允许少量请求预设尝试次数转发到依赖服务检测服务是否已恢复。2. 核心配置参数控制状态切换的关键断路器的行为的由一组核心参数控制参数配置的合理性直接影响容错效果实际开发中需结合业务场景如依赖服务的稳定性、接口响应时间灵活调整核心参数如下失败阈值关闭状态下允许的最大失败次数。当失败次数达到该阈值时断路器立即切换为打开状态例10次请求中失败8次阈值设为8则触发跳闸。超时时间打开状态持续时间打开状态的维持时间超时后自动切换为半开状态。目的是给依赖服务一定的恢复时间避免频繁试探例超时时间设为5秒即打开状态维持5秒后进入半开状态。半开状态尝试次数半开状态下允许转发到依赖服务的最大请求数。用于检测依赖服务是否恢复若这些尝试请求中成功次数达到预设标准通常为全部成功则切换为关闭状态若有失败则立即切换回打开状态例尝试次数设为33次请求全部成功则恢复1次失败则重新跳闸。3. 核心逻辑流程状态切换完整链路断路器的工作流程本质是“状态检测→计数统计→超时判断→状态切换”的循环结合三种状态的行为完整逻辑如下可直接对应实际开发中的代码逻辑关闭状态CLOSED流程接收请求正常转发到依赖服务若请求成功重置失败计数器失败次数清零维持关闭状态若请求失败失败计数器累加1判断失败次数是否达到「失败阈值」若是立即切换为打开状态若否继续维持关闭状态。打开状态OPEN流程接收请求直接拒绝不转发到依赖服务返回失败响应可执行降级逻辑启动超时计时器记录打开状态的持续时间当持续时间达到「超时时间」自动切换为半开状态。半开状态HALF_OPEN流程接收请求按照「半开状态尝试次数」允许少量请求转发到依赖服务若尝试请求全部成功重置失败计数器切换为关闭状态恢复正常请求转发若尝试请求中有任意一次失败失败计数器重置为阈值或累加后达到阈值立即切换回打开状态重新进入超时等待若尝试次数用完仍未达到“全部成功”标准同样切换回打开状态。二、实现核心要点线程安全是前提断路器会被多线程同时调用如微服务中多个请求并发调用依赖服务因此失败计数器、状态标识必须保证原子性可使用原子类如Java中的AtomicInteger、AtomicReference避免出现“计数错乱”“状态切换异常”例多线程同时修改失败次数导致阈值判断错误。状态管理要严谨三种状态的切换必须遵循固定逻辑不允许出现“跳跃式切换”如直接从打开状态切换到关闭状态同时要避免状态切换的死循环如半开状态反复失败、反复切换到打开状态需合理设置超时时间和尝试次数。超时控制要精准打开状态的超时时间需结合依赖服务的恢复能力设置——过短会导致频繁试探增加系统负担过长会导致依赖服务恢复后无法及时恢复调用影响业务可用性。降级逻辑不可少打开状态下直接拒绝请求会影响业务体验因此需搭配降级逻辑如返回缓存数据、默认响应、友好提示确保即使依赖服务故障自身服务也能正常提供基础功能提升系统可用性。三、补充说明微服务中的“熔断”本质就是断路器模式的落地实现。比如Spring Cloud中的Resilience4j、Sentinel其熔断功能的核心逻辑完全遵循本文所述的断路器模式——通过状态管理、失败计数、超时控制实现故障隔离和服务恢复。区别仅在于框架实现的断路器还增加了更多实用特性如滑动窗口计数、熔断后的监控告警、自定义降级策略但核心原理与我们手动实现的断路器完全一致。因此理解断路器模式的实现逻辑是掌握微服务熔断机制的基础。断路器模式的实现核心是「状态管理 原子计数 超时控制」三者协同工作实现“故障隔离→试探恢复→正常运行”的闭环。其核心价值在于防止故障扩散、保护系统资源同时兼顾服务恢复的及时性是微服务架构中容错设计的核心手段。四、Demo及日常生产使用手搓demo断路器核心类import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * 断路器核心实现 * 状态关闭(CLOSED) - 开启(OPEN) - 半开(HALF_OPEN) */ public class CircuitBreaker { // 断路器状态枚举 public enum State { CLOSED, OPEN, HALF_OPEN } // 配置参数 private final int failureThreshold; // 失败阈值连续失败N次触发熔断 private final long openTimeout; // 开启状态超时时间ms超时后进入半开 private final int successThreshold; // 半开状态成功次数阈值 // 状态变量线程安全 private volatile State currentState; private final AtomicInteger failureCount; // 失败计数器 private final AtomicInteger successCount; // 成功计数器 private final AtomicLong openStateStartTime;// 开启状态开始时间 /** * 构造方法 * param failureThreshold 失败阈值 * param openTimeout 熔断超时时间 * param successThreshold 半开成功阈值 */ public CircuitBreaker(int failureThreshold, long openTimeout, int successThreshold) { this.failureThreshold failureThreshold; this.openTimeout openTimeout; this.successThreshold successThreshold; this.currentState State.CLOSED; this.failureCount new AtomicInteger(0); this.successCount new AtomicInteger(0); this.openStateStartTime new AtomicLong(0); } /** * 执行目标方法核心入口 */ public T T execute(ServiceCallableT service) throws Exception { // 1. 检查并切换状态 checkAndSwitchState(); // 2. 断路器开启状态直接快速失败 if (currentState State.OPEN) { System.out.println(【断路器】状态OPEN → 拒绝请求快速失败); throw new RuntimeException(服务熔断请求被拒绝); } // 3. 关闭/半开状态执行服务调用 try { T result service.call(); // 调用成功 onSuccess(); return result; } catch (Exception e) { // 调用失败 onFailure(); throw e; } } /** * 检查状态并自动切换 */ private void checkAndSwitchState() { if (currentState State.OPEN) { // 开启状态超时切换为半开 long now System.currentTimeMillis(); if (now - openStateStartTime.get() openTimeout) { System.out.println(【断路器】超时恢复 → 状态切换OPEN → HALF_OPEN); currentState State.HALF_OPEN; successCount.set(0); } } } /** * 调用成功处理 */ private void onSuccess() { switch (currentState) { case CLOSED: // 关闭状态重置失败计数 failureCount.set(0); break; case HALF_OPEN: // 半开状态累计成功次数 if (successCount.incrementAndGet() successThreshold) { System.out.println(【断路器】服务恢复 → 状态切换HALF_OPEN → CLOSED); currentState State.CLOSED; failureCount.set(0); successCount.set(0); } break; default: break; } } /** * 调用失败处理 */ private void onFailure() { switch (currentState) { case CLOSED: // 关闭状态累计失败达到阈值则熔断 if (failureCount.incrementAndGet() failureThreshold) { System.out.println(【断路器】失败达阈值 → 状态切换CLOSED → OPEN); currentState State.OPEN; openStateStartTime.set(System.currentTimeMillis()); } break; case HALF_OPEN: // 半开状态只要失败立即重新熔断 System.out.println(【断路器】半开调用失败 → 状态切换HALF_OPEN → OPEN); currentState State.OPEN; openStateStartTime.set(System.currentTimeMillis()); successCount.set(0); break; default: break; } } // 函数式接口定义服务调用逻辑 FunctionalInterface public interface ServiceCallableT { T call() throws Exception; } // 获取当前状态测试用 public State getCurrentState() { return currentState; } }测试主类/** * 断路器模式测试 Demo */ public class CircuitBreakerDemo { // 模拟远程服务调用随机失败模拟服务异常 private static String callRemoteService(boolean shouldFail) throws Exception { if (shouldFail) { System.out.println(【服务调用】失败); throw new Exception(远程服务超时/异常); } System.out.println(【服务调用】成功); return 服务返回结果; } public static void main(String[] args) throws InterruptedException { // 初始化断路器失败3次熔断熔断5秒后进入半开半开连续2次成功则恢复 CircuitBreaker breaker new CircuitBreaker(3, 5000, 2); System.out.println( 第一阶段连续调用失败触发熔断 ); // 模拟连续失败 for (int i 0; i 5; i) { try { breaker.execute(() - callRemoteService(true)); } catch (Exception e) { System.out.println(请求异常 e.getMessage() \n); } } System.out.println( 第二阶段断路器开启直接拒绝请求 ); // 断路器开启所有请求直接被拒 for (int i 0; i 2; i) { try { breaker.execute(() - callRemoteService(false)); } catch (Exception e) { System.out.println(请求异常 e.getMessage() \n); } } System.out.println( 第三阶段等待5秒进入半开状态 ); // 等待超时进入半开 Thread.sleep(5000); System.out.println( 第四阶段半开状态尝试成功调用 ); // 半开状态连续成功恢复关闭状态 for (int i 0; i 3; i) { try { breaker.execute(() - callRemoteService(false)); } catch (Exception e) { System.out.println(请求异常 e.getMessage()); } System.out.println(); } System.out.println( 第五阶段断路器恢复关闭正常调用 ); try { breaker.execute(() - callRemoteService(false)); } catch (Exception e) { e.printStackTrace(); } } }运行效果说明 执行代码后你会看到完整的状态流转 连续失败 3 次 → 断路器从 CLOSED → OPEN 熔断期间 → 所有请求直接快速失败 等待 5 秒超时 → 断路器从 OPEN → HALF_OPEN 连续成功 2 次 → 断路器从 HALF_OPEN → CLOSED 恢复正常 → 服务正常调用生产级推荐使用成熟框架Resilience4jSpringCloud 官方推荐Sentinel阿里开源更轻量HystrixNetflix 老牌已停更业务 Service核心使用 SentinelResource 定义熔断资源 降级方法。importcom.alibaba.csp.sentinel.annotation.SentinelResource;importcom.alibaba.csp.sentinel.slots.block.BlockException;importorg.springframework.stereotype.Service;ServicepublicclassTestService{/** * 定义 Sentinel 资源 * value 资源名称自定义 * blockHandler 限流/熔断时走的降级方法 */SentinelResource(valueremoteService,blockHandlerfallbackHandler)publicStringcallRemoteService(booleanfail){// 模拟远程调用异常if(fail){thrownewRuntimeException(远程服务调用失败);}return远程服务调用成功 ✅;}/** * 降级/兜底方法参数最后必须加 BlockException */publicStringfallbackHandler(booleanfail,BlockExceptionex){return服务熔断/限流 → 已降级 ✅;}}控制层测试接口importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassTestController{AutowiredprivateTestServicetestService;// 测试failtrue 触发失败GetMapping(/test)publicStringtest(RequestParam(defaultValuefalse)booleanfail){returntestService.callRemoteService(fail);}}配置熔断规则importcom.alibaba.csp.sentinel.slots.block.RuleConstant;importcom.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;importcom.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;importorg.springframework.stereotype.Component;importjavax.annotation.PostConstruct;importjava.util.Collections;ComponentpublicclassSentinelConfig{PostConstructpublicvoidinitDegradeRule(){DegradeRulerulenewDegradeRule();rule.setResource(remoteService);// 对应 SentinelResource 的名称// 熔断策略异常比例rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);// 异常比例 50% 触发熔断rule.setCount(0.5);// 熔断 5 秒后进入半开探测rule.setTimeWindow(5);// 加载规则DegradeRuleManager.loadRules(Collections.singletonList(rule));System.out.println(Sentinel 熔断规则加载完成 ✅);}}Sentinel 控制台可视化监控地址启动java -jar sentinel-dashboard-1.8.6.jar

更多文章