熔断器 Circuit Breaker 模式
FreeGuideOnline
最新
2026-07-12
[关闭] --(失败次数 >= 阈值)--> [打开] [打开] --(等待时间结束)--> [半开] [半开] --(探测请求成功)--> [关闭] [半开] --(探测请求失败)--> [打开]
- **失败阈值**:可以是绝对失败次数,也可以是失败率(如最近10秒内失败率超过50%)。
- **冷却时间(Sleep Window)**:熔断器打开后,必须等待一段时间才能进入半开状态,防止频繁重试加重故障服务负担。
- **探测请求数量**:半开状态下只允许有限个请求(如1~3个)通过,避免大流量冲击尚未稳定的服务。
---
## 熔断器的关键配置参数
一个健壮的熔断器实现通常会提供以下可配置项:
- **错误率阈值**:触发熔断的失败百分比,例如50%意味着失败请求超过一半时断开。
- **滑动窗口时间**:用于统计错误率的时间长度(如最近10秒、30秒)。
- **最小请求数量**:滑动窗口内至少需要达到多少请求才开始统计错误率,避免低流量时偶发性错误导致误熔断。
- **熔断持续时间**:打开状态维持多久后进入半开状态(如30秒)。
- **半开状态允许请求数**:从半开恢复到关闭所需探测的成功次数,通常会使用1个请求,但可配置。
- **忽略的异常类型**:某些业务异常不应该计入失败(如参数校验失败),只将超时、连接拒绝、服务不可用等视为失败。
这些参数可以按照依赖服务的 SLA 和业务容忍度灵活调整。
---
## 熔断器的三种使用方式
### 1. 快速失败(Fail-Fast)
当熔断器打开时,立即返回一个错误,例如 HTTP 503 Service Unavailable,或一个预定义的降级数据(如空列表、缓存数据)。这是最基础的模式。
### 2. 降级返回(Fallback)
在熔断时,不直接抛出异常,而是执行一个“备用逻辑”。例如:
- 读取本地缓存
- 返回默认值
- 调用另一个备用服务
- 发起静默告警
这种模式对用户体验更友好。
### 3. 重试与熔断结合
重试是处理瞬时故障的有效手段,但**无节制的重试可能加剧故障**。常见做法是将熔断器包裹在重试策略之外:熔断器打开后,重试逻辑不会执行,减少无效请求。
---
## 实际应用中的最佳实践
### 1. 为每个远程依赖创建独立的熔断器
不同服务、不同接口的故障模式不同,应该为**每一个独立的依赖关系**配置一个熔断器实例。例如:订单服务调用库存服务和支付服务,应分别为两个服务创建熔断器。
### 2. 合理设置熔断阈值,避免“雪崩”误判
如果阈值过低,短暂抖动就会导致熔断,影响正常业务;阈值过高则失去保护作用。建议根据流量历史设置,例如:
- 失败率阈值:50%(可动态调整)
- 窗口大小:10秒~60秒
- 最小请求数:至少10个请求
并在上线后根据监控数据调优。
### 3. 区分不同类型的错误
并非所有异常都代表“依赖不可用”。可以将异常分类:
- **可熔断错误**:连接超时、读取超时、HTTP 5xx、服务拒绝连接等。
- **不可熔断错误**:参数非法、权限不足等业务异常。
只对可熔断错误进行计数,避免误触发。
### 4. 熔断器与超时控制结合
即使熔断器在关闭状态,**对每次请求也必须设置超时**。否则某个慢请求可能占用线程远超预期时间。建议:超时时间小于熔断滑动窗口的时间,确保快速失败。
### 5. 监控与告警
熔断器状态变化应记录日志并触发监控指标。例如:
- 熔断打开次数
- 熔断持续时间
- 降级调用次数
- 半开探测成功率
并与 Prometheus、Grafana、ELK 等系统集成,便于及时发现故障。
### 6. 避免在熔断器上过度重试
熔断器本身已经提供保护,应用层不应再在熔断器打开后反复重试。如果使用了 Spring Retry、Resilience4j 等库,需注意重试策略与熔断器的组合顺序。
---
## 主流实现方案
### 1. Resilience4j(Java 推荐)
轻量级、函数式编程友好,专为 Java 8+ 设计,不依赖任何外部库。提供熔断、重试、限流、舱壁等模块。
```java
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.slidingWindowSize(10)
.minimumNumberOfCalls(5)
.waitDurationInOpenState(Duration.ofSeconds(10))
.build();
CircuitBreaker circuitBreaker = CircuitBreaker.of("backendService", config);
Supplier<String> decorated = CircuitBreaker.decorateSupplier(circuitBreaker, () -> callBackend());
String result = Try.ofSupplier(decorated)
.recover(throwable -> "fallback")
.get();
2. Hystrix(已停止维护,可参考)
Netflix Hystrix 是早期标杆,但已进入维护模式,新项目建议使用 Resilience4j 或 Sentinel。
3. Sentinel(阿里巴巴)
面向分布式架构的轻量级流量控制框架,支持熔断降级、系统保护、热点参数限流等功能。
4. Polly(.NET 生态)
.NET 平台流行的弹性策略库,可以灵活组合重试、熔断、超时策略。
var circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(30)
);
5. 服务网格 Sidecar 模式(Istio/Envoy)
在云原生环境中,熔断可以下沉至 Sidecar 代理层,无需修改应用代码。Envoy 支持连接池和请求级别的熔断配置。
熔断器 vs 其他弹性模式
- 重试模式:解决瞬时故障,但可能导致雪崩;熔断器处理持续故障。
- 舱壁模式(Bulkhead):隔离资源以防止一个模块拖垮整体;熔断器阻止对故障依赖的调用。
- 限流模式(Rate Limiter):控制流量速率;熔断器根据失败率拒绝请求。
- 超时模式:单个请求的最大等待时间;熔断器是累积失败后的保护。
实际工程中,这些模式通常组合使用,搭建系统弹性长城。
熔断器在分布式系统中的位置
以微服务调用为例,熔断器通常放在客户端调用侧:
服务 A ---[熔断器]---> 服务 B(可能出现故障)