52-熔断降级详解

5 阅读12分钟

熔断降级详解

一、知识概述

熔断降级是微服务架构中保护系统稳定性的重要机制。当下游服务出现故障或响应变慢时,熔断器会快速失败,防止故障蔓延,同时提供降级策略保证系统可用性。

本文将深入讲解:

  • 熔断器原理与状态机
  • Hystrix熔断器
  • Sentinel熔断降级
  • Resilience4j弹性设计
  • 自定义熔断器实现

二、为什么需要熔断

2.1 雪崩效应

正常情况:
服务A ──→ 服务B ──→ 服务C
  ↓         ↓         ↓
 正常      正常      正常

服务C故障时:
服务A ──→ 服务B ──→ 服务C(故障)
  ↓         ↓         ↓
 等待      等待      超时
  ↓         ↓
线程堆积   线程堆积
  ↓         ↓
服务A崩溃  服务B崩溃

→ 整个链路崩溃(雪崩效应)

2.2 熔断器的作用

                   ┌─────────────────┐
服务A ──请求──→   │    熔断器        │
                   │  ┌───────────┐  │
                   │  │ 状态判断  │──┼──→ 正常 ──→ 服务B
                   │  └───────────┘  │
                   │        │        │
                   │        ↓ 熔断   │
                   │  ┌───────────┐  │
                   │  │ 降级响应  │──┼──→ 降级数据
                   │  └───────────┘  │
                   └─────────────────┘

核心作用:

  1. 快速失败:避免等待超时,释放线程资源
  2. 防止雪崩:阻断故障蔓延
  3. 优雅降级:提供备选方案,保证基本可用
  4. 自动恢复:故障恢复后自动切换回正常状态

三、熔断器原理

3.1 状态机模型

         ┌──────────────────────────────────────┐
         │                                      │
         ↓                                      │
    ┌─────────┐  失败率>阈值   ┌─────────┐      │
    │  CLOSED │ ─────────────→ │   OPEN  │      │
    │ (关闭)  │                │ (打开)  │      │
    └─────────┘                └─────────┘      │
         ↑                          │           │
         │                     超时时间到        │
         │                          ↓           │
         │                     ┌─────────┐      │
         └────────────────────│HALF_OPEN│───────┘
              成功率恢复       │(半开)   │  失败
                               └─────────┘

三种状态:

状态说明行为
CLOSED关闭状态(正常)请求正常通过,统计失败率
OPEN打开状态(熔断)请求直接返回降级数据
HALF_OPEN半开状态(探测)放行部分请求探测服务是否恢复

3.2 状态转换规则

/**
 * 熔断器状态枚举
 */
public enum CircuitState {
    CLOSED,      // 关闭:正常请求
    OPEN,        // 打开:熔断中
    HALF_OPEN    // 半开:探测恢复
}

/**
 * 状态转换条件
 */
public class StateTransition {
    
    // CLOSED -> OPEN:失败率超过阈值
    public static final double FAILURE_RATE_THRESHOLD = 0.5; // 50%
    
    // OPEN -> HALF_OPEN:熔断超时
    public static final long OPEN_TIMEOUT_MS = 10000; // 10秒
    
    // HALF_OPEN -> CLOSED:探测成功
    public static final int SUCCESS_THRESHOLD = 3; // 连续成功3次
    
    // HALF_OPEN -> OPEN:探测失败
    public static final int FAILURE_THRESHOLD = 1; // 失败1次
}

四、自定义熔断器实现

4.1 基础实现

/**
 * 熔断器实现
 */
public class CircuitBreaker {
    
    private final String name;
    private final CircuitBreakerConfig config;
    
    // 状态
    private final AtomicReference<CircuitState> state;
    
    // 统计窗口
    private final SlidingWindow slidingWindow;
    
    // 熔断开始时间
    private final AtomicLong openStartTime;
    
    // 半开状态计数
    private final AtomicInteger halfOpenSuccess;
    private final AtomicInteger halfOpenFailure;
    
    public CircuitBreaker(String name, CircuitBreakerConfig config) {
        this.name = name;
        this.config = config;
        this.state = new AtomicReference<>(CircuitState.CLOSED);
        this.slidingWindow = new SlidingWindow(config.getWindowSize());
        this.openStartTime = new AtomicLong(0);
        this.halfOpenSuccess = new AtomicInteger(0);
        this.halfOpenFailure = new AtomicInteger(0);
    }
    
    /**
     * 尝试获取许可
     */
    public boolean tryAcquire() {
        CircuitState currentState = state.get();
        
        switch (currentState) {
            case CLOSED:
                return true;
                
            case OPEN:
                // 检查是否超过熔断时间
                if (System.currentTimeMillis() - openStartTime.get() >= config.getOpenTimeoutMs()) {
                    // 转换到半开状态
                    if (state.compareAndSet(CircuitState.OPEN, CircuitState.HALF_OPEN)) {
                        halfOpenSuccess.set(0);
                        halfOpenFailure.set(0);
                        return true;
                    }
                }
                return false;
                
            case HALF_OPEN:
                // 半开状态,只允许少量请求通过
                return halfOpenSuccess.get() + halfOpenFailure.get() < config.getHalfOpenMaxCalls();
                
            default:
                return false;
        }
    }
    
    /**
     * 记录成功
     */
    public void recordSuccess() {
        CircuitState currentState = state.get();
        
        switch (currentState) {
            case CLOSED:
                slidingWindow.recordSuccess();
                break;
                
            case HALF_OPEN:
                int success = halfOpenSuccess.incrementAndGet();
                if (success >= config.getSuccessThreshold()) {
                    // 探测成功,恢复到关闭状态
                    state.compareAndSet(CircuitState.HALF_OPEN, CircuitState.CLOSED);
                    slidingWindow.reset();
                }
                break;
                
            default:
                break;
        }
    }
    
    /**
     * 记录失败
     */
    public void recordFailure() {
        CircuitState currentState = state.get();
        
        switch (currentState) {
            case CLOSED:
                slidingWindow.recordFailure();
                // 检查失败率
                if (slidingWindow.getFailureRate() >= config.getFailureRateThreshold()) {
                    // 失败率超过阈值,熔断
                    if (state.compareAndSet(CircuitState.CLOSED, CircuitState.OPEN)) {
                        openStartTime.set(System.currentTimeMillis());
                    }
                }
                break;
                
            case HALF_OPEN:
                halfOpenFailure.incrementAndGet();
                // 探测失败,重新熔断
                if (state.compareAndSet(CircuitState.HALF_OPEN, CircuitState.OPEN)) {
                    openStartTime.set(System.currentTimeMillis());
                }
                break;
                
            default:
                break;
        }
    }
    
    /**
     * 获取当前状态
     */
    public CircuitState getState() {
        return state.get();
    }
    
    /**
     * 获取统计信息
     */
    public CircuitStats getStats() {
        return new CircuitStats(
            name,
            state.get(),
            slidingWindow.getTotalCalls(),
            slidingWindow.getSuccessCalls(),
            slidingWindow.getFailureCalls(),
            slidingWindow.getFailureRate()
        );
    }
}

/**
 * 熔断器配置
 */
@Data
@Builder
public class CircuitBreakerConfig {
    private int windowSize;             // 统计窗口大小
    private double failureRateThreshold; // 失败率阈值
    private long openTimeoutMs;         // 熔断超时时间
    private int halfOpenMaxCalls;       // 半开状态最大调用次数
    private int successThreshold;       // 恢复成功阈值
}

/**
 * 滑动窗口统计
 */
public class SlidingWindow {
    
    private final int size;
    private final LinkedList<Boolean> window;
    
    public SlidingWindow(int size) {
        this.size = size;
        this.window = new LinkedList<>();
    }
    
    public synchronized void recordSuccess() {
        window.addLast(true);
        if (window.size() > size) {
            window.removeFirst();
        }
    }
    
    public synchronized void recordFailure() {
        window.addLast(false);
        if (window.size() > size) {
            window.removeFirst();
        }
    }
    
    public synchronized double getFailureRate() {
        if (window.isEmpty()) {
            return 0.0;
        }
        
        long failures = window.stream().filter(b -> !b).count();
        return (double) failures / window.size();
    }
    
    public synchronized void reset() {
        window.clear();
    }
    
    public synchronized int getTotalCalls() {
        return window.size();
    }
    
    public synchronized long getSuccessCalls() {
        return window.stream().filter(b -> b).count();
    }
    
    public synchronized long getFailureCalls() {
        return window.stream().filter(b -> !b).count();
    }
}

/**
 * 统计信息
 */
@Data
@AllArgsConstructor
public class CircuitStats {
    private String name;
    private CircuitState state;
    private int totalCalls;
    private long successCalls;
    private long failureCalls;
    private double failureRate;
}

4.2 使用模板

/**
 * 熔断器模板
 */
@Component
public class CircuitBreakerTemplate {
    
    private final Map<String, CircuitBreaker> breakers = new ConcurrentHashMap<>();
    
    /**
     * 在熔断保护下执行
     */
    public <T> T execute(String breakerName, CircuitBreakerConfig config,
                         Supplier<T> supplier, Supplier<T> fallback) {
        CircuitBreaker breaker = breakers.computeIfAbsent(breakerName,
            k -> new CircuitBreaker(k, config));
        
        // 尝试获取许可
        if (!breaker.tryAcquire()) {
            // 熔断中,返回降级数据
            return fallback.get();
        }
        
        try {
            T result = supplier.get();
            breaker.recordSuccess();
            return result;
        } catch (Exception e) {
            breaker.recordFailure();
            return fallback.get();
        }
    }
    
    /**
     * 无返回值版本
     */
    public void execute(String breakerName, CircuitBreakerConfig config,
                        Runnable runnable, Runnable fallback) {
        execute(breakerName, config, 
            () -> { runnable.run(); return null; },
            () -> { fallback.run(); return null; }
        );
    }
    
    /**
     * 获取熔断器状态
     */
    public CircuitStats getStats(String breakerName) {
        CircuitBreaker breaker = breakers.get(breakerName);
        return breaker != null ? breaker.getStats() : null;
    }
}

// 使用示例
@Service
public class OrderService {
    
    @Autowired
    private CircuitBreakerTemplate circuitBreakerTemplate;
    
    public Order getOrder(Long orderId) {
        CircuitBreakerConfig config = CircuitBreakerConfig.builder()
            .windowSize(100)
            .failureRateThreshold(0.5)
            .openTimeoutMs(10000)
            .halfOpenMaxCalls(5)
            .successThreshold(3)
            .build();
        
        return circuitBreakerTemplate.execute(
            "order-service",
            config,
            () -> callRemoteService(orderId),    // 正常调用
            () -> getOrderFromCache(orderId)     // 降级方案
        );
    }
}

五、Hystrix熔断器

5.1 依赖配置

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

5.2 基础使用

@SpringBootApplication
@EnableCircuitBreaker
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@Service
public class UserService {
    
    @Autowired
    private RestTemplate restTemplate;
    
    /**
     * 使用@HystrixCommand注解
     */
    @HystrixCommand(
        fallbackMethod = "getUserFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
        }
    )
    public User getUser(Long userId) {
        return restTemplate.getForObject("http://user-service/users/" + userId, User.class);
    }
    
    /**
     * 降级方法(参数必须一致)
     */
    public User getUserFallback(Long userId) {
        // 返回默认用户或缓存数据
        return User.defaultUser();
    }
}

5.3 配置详解

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000  # 超时时间
          strategy: THREAD               # 隔离策略
        timeout:
          enabled: true                  # 启用超时
      circuitBreaker:
        enabled: true                    # 启用熔断
        requestVolumeThreshold: 20       # 请求量阈值
        errorThresholdPercentage: 50     # 错误百分比阈值
        sleepWindowInMilliseconds: 5000  # 熔断时间窗口
      metrics:
        rollingStats:
          timeInMilliseconds: 10000      # 统计窗口时间
          numBuckets: 10                 # 统计窗口桶数
    # 特定命令配置
    getUser:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000
  
  threadpool:
    default:
      coreSize: 10                       # 核心线程数
      maximumSize: 20                    # 最大线程数
      maxQueueSize: -1                   # 队列大小(-1不使用队列)
      keepAliveTimeMinutes: 1            # 空闲线程存活时间

5.4 Hystrix Dashboard

@SpringBootApplication
@EnableHystrixDashboard
public class DashboardApplication {
    public static void main(String[] args) {
        SpringApplication.run(DashboardApplication.class, args);
    }
}

// 被监控服务需要开启监控端点
@Configuration
public class HystrixConfig {
    
    @Bean
    public ServletRegistrationBean<HystrixMetricsStreamServlet> hystrixMetricsStreamServlet() {
        HystrixMetricsStreamServlet servlet = new HystrixMetricsStreamServlet();
        return new ServletRegistrationBean<>(servlet, "/hystrix.stream");
    }
}

六、Sentinel熔断降级

6.1 依赖配置

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

6.2 基础使用

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@Service
public class ProductService {
    
    /**
     * 使用@SentinelResource注解
     */
    @SentinelResource(
        value = "getProduct",
        fallback = "getProductFallback",      // 降级方法
        blockHandler = "getProductBlockHandler" // 限流/熔断处理方法
    )
    public Product getProduct(Long productId) {
        // 业务逻辑
        return callRemoteService(productId);
    }
    
    /**
     * 降级方法(处理业务异常)
     */
    public Product getProductFallback(Long productId, Throwable t) {
        log.warn("获取商品降级: productId={}, error={}", productId, t.getMessage());
        return Product.defaultProduct();
    }
    
    /**
     * 限流/熔断处理方法
     */
    public Product getProductBlockHandler(Long productId, BlockException e) {
        log.warn("获取商品被限流/熔断: productId={}", productId);
        return Product.defaultProduct();
    }
}

6.3 熔断规则配置

@Configuration
public class SentinelConfig {
    
    @PostConstruct
    public void initRules() {
        List<DegradeRule> rules = new ArrayList<>();
        
        // 慢调用比例熔断
        DegradeRule slowCallRule = new DegradeRule("getProduct");
        slowCallRule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
        slowCallRule.setCount(500);  // 慢调用阈值:500ms
        slowCallRule.setSlowRatioThreshold(0.5);  // 慢调用比例:50%
        slowCallRule.setMinRequestAmount(10);     // 最小请求数
        slowCallRule.setStatIntervalMs(10000);    // 统计时长
        slowCallRule.setTimeWindow(10);           // 熔断时长:10秒
        rules.add(slowCallRule);
        
        // 异常比例熔断
        DegradeRule errorRatioRule = new DegradeRule("getProduct");
        errorRatioRule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
        errorRatioRule.setCount(0.3);  // 异常比例:30%
        errorRatioRule.setMinRequestAmount(10);
        errorRatioRule.setStatIntervalMs(10000);
        errorRatioRule.setTimeWindow(10);
        rules.add(errorRatioRule);
        
        // 异常数熔断
        DegradeRule errorCountRule = new DegradeRule("getProduct");
        errorCountRule.setGrade(CircuitBreakerStrategy.ERROR_COUNT.getType());
        errorCountRule.setCount(5);  // 异常数:5
        errorCountRule.setMinRequestAmount(10);
        errorCountRule.setStatIntervalMs(10000);
        errorCountRule.setTimeWindow(10);
        rules.add(errorCountRule);
        
        DegradeRuleManager.loadRules(rules);
    }
}

6.4 Sentinel Dashboard

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080  # Dashboard地址
        port: 8719                  # 与Dashboard通信端口
      eager: true                   # 应用启动时立即初始化

6.5 三种熔断策略

/**
 * Sentinel熔断策略示例
 */
@Service
public class DegradeStrategyDemo {
    
    /**
     * 策略1:慢调用比例
     * 当响应时间超过阈值(如500ms)的调用比例达到设定值时触发熔断
     */
    public void slowCallRatioStrategy() {
        // 配置示例:
        // - 慢调用阈值:500ms
        // - 慢调用比例:50%
        // - 最小请求数:10
        // - 统计时长:10秒
        // 
        // 触发条件:10秒内至少10个请求,慢调用比例>50%
    }
    
    /**
     * 策略2:异常比例
     * 当异常调用比例达到设定值时触发熔断
     */
    public void errorRatioStrategy() {
        // 配置示例:
        // - 异常比例:30%
        // - 最小请求数:10
        // - 统计时长:10秒
        //
        // 触发条件:10秒内至少10个请求,异常比例>30%
    }
    
    /**
     * 策略3:异常数
     * 当异常调用数达到设定值时触发熔断
     */
    public void errorCountStrategy() {
        // 配置示例:
        // - 异常数:5
        // - 最小请求数:10
        // - 统计时长:10秒
        //
        // 触发条件:10秒内至少10个请求,异常数>5
    }
}

七、Resilience4j

7.1 依赖配置

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

7.2 配置

resilience4j:
  circuitbreaker:
    configs:
      default:
        slidingWindowSize: 100
        slidingWindowType: COUNT_BASED
        minimumNumberOfCalls: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 10s
        permittedNumberOfCallsInHalfOpenState: 5
        automaticTransitionFromOpenToHalfOpenEnabled: true
    instances:
      userService:
        baseConfig: default
      orderService:
        slidingWindowSize: 50
        failureRateThreshold: 40
        waitDurationInOpenState: 5s
  
  retry:
    configs:
      default:
        maxAttempts: 3
        waitDuration: 500ms
        retryExceptions:
          - java.io.IOException
          - java.net.SocketTimeoutException
    instances:
      userService:
        baseConfig: default
  
  ratelimiter:
    configs:
      default:
        limitForPeriod: 100
        limitRefreshPeriod: 1s
        timeoutDuration: 0
    instances:
      userService:
        baseConfig: default
  
  timelimiter:
    configs:
      default:
        timeoutDuration: 3s
        cancelRunningFuture: true
    instances:
      userService:
        timeoutDuration: 5s

7.3 使用示例

@Service
public class PaymentService {
    
    /**
     * 熔断器
     */
    @CircuitBreaker(name = "paymentService", fallbackMethod = "processPaymentFallback")
    public PaymentResult processPayment(PaymentRequest request) {
        // 业务逻辑
        return doPayment(request);
    }
    
    public PaymentResult processPaymentFallback(PaymentRequest request, Throwable t) {
        log.warn("支付服务降级: {}", t.getMessage());
        return PaymentResult.pending();
    }
    
    /**
     * 熔断 + 重试
     */
    @CircuitBreaker(name = "paymentService")
    @Retry(name = "paymentService")
    public PaymentResult processPaymentWithRetry(PaymentRequest request) {
        return doPayment(request);
    }
    
    /**
     * 熔断 + 重试 + 限流
     */
    @CircuitBreaker(name = "paymentService")
    @Retry(name = "paymentService")
    @RateLimiter(name = "paymentService")
    public PaymentResult processPaymentFull(PaymentRequest request) {
        return doPayment(request);
    }
    
    /**
     * 超时控制
     */
    @TimeLimiter(name = "paymentService")
    @CircuitBreaker(name = "paymentService")
    public CompletableFuture<PaymentResult> processPaymentAsync(PaymentRequest request) {
        return CompletableFuture.supplyAsync(() -> doPayment(request));
    }
}

7.4 编程式使用

@Service
public class InventoryService {
    
    private final CircuitBreaker circuitBreaker;
    private final Retry retry;
    private final RateLimiter rateLimiter;
    
    public InventoryService(
            CircuitBreakerRegistry circuitBreakerRegistry,
            RetryRegistry retryRegistry,
            RateLimiterRegistry rateLimiterRegistry) {
        
        this.circuitBreaker = circuitBreakerRegistry.circuitBreaker("inventoryService");
        this.retry = retryRegistry.retry("inventoryService");
        this.rateLimiter = rateLimiterRegistry.rateLimiter("inventoryService");
    }
    
    /**
     * 编程式组合
     */
    public Inventory getInventory(Long productId) {
        // 组合多个弹性模式
        Supplier<Inventory> supplier = () -> callRemoteService(productId);
        
        // 添加限流
        Supplier<Inventory> rateLimitedSupplier = 
            RateLimiter.decorateSupplier(rateLimiter, supplier);
        
        // 添加重试
        Supplier<Inventory> retrySupplier = 
            Retry.decorateSupplier(retry, rateLimitedSupplier);
        
        // 添加熔断
        Supplier<Inventory> circuitBreakerSupplier = 
            CircuitBreaker.decorateSupplier(circuitBreaker, retrySupplier);
        
        try {
            return circuitBreakerSupplier.get();
        } catch (Exception e) {
            return getInventoryFromCache(productId);
        }
    }
    
    /**
     * 使用Try.of().recover()
     */
    public Inventory getInventoryWithRecovery(Long productId) {
        return CircuitBreaker.decorateSupplier(circuitBreaker, 
            () -> callRemoteService(productId))
            .get();
    }
}

八、降级策略

8.1 常见降级策略

@Service
public class FallbackStrategyService {
    
    /**
     * 策略1:返回默认值
     */
    public User getDefaultFallback(Long userId) {
        return User.defaultUser();
    }
    
    /**
     * 策略2:返回缓存数据
     */
    @Autowired
    private RedisTemplate<String, User> redisTemplate;
    
    public User getFromCache(Long userId) {
        return redisTemplate.opsForValue().get("user:" + userId);
    }
    
    /**
     * 策略3:返回部分数据
     */
    public Product getProductPartial(Long productId) {
        Product product = new Product();
        product.setId(productId);
        product.setName("商品信息暂时不可用");
        product.setPrice(null);  // 价格不返回
        return product;
    }
    
    /**
     * 策略4:调用备用服务
     */
    @Autowired
    private RestTemplate restTemplate;
    
    public Order getOrderFromBackup(Long orderId) {
        // 调用备用服务
        return restTemplate.getForObject(
            "http://backup-order-service/orders/" + orderId, 
            Order.class
        );
    }
    
    /**
     * 策略5:返回错误提示
     */
    public Result getErrorFallback() {
        return Result.error("系统繁忙,请稍后再试");
    }
    
    /**
     * 策略6:排队/异步处理
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void submitAsync(Request request) {
        // 发送到消息队列,异步处理
        rabbitTemplate.convertAndSend("request.queue", request);
    }
}

8.2 分级降级

/**
 * 分级降级策略
 */
@Service
public class GradedFallbackService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private LocalCacheService localCache;
    
    /**
     * 多级降级:主服务 -> Redis缓存 -> 本地缓存 -> 默认值
     */
    public Product getProduct(Long productId) {
        try {
            // L1: 主服务
            return callMainService(productId);
        } catch (Exception e) {
            log.warn("主服务异常,尝试Redis缓存");
        }
        
        // L2: Redis缓存
        Product product = (Product) redisTemplate.opsForValue()
            .get("product:" + productId);
        if (product != null) {
            return product;
        }
        
        // L3: 本地缓存
        product = localCache.get("product:" + productId);
        if (product != null) {
            return product;
        }
        
        // L4: 默认值
        return Product.defaultProduct();
    }
}

九、监控与告警

9.1 指标采集

/**
 * 熔断器指标采集
 */
@Component
public class CircuitBreakerMetrics {
    
    private final MeterRegistry meterRegistry;
    
    public CircuitBreakerMetrics(MeterRegistry meterRegistry,
                                  CircuitBreakerRegistry registry) {
        this.meterRegistry = meterRegistry;
        
        // 为所有熔断器注册指标
        registry.getAllCircuitBreakers().forEach(this::registerMetrics);
    }
    
    private void registerMetrics(CircuitBreaker circuitBreaker) {
        String name = circuitBreaker.getName();
        
        // 状态指标
        Gauge.builder("circuit_breaker_state", circuitBreaker, cb -> cb.getState().getOrder())
            .tag("name", name)
            .register(meterRegistry);
        
        // 调用次数
        Counter successCounter = Counter.builder("circuit_breaker_calls")
            .tag("name", name)
            .tag("result", "success")
            .register(meterRegistry);
        
        Counter failureCounter = Counter.builder("circuit_breaker_calls")
            .tag("name", name)
            .tag("result", "failure")
            .register(meterRegistry);
        
        // 注册事件监听
        circuitBreaker.getEventPublisher()
            .onSuccess(event -> successCounter.increment())
            .onError(event -> failureCounter.increment())
            .onStateTransition(event -> {
                log.info("熔断器状态变化: {} -> {}", 
                    event.getStateTransition().getFromState(),
                    event.getStateTransition().getToState());
            });
    }
}

9.2 告警规则

/**
 * 熔断器告警服务
 */
@Service
@Slf4j
public class CircuitBreakerAlertService {
    
    @Autowired
    private NotificationService notificationService;
    
    private final Map<String, Long> lastAlertTime = new ConcurrentHashMap<>();
    
    /**
     * 监听熔断事件
     */
    @EventListener
    public void onCircuitBreakerEvent(CircuitBreakerOnStateTransitionEvent event) {
        String breakerName = event.getCircuitBreakerName();
        CircuitBreaker.State toState = event.getStateTransition().getToState();
        
        // 检查告警冷却时间
        if (shouldAlert(breakerName)) {
            String message = String.format("熔断器[%s]状态变更为: %s", 
                breakerName, toState);
            
            if (toState == CircuitBreaker.State.OPEN) {
                // 熔断打开,发送告警
                notificationService.sendAlert("熔断告警", message);
            } else if (toState == CircuitBreaker.State.CLOSED) {
                // 熔断恢复,发送通知
                notificationService.sendNotice("熔断恢复", message);
            }
            
            lastAlertTime.put(breakerName, System.currentTimeMillis());
        }
    }
    
    private boolean shouldAlert(String breakerName) {
        Long last = lastAlertTime.get(breakerName);
        return last == null || System.currentTimeMillis() - last > 60000; // 1分钟冷却
    }
}

十、最佳实践

10.1 设计原则

1. 快速失败
   - 超时时间设置合理
   - 熔断阈值设置合理

2. 优雅降级
   - 提供有意义的降级数据
   - 保证核心功能可用

3. 自动恢复
   - 设置合理的探测机制
   - 避免抖动

4. 可观测性
   - 完善的监控指标
   - 及时告警通知

10.2 配置建议

/**
 * 熔断器配置建议
 */
public class CircuitBreakerBestPractice {
    
    /**
     * API网关熔断配置
     */
    public CircuitBreakerConfig apiGatewayConfig() {
        return CircuitBreakerConfig.builder()
            .slidingWindowSize(100)           // 统计最近100次请求
            .failureRateThreshold(50)          // 失败率50%触发熔断
            .waitDurationInOpenState(Duration.ofSeconds(10))  // 熔断10秒
            .permittedNumberOfCallsInHalfOpenState(5)  // 半开状态放行5个请求
            .minimumNumberOfCalls(20)          // 最少20次请求才计算失败率
            .build();
    }
    
    /**
     * 数据库服务熔断配置
     */
    public CircuitBreakerConfig databaseConfig() {
        return CircuitBreakerConfig.builder()
            .slidingWindowSize(50)
            .failureRateThreshold(30)          // 数据库更敏感,30%失败率
            .waitDurationInOpenState(Duration.ofSeconds(5))
            .permittedNumberOfCallsInHalfOpenState(3)
            .minimumNumberOfCalls(10)
            .build();
    }
    
    /**
     * 外部API熔断配置
     */
    public CircuitBreakerConfig externalApiConfig() {
        return CircuitBreakerConfig.builder()
            .slidingWindowSize(20)             // 窗口小一些
            .failureRateThreshold(60)          // 外部服务容忍度高一些
            .waitDurationInOpenState(Duration.ofSeconds(30))  // 等待时间长一些
            .permittedNumberOfCallsInHalfOpenState(5)
            .minimumNumberOfCalls(5)
            .build();
    }
}

10.3 常见问题

/**
 * 常见问题与解决方案
 */
public class CircuitBreakerIssues {
    
    /**
     * 问题1:熔断器抖动
     * 原因:阈值设置过低,或恢复探测过快
     * 解决:调整阈值和等待时间
     */
    public void solveOscillation() {
        // 增加统计窗口
        // 增加等待时间
        // 增加最小请求数
    }
    
    /**
     * 问题2:熔断不生效
     * 原因:异常被吞掉,或配置错误
     * 解决:正确处理异常,检查配置
     */
    public void solveNotWorking() {
        // 确保异常被正确抛出
        // 检查异常类型是否被记录
        // 验证配置是否生效
    }
    
    /**
     * 问题3:降级数据不合理
     * 原因:降级策略设计不当
     * 解决:设计合理的降级策略
     */
    public void solveBadFallback() {
        // 核心数据返回缓存或默认值
        // 非核心数据返回null或空列表
        // 用户友好提示
    }
}

十一、总结

11.1 框架对比

特性HystrixSentinelResilience4j
维护状态停止维护活跃维护活跃维护
熔断策略异常比例多种策略可配置
限流不支持支持支持
控制台DashboardDashboard不提供
学习成本
性能

11.2 选择建议

  • 新项目:推荐 Resilience4j 或 Sentinel
  • 已有Hystrix:可继续使用,建议迁移到 Resilience4j
  • 阿里生态:Sentinel 与 Spring Cloud Alibaba 集成更好

十二、思考与练习

思考题

  1. 基础题:熔断器的三种状态(CLOSED、OPEN、HALF_OPEN)分别表示什么?状态转换的触发条件是什么?

  2. 进阶题:Sentinel 的三种熔断策略(慢调用比例、异常比例、异常数)分别适合什么场景?请举例说明。

  3. 实战题:设计一个电商系统的熔断降级方案,针对商品详情、下单支付、物流查询三个核心场景,说明各自的熔断配置和降级策略。

编程练习

练习:实现一个支持自定义熔断策略的熔断器框架,要求:

  • 支持基于失败率、基于响应时间两种熔断策略
  • 提供注解方式配置熔断规则
  • 支持动态调整熔断参数(如阈值、窗口大小)
  • 提供熔断事件监听和指标上报接口

提示:参考 Resilience4j 的设计,使用装饰器模式实现熔断逻辑。

章节关联

  • 前置章节:《限流算法详解》- 学习请求限流策略
  • 后续章节:《服务监控详解》- 学习熔断器的监控指标采集
  • 扩展阅读:《Release It!》防错设计模式

📝 下一章预告

下一章将学习服务监控详解,探讨如何通过指标采集、链路追踪、日志聚合等手段,构建全方位的服务可观测性体系。


本章完