核心观点: 熔断器是微服务架构的安全气囊,通过快速失败隔离故障,防止雪崩。Sentinel是当前生产环境的最佳选择。


熔断器核心原理

什么是熔断器?

熔断器(Circuit Breaker)借鉴了电路中的断路器概念:

电路断路器:
  正常 → 短路 → 断路器跳闸 → 保护电路

服务熔断器:
  正常 → 下游故障 → 熔断器打开 → 保护上游

核心思想: 当下游服务故障时,快速失败优于漫长等待

熔断器状态机

熔断器有三种状态:

          错误率>阈值
  Closed ───────────→ Open
    ↑                  │
    │                  │ 等待恢复时间
    │                  ↓
    │              Half-Open
    │                  │
    │  探测成功         │ 探测失败
    └──────────────────┘

状态说明:

  1. Closed(闭合): 正常状态

    • 放行所有请求
    • 统计错误率
    • 错误率>阈值 → 转Open
  2. Open(打开): 熔断状态

    • 拒绝所有请求,快速失败
    • 不调用下游服务
    • 等待一段时间 → 转Half-Open
  3. Half-Open(半开): 探测状态

    • 放行少量请求(探测)
    • 成功 → 转Closed
    • 失败 → 转Open

手写熔断器

/**
 * 简化版熔断器
 */
public class SimpleCircuitBreaker {

    // 状态枚举
    enum State { CLOSED, OPEN, HALF_OPEN }

    private State state = State.CLOSED;
    private int failureCount = 0;
    private int successCount = 0;
    private long lastFailureTime = 0;

    // 配置
    private final int failureThreshold;     // 失败阈值
    private final long timeoutMillis;       // 熔断时长
    private final int halfOpenSuccessThreshold; // 半开成功阈值

    public SimpleCircuitBreaker(int failureThreshold, long timeoutMillis) {
        this.failureThreshold = failureThreshold;
        this.timeoutMillis = timeoutMillis;
        this.halfOpenSuccessThreshold = 3;
    }

    /**
     * 执行受保护的调用
     */
    public <T> T execute(Callable<T> callable, Function<Exception, T> fallback) {
        // 检查状态
        if (state == State.OPEN) {
            // 检查是否可以进入半开状态
            if (System.currentTimeMillis() - lastFailureTime >= timeoutMillis) {
                state = State.HALF_OPEN;
                successCount = 0;
            } else {
                // 快速失败,调用降级
                return fallback.apply(new CircuitBreakerOpenException());
            }
        }

        try {
            // 调用实际方法
            T result = callable.call();

            // 调用成功
            onSuccess();
            return result;

        } catch (Exception e) {
            // 调用失败
            onFailure();
            return fallback.apply(e);
        }
    }

    private synchronized void onSuccess() {
        failureCount = 0;

        if (state == State.HALF_OPEN) {
            successCount++;
            if (successCount >= halfOpenSuccessThreshold) {
                // 连续成功,恢复闭合
                state = State.CLOSED;
            }
        }
    }

    private synchronized void onFailure() {
        lastFailureTime = System.currentTimeMillis();

        if (state == State.HALF_OPEN) {
            // 半开状态失败,立即打开
            state = State.OPEN;
            successCount = 0;
        } else if (state == State.CLOSED) {
            failureCount++;
            if (failureCount >= failureThreshold) {
                // 失败次数达到阈值,打开熔断器
                state = State.OPEN;
            }
        }
    }

    public State getState() {
        return state;
    }
}

// 使用示例
public class UserService {

    private SimpleCircuitBreaker breaker =
        new SimpleCircuitBreaker(5, 10000); // 5次失败,熔断10秒

    public User getUser(Long userId) {
        return breaker.execute(
            // 实际调用
            () -> userServiceClient.getUser(userId),

            // 降级方法
            (ex) -> {
                log.warn("用户服务熔断,返回默认用户");
                return User.defaultUser(userId);
            }
        );
    }
}

工作流程:

请求1-4: 成功 → state=CLOSED, failureCount=0
请求5-9: 失败 → state=CLOSED, failureCount=5 → 达到阈值
请求10: 失败 → state=OPEN (熔断打开)

请求11-20: 快速失败(1ms),不调用下游

10秒后:
请求21: state=HALF_OPEN,放行探测
  └─ 成功 → successCount=1
请求22-23: 继续探测,成功
  └─ successCount=3 → state=CLOSED (恢复)

请求24+: 正常调用

Hystrix vs Sentinel

核心差异

维度HystrixSentinel
隔离策略线程池隔离信号量隔离
性能低(线程切换)高(无切换)
熔断规则错误率慢调用/异常率/异常数
限流功能强大(多种算法)
Dashboard简单丰富
维护状态❌ 停止维护✅ 活跃
推荐度⭐⭐⭐⭐⭐⭐⭐

Hystrix:线程池隔离

原理:

主线程池 → Hystrix线程池 → 下游服务

优势: 完全隔离,下游故障不影响主线程
劣势: 性能开销大(线程切换、上下文切换)

代码示例:

public class GetUserCommand extends HystrixCommand<User> {

    public GetUserCommand(Long userId) {
        super(HystrixCommandGroupKey.Factory.asKey("UserService"));
    }

    @Override
    protected User run() {
        // 在Hystrix线程池中执行
        return userServiceClient.getUser(userId);
    }

    @Override
    protected User getFallback() {
        return User.defaultUser();
    }
}

// 使用
User user = new GetUserCommand(userId).execute();

Sentinel:信号量隔离

原理:

主线程 → 信号量控制 → 下游服务

优势: 性能高,无线程切换
劣势: 隔离性弱于线程池

代码示例:

@Service
public class UserService {

    @SentinelResource(
        value = "getUser",
        fallback = "getUserFallback"
    )
    public User getUser(Long userId) {
        // 主线程直接调用
        return userServiceClient.getUser(userId);
    }

    public User getUserFallback(Long userId, Throwable ex) {
        return User.defaultUser(userId);
    }
}

性能对比

JMH基准测试结果(模拟远程调用50ms):

Hystrix(线程池):
  - 吞吐量: 2000 ops/s
  - 响应时间: P99=55ms(额外5ms开销)

Sentinel(信号量):
  - 吞吐量: 18000 ops/s
  - 响应时间: P99=51ms(额外1ms开销)

性能差异: Sentinel快9倍

选择建议

选择Sentinel:

  • ✅ 性能要求高(99%场景)
  • ✅ 需要丰富的限流功能
  • ✅ 需要可视化Dashboard
  • ✅ 生产环境推荐

选择Hystrix:

  • 已有Hystrix代码,短期不迁移
  • 对隔离性要求极高的场景(罕见)

实际上: Hystrix已停止维护,强烈建议使用Sentinel


Sentinel快速上手

1. 依赖引入

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2022.0.0.0</version>
</dependency>

2. 配置文件

# application.yml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080  # Sentinel Dashboard地址
        port: 8719                 # 客户端端口
      eager: true                  # 立即加载

3. 基本使用

@RestController
@RequestMapping("/api")
public class OrderController {

    @Autowired
    private UserService userService;

    @GetMapping("/orders")
    @SentinelResource(
        value = "getOrders",           // 资源名称
        blockHandler = "handleBlock",  // 限流/熔断处理
        fallback = "handleFallback"    // 异常降级
    )
    public Result getOrders(@RequestParam Long userId) {
        User user = userService.getUser(userId);
        List<Order> orders = orderService.getByUserId(userId);
        return Result.success(orders);
    }

    // 限流/熔断处理
    public Result handleBlock(Long userId, BlockException ex) {
        log.warn("请求被限流或熔断: userId={}", userId);
        return Result.fail("系统繁忙,请稍后重试");
    }

    // 异常降级
    public Result handleFallback(Long userId, Throwable ex) {
        log.error("服务异常降级: userId={}", userId, ex);
        return Result.fail("服务暂时不可用");
    }
}

4. 编程式配置规则

@Configuration
public class SentinelConfig {

    @PostConstruct
    public void initRules() {
        // 限流规则
        List<FlowRule> flowRules = new ArrayList<>();
        FlowRule flowRule = new FlowRule("getOrders");
        flowRule.setCount(100);  // 100 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        flowRules.add(flowRule);
        FlowRuleManager.loadRules(flowRules);

        // 熔断规则
        List<DegradeRule> degradeRules = new ArrayList<>();

        // 规则1: 慢调用比例
        DegradeRule slowRule = new DegradeRule("getOrders");
        slowRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        slowRule.setCount(1000);                // RT>1秒为慢调用
        slowRule.setSlowRatioThreshold(0.5);   // 慢调用比例50%
        slowRule.setMinRequestAmount(10);       // 最小请求数10
        slowRule.setStatIntervalMs(1000);       // 统计时长1秒
        slowRule.setTimeWindow(10);             // 熔断10秒
        degradeRules.add(slowRule);

        // 规则2: 异常比例
        DegradeRule exceptionRule = new DegradeRule("getOrders");
        exceptionRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
        exceptionRule.setCount(0.5);            // 异常比例50%
        exceptionRule.setMinRequestAmount(10);
        exceptionRule.setStatIntervalMs(1000);
        exceptionRule.setTimeWindow(10);
        degradeRules.add(exceptionRule);

        DegradeRuleManager.loadRules(degradeRules);
    }
}

5. Sentinel Dashboard

启动Dashboard:

# 下载sentinel-dashboard.jar
wget https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar

# 启动(端口8080)
java -jar sentinel-dashboard-1.8.6.jar

# 访问
http://localhost:8080
用户名: sentinel
密码: sentinel

功能:

  • ✅ 实时监控:QPS、响应时间、错误率
  • ✅ 规则配置:限流、熔断、热点、系统规则
  • ✅ 调用链路:可视化依赖关系
  • ✅ 集群管理:多实例统一管理

生产最佳实践

1. 熔断阈值配置

慢调用比例熔断:

DegradeRule rule = new DegradeRule("resourceName");
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);

// RT阈值 = P99响应时间 × 2
// 示例:正常P99=500ms,设置1000ms
rule.setCount(1000);

// 慢调用比例 = 50%(容错率)
rule.setSlowRatioThreshold(0.5);

// 最小请求数 = 10(避免样本过少)
rule.setMinRequestAmount(10);

// 熔断时长 = 10秒(快速恢复)
rule.setTimeWindow(10);

配置建议:

RT阈值配置:
  - 快速接口(P99<100ms): RT阈值 = 200ms
  - 一般接口(P99=100-500ms): RT阈值 = P99 × 2
  - 慢接口(P99>500ms): RT阈值 = P99 × 1.5

慢调用比例:
  - 严格模式: 30%(敏感)
  - 标准模式: 50%(推荐)
  - 宽松模式: 70%(容忍度高)

熔断时长:
  - 快速恢复: 5-10秒(推荐)
  - 中等恢复: 30秒
  - 长期恢复: 60秒(慎用)

2. 降级策略设计

分级降级:

@Service
public class OrderService {

    // L1: 核心接口 - 返回兜底数据
    @SentinelResource(value = "createOrder", fallback = "createOrderFallback")
    public Order createOrder(OrderRequest request) {
        return orderRepository.save(buildOrder(request));
    }

    public Order createOrderFallback(OrderRequest request, Throwable ex) {
        // 降级:返回pending状态订单,后台异步处理
        log.warn("订单创建降级,userId={}", request.getUserId());
        Order order = new Order();
        order.setStatus(OrderStatus.PENDING);
        order.setUserId(request.getUserId());
        // 发送到消息队列,异步处理
        mqProducer.send(request);
        return order;
    }

    // L2: 重要接口 - 返回缓存
    @SentinelResource(value = "getOrderDetail", fallback = "getOrderDetailFallback")
    public Order getOrderDetail(Long orderId) {
        return orderRepository.findById(orderId);
    }

    public Order getOrderDetailFallback(Long orderId, Throwable ex) {
        // 降级:返回缓存数据
        return cacheService.get("order:" + orderId);
    }

    // L3: 非核心接口 - 快速失败
    @SentinelResource(value = "getRecommendation", fallback = "getRecommendationFallback")
    public List<Product> getRecommendation(Long userId) {
        return recommendService.getForUser(userId);
    }

    public List<Product> getRecommendationFallback(Long userId, Throwable ex) {
        // 降级:返回空列表
        return Collections.emptyList();
    }
}

降级策略矩阵:

接口类型降级策略示例
核心写接口异步处理创建订单→MQ异步
核心读接口返回兜底数据用户信息→默认用户
重要接口返回缓存商品详情→缓存数据
非核心接口快速失败推荐服务→空列表
边缘功能功能降级统计报表→提示维护中

3. 规则持久化

Sentinel默认规则存储在内存,重启丢失。生产环境需要持久化到配置中心。

Nacos集成:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
spring:
  cloud:
    sentinel:
      datasource:
        # 流控规则
        flow:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow

        # 熔断规则
        degrade:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}-degrade-rules
            groupId: SENTINEL_GROUP
            rule-type: degrade

Nacos配置示例:

[
  {
    "resource": "getOrders",
    "grade": 0,
    "count": 1000,
    "slowRatioThreshold": 0.5,
    "minRequestAmount": 10,
    "statIntervalMs": 1000,
    "timeWindow": 10
  }
]

4. 监控告警

核心指标:

// 自定义监控指标
@Component
public class SentinelMetrics {

    @Scheduled(fixedRate = 60000)
    public void collectMetrics() {
        // 获取所有资源的统计信息
        Map<String, Node> nodeMap = ClusterBuilderSlot.getClusterNodeMap();

        for (Map.Entry<String, Node> entry : nodeMap.entrySet()) {
            String resource = entry.getKey();
            Node node = entry.getValue();

            // 关键指标
            long passQps = node.passQps();           // 通过QPS
            long blockQps = node.blockQps();         // 拒绝QPS
            long exceptionQps = node.exceptionQps(); // 异常QPS
            double avgRt = node.avgRt();             // 平均响应时间

            // 上报到监控系统
            metricsReporter.report(resource, passQps, blockQps, exceptionQps, avgRt);
        }
    }
}

告警规则:

# Prometheus告警规则
groups:
  - name: sentinel_alerts
    rules:
      # 熔断告警
      - alert: CircuitBreakerOpen
        expr: sentinel_circuit_breaker_state == 1
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "熔断器打开"
          description: "{{ $labels.resource }} 熔断器已打开"

      # 限流告警
      - alert: HighBlockRate
        expr: rate(sentinel_block_qps[1m]) > 100
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "限流次数过多"
          description: "{{ $labels.resource }} 限流 > 100次/min"

      # 响应时间告警
      - alert: HighResponseTime
        expr: sentinel_avg_rt > 1000
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "响应时间过长"
          description: "{{ $labels.resource }} P99 > 1秒"

核心对比总结

Hystrix vs Sentinel 终极对比

维度HystrixSentinel推荐
性能2000 ops/s18000 ops/sSentinel
隔离方式线程池(强隔离)信号量(轻量)Sentinel
限流功能❌ 无✅ 强大Sentinel
熔断规则错误率慢调用/异常率/异常数Sentinel
热点限流❌ 无✅ 支持Sentinel
系统自适应❌ 无✅ 支持Sentinel
Dashboard简单功能丰富Sentinel
规则持久化❌ 难✅ 易(Nacos等)Sentinel
维护状态❌ 停止维护✅ 活跃Sentinel
学习曲线中等中等平手
社区支持❌ 弱✅ 强Sentinel

结论: Sentinel全面优于Hystrix,生产环境强烈推荐Sentinel

快速配置检查清单

生产环境上线前检查:

熔断配置:

  • RT阈值 = P99响应时间 × 2
  • 慢调用比例 = 50%
  • 最小请求数 ≥ 10
  • 熔断时长 = 10秒

降级策略:

  • 核心接口有降级方法
  • 降级方法经过测试
  • 降级日志记录完整
  • 降级数据合理(不返回null)

监控告警:

  • 熔断事件告警
  • 限流次数告警
  • 响应时间告警
  • 错误率告警

规则持久化:

  • 规则存储到配置中心(Nacos)
  • 规则版本控制
  • 规则变更有审批流程

压测验证:

  • 正常流量下验证
  • 2倍流量下验证
  • 下游故障场景验证
  • 熔断恢复场景验证

总结

核心要点

  1. 熔断器是微服务必备

    • 防止雪崩扩散
    • 快速失败优于漫长等待
    • 状态机:Closed → Open → Half-Open
  2. Sentinel是最佳选择

    • 性能:比Hystrix快9倍
    • 功能:限流+熔断+热点+自适应
    • 生态:活跃维护,丰富Dashboard
  3. 生产配置建议

    • RT阈值 = P99 × 2
    • 慢调用比例 = 50%
    • 熔断时长 = 10秒
    • 规则持久化到Nacos
  4. 降级策略分级

    • 核心接口:返回兜底数据
    • 重要接口:返回缓存
    • 非核心接口:快速失败

下一步行动

  1. 快速上手:Spring Boot集成Sentinel(10分钟)
  2. 压测验证:验证熔断效果(30分钟)
  3. 配置优化:根据P99调整阈值(1小时)
  4. 监控告警:接入Prometheus(2小时)
  5. 规则持久化:集成Nacos(1小时)

总耗时: 半天即可完成生产环境熔断降级方案。


系列文章:

  1. ✅ 为什么需要熔断限流?从一次生产事故说起
  2. ✅ 限流算法深度解析:从计数器到令牌桶
  3. ✅ 熔断降级实战:从Hystrix到Sentinel(本文)

参考资料:


📢 如果这篇文章对你有帮助,欢迎点赞、收藏、转发!