Skip to content

熔断器

本页是熔断、隔离和降级的基础导读。HystrixCommand内部执行、线程/信号量隔离、Rolling Metrics、取消边界以及迁移到Resilience4j的完整过程,请继续阅读:

Hystrix 用来解决微服务中的故障扩散问题。一个服务调用另一个服务时,如果下游响应变慢或持续失败,上游线程会被大量占用,最终可能把整个系统拖垮。这种现象通常叫服务雪崩。

Hystrix 提供超时、隔离、熔断、降级等能力,让系统在部分服务异常时仍能保持基本可用。

阅读入口:先理解故障如何被隔离

按“资源隔离 → 超时 → Rolling Metrics → 熔断状态 → fallback”阅读。先掌握 Hystrix 的历史模型,再对照 Resilience4j 的模块化实现和迁移边界。

核心原理:命令封装、资源隔离与熔断统计

Hystrix 把远程调用封装成 HystrixCommand,根据配置选择线程池隔离或信号量隔离;执行结果进入滚动统计窗口,错误率达到阈值后打开熔断器,后续请求直接走 fallback,等待休眠窗口后再半开探测。

mermaid
flowchart TD
    A["HystrixCommand.execute"] --> B["线程池/信号量隔离"]
    B --> C{"熔断器是否 OPEN?"}
    C -- "是" --> D["短路并执行fallback"]
    C -- "否" --> E["执行远程调用"]
    E --> F["超时/异常/成功写入Rolling Metrics"]
    F --> G{"达到失败阈值?"}
    G -- "是" --> H["OPEN,拒绝新调用"]
    G -- "否" --> I["返回正常结果"]
    H --> J["休眠窗口后HALF_OPEN探测"]

线程隔离能限制故障线程池,不能撤销已经提交的下游写操作;fallback 只能返回业务允许的兜底,不能把扣款或扣库存伪装成成功。

服务雪崩流程

mermaid
flowchart TD
    A[用户请求进入订单服务] --> B[订单服务调用库存服务]
    B --> C{库存服务变慢}
    C --> D[订单服务线程阻塞]
    D --> E[线程池被占满]
    E --> F[订单服务也不可用]
    F --> G[故障继续向上游扩散]

Hystrix 如何保护系统

mermaid
flowchart TD
    A[发起远程调用] --> B[进入隔离资源]
    B --> C{是否超时或失败过多?}
    C -->|否| D[正常返回]
    C -->|是| E[打开熔断器]
    E --> F[直接执行降级逻辑]
    F --> G[快速返回]

核心概念

超时

远程调用不能无限等待。Hystrix 会为调用设置超时时间,超过时间直接失败并进入降级逻辑。

隔离

隔离是为了限制故障影响范围。常见方式:

  • 线程池隔离:不同下游使用不同线程池,一个下游慢不会占满所有业务线程。
  • 信号量隔离:限制并发数,开销较小,但隔离能力弱于线程池。

熔断

当某个下游服务失败率达到阈值时,Hystrix 会打开熔断器。熔断打开后,请求不再真正调用下游,而是直接走降级逻辑。

经过一段时间后,熔断器进入半开状态,放少量请求试探。如果成功,关闭熔断;如果失败,继续打开。

mermaid
flowchart TD
    A["CLOSED正常放行"] --> B{"失败率和请求量达到阈值"}
    B -- "否" --> A
    B -- "是" --> C["OPEN快速失败"]
    C --> D["等待Sleep Window"]
    D --> E["允许单个或少量试探请求"]
    E --> F{"试探是否成功"}
    F -- "成功" --> A
    F -- "失败" --> C

降级

降级是在失败时返回可接受的结果。例如:

  • 商品评价服务不可用时,返回空评价。
  • 推荐服务不可用时,返回默认推荐。
  • 库存服务不可用时,提示稍后重试。

降级要符合业务语义,不能把失败伪装成成功。

开发建议

  1. 所有远程调用都要设置超时。
  2. 重要下游要配置隔离资源,避免互相影响。
  3. 降级逻辑要简单,不要在 fallback 中再调用一堆不稳定服务。
  4. 写操作降级要谨慎,不能默认成功。
  5. 监控熔断次数、失败率、超时数量和线程池使用率。

Hystrix 通常用于保护 Feign 远程调用,和 Ribbon 负载均衡一起构成服务调用的稳定性基础。

代码 Demo:HystrixCommand 降级

java
public class StockCommand extends HystrixCommand<String> {
    private final RestTemplate restTemplate;
    private final Long productId;

    public StockCommand(RestTemplate restTemplate, Long productId) {
        super(HystrixCommandGroupKey.Factory.asKey("stock"));
        this.restTemplate = restTemplate;
        this.productId = productId;
    }

    @Override
    protected String run() {
        return restTemplate.getForObject(
            "http://inventory-service/api/stocks/" + productId,
            String.class
        );
    }

    @Override
    protected String getFallback() {
        return "{\"available\":false,\"message\":\"库存服务暂不可用\"}";
    }
}

使用:

java
String result = new StockCommand(restTemplate, 1001L).execute();

实际新项目更多会使用 Sentinel 或 Resilience4j,但 Hystrix 的超时、隔离、熔断、降级思想仍然值得掌握。

Hystrix、Sentinel、Resilience4j 对比

Spring Cloud 容错治理经历过几个常见阶段:

text
Hystrix 经典熔断隔离
    -> Sentinel 流量治理
    -> Resilience4j 轻量模块化容错组件
对比项HystrixSentinelResilience4j
主要定位熔断、隔离、降级限流、熔断、热点参数、系统保护熔断、限流、重试、隔离、超时
常见生态Spring Cloud Netflix 老项目Spring Cloud Alibaba 常见Spring Cloud CircuitBreaker 常见
隔离方式线程池隔离、信号量隔离并发线程数控制、规则拦截Bulkhead、ThreadPoolBulkhead
限流能力较弱很强有 RateLimiter 模块
控制台Hystrix DashboardSentinel Dashboard通常结合 Actuator/Micrometer
当前建议老项目维护理解流量治理强需求优先考虑Spring 官方生态和轻量场景常用

三者的共同目标都是防止故障扩散,但关注点不同:

  • Hystrix 更强调隔离和熔断。
  • Sentinel 更强调实时流量控制和规则治理。
  • Resilience4j 更强调轻量、模块化、函数式组合。

Resilience4j 的核心模块

Resilience4j 不是一个单一熔断器,而是一组容错组件。

本节只用于从Hystrix过渡到现代组件。Java 17、Spring Boot 3、Spring Cloud CircuitBreaker、滑动窗口Subtract-on-Evict、状态并发转换、Spring AOP顺序、Cloud Factory真实执行链和商业Demo统一进入Resilience4j独立专栏,不要把下面的概念示例当成完整生产实现。

模块作用
CircuitBreaker熔断器,根据失败率或慢调用比例打开熔断
RateLimiter限流,控制单位时间允许多少请求
Retry重试,处理短暂失败
Bulkhead舱壁隔离,限制并发调用数
TimeLimiter超时控制,限制异步调用等待时间

它的思想是把不同能力拆成小模块,需要什么组合什么。

mermaid
flowchart TD
    A["业务调用"] --> B["RateLimiter 限流"]
    B --> C["Bulkhead 隔离"]
    C --> D["CircuitBreaker 熔断判断"]
    D --> E["Retry 有限重试"]
    E --> F["TimeLimiter 超时控制"]
    F --> G["调用下游服务"]

Resilience4j 熔断状态

Resilience4j 的熔断器也有类似状态:

mermaid
flowchart TD
    A["CLOSED 正常放行"] --> B{"失败率或慢调用比例超阈值"}
    B -->|"否"| A
    B -->|"是"| C["OPEN 快速拒绝"]
    C --> D["等待一段时间"]
    D --> E["HALF_OPEN 放行少量探测请求"]
    E --> F{"探测成功"}
    F -->|"是"| A
    F -->|"否"| C

核心指标通常包括:

  • 失败率。
  • 慢调用比例。
  • 最小调用数量。
  • 滑动窗口大小。
  • 熔断打开持续时间。
  • 半开状态允许探测请求数。

Resilience4j 配置 Demo

yaml
resilience4j:
  circuitbreaker:
    instances:
      userService:
        slidingWindowSize: 20
        minimumNumberOfCalls: 10
        failureRateThreshold: 50
        slowCallRateThreshold: 50
        slowCallDurationThreshold: 2s
        waitDurationInOpenState: 10s
        permittedNumberOfCallsInHalfOpenState: 3
  retry:
    instances:
      userService:
        maxAttempts: 3
        waitDuration: 200ms
  bulkhead:
    instances:
      userService:
        maxConcurrentCalls: 50

业务代码示例:

java
@Service
public class UserQueryService {
    private final UserClient userClient;

    public UserQueryService(UserClient userClient) {
        this.userClient = userClient;
    }

    @CircuitBreaker(name = "userService", fallbackMethod = "fallback")
    @Retry(name = "userService")
    @Bulkhead(name = "userService")
    public UserDTO getUser(Long userId) {
        return userClient.getUser(userId);
    }

    public UserDTO fallback(Long userId, Throwable ex) {
        return new UserDTO(userId, "unknown");
    }
}

注意:这个 fallback 只适合用户展示类场景。支付、扣库存、权限校验这类业务不能随便返回默认成功。

为什么只会熔断还不够

熔断只是容错治理的一部分。

问题只靠熔断是否够还需要
瞬时大流量不够限流、排队、削峰
某下游慢部分够超时、慢调用熔断、隔离
写接口失败不够幂等、事务、补偿
线程池被打满不够舱壁隔离、限流
偶发网络抖动不够有限重试和退避

容错治理要组合使用,不能把所有问题都交给一个组件。