核心概念

Hystrix是Netflix开源的容错库,用于处理分布式系统中的延迟和故障,通过熔断、降级、隔离、限流等机制防止服务雪崩效应。

注意:Hystrix已于2018年停止维护,官方推荐使用Resilience4jAlibaba Sentinel替代。

服务雪崩效应

服务A → 服务B → 服务C → 服务D(故障)
   ↑        ↑        ↑
  请求堆积  请求堆积  请求堆积
   ↓        ↓        ↓
  线程耗尽 线程耗尽  线程耗尽
   ↓        ↓        ↓
  服务崩溃  服务崩溃  服务崩溃

Hystrix解决方案

  • 熔断器(Circuit Breaker):快速失败,防止请求堆积
  • 服务降级(Fallback):提供备用响应
  • 资源隔离(Isolation):线程池/信号量隔离
  • 请求缓存(Request Cache):减少重复请求

熔断器工作原理

三种状态

         ┌─────────────┐
  失败达到阈值  │   CLOSED    │ 正常状态
    ├──────> │  (闭合)      │ 请求正常通过
    │        └──────┬──────┘
    │               │
    │               │ 失败率过高
    │               ↓
    │        ┌─────────────┐
    │        │    OPEN     │ 熔断状态
    │        │  (打开)      │ 快速失败
    │        └──────┬──────┘
    │               │
    │               │ 等待一段时间
    │               ↓
    │        ┌─────────────┐
    │        │ HALF_OPEN   │ 半开状态
    └────── │  (半开)      │ 尝试恢复
             └─────────────┘
                   │
          成功则CLOSED
          失败则OPEN

状态转换逻辑

  1. CLOSED(闭合)
    • 初始状态,请求正常通过
    • 记录成功/失败次数
    • 失败率达到阈值 → OPEN
  2. OPEN(打开)
    • 拒绝所有请求,直接返回降级结果
    • 等待窗口期(默认5秒)
    • 窗口期结束 → HALF_OPEN
  3. HALF_OPEN(半开)
    • 允许少量请求通过
    • 请求成功 → CLOSED
    • 请求失败 → OPEN

核心使用方式

1. 基本使用

<!-- 依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
// 启动类
@SpringBootApplication
@EnableCircuitBreaker  // 或 @EnableHystrix
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 服务类
@Service
public class UserService {
    @HystrixCommand(
        fallbackMethod = "getUserFallback",  // 降级方法
        commandKey = "getUserById",  // 命令键
        groupKey = "UserService",  // 分组键
        threadPoolKey = "UserServicePool"  // 线程池键
    )
    public User getUserById(Long id) {
        // 模拟远程调用
        String url = "http://user-service/api/users/" + id;
        return restTemplate.getForObject(url, User.class);
    }
    
    // 降级方法(参数和返回值必须与原方法一致)
    public User getUserFallback(Long id) {
        return new User(id, "降级用户", "fallback@example.com");
    }
    
    // 支持获取异常信息的降级方法
    public User getUserFallback(Long id, Throwable throwable) {
        log.error("调用失败: {}", throwable.getMessage());
        return new User(id, "降级用户", "fallback@example.com");
    }
}

2. 详细配置

@HystrixCommand(
    commandProperties = {
        // ========== 熔断配置 ==========
        // 是否开启熔断器
        @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
        // 熔断触发最小请求数(10秒内至少20个请求才计算熔断)
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
        // 熔断错误比例阈值(错误率达到50%触发熔断)
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
        // 熔断后休眠时间(5秒后进入半开状态)
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
        
        // ========== 超时配置 ==========
        // 是否开启超时
        @HystrixProperty(name = "execution.timeout.enabled", value = "true"),
        // 超时时间(3秒)
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
        // 超时是否中断线程
        @HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
        
        // ========== 隔离策略 ==========
        // 隔离策略:THREAD(线程池)或 SEMAPHORE(信号量)
        @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
        // 信号量最大并发数(使用SEMAPHORE时有效)
        @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
        
        // ========== 降级配置 ==========
        // 降级信号量最大并发数
        @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "20"),
        
        // ========== 统计配置 ==========
        // 统计滚动窗口时间(10秒)
        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000"),
        // 统计窗口桶数量(10个桶,每个1秒)
        @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10")
    },
    threadPoolProperties = {
        // 核心线程数
        @HystrixProperty(name = "coreSize", value = "10"),
        // 最大线程数
        @HystrixProperty(name = "maximumSize", value = "20"),
        // 是否允许最大线程数生效
        @HystrixProperty(name = "allowMaximumSizeToDivergeFromCoreSize", value = "true"),
        // 队列大小(-1使用SynchronousQueue,0使用LinkedBlockingQueue)
        @HystrixProperty(name = "maxQueueSize", value = "100"),
        // 队列拒绝阈值
        @HystrixProperty(name = "queueSizeRejectionThreshold", value = "80"),
        // 线程存活时间
        @HystrixProperty(name = "keepAliveTimeMinutes", value = "2")
    }
)
public User getUserById(Long id) {
    // ...
}

3. 配置文件方式

hystrix:
  command:
    default:  # 全局配置
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000  # 超时时间
      circuitBreaker:
        enabled: true
        requestVolumeThreshold: 20  # 最小请求数
        errorThresholdPercentage: 50  # 错误率阈值
        sleepWindowInMilliseconds: 5000  # 休眠窗口
    getUserById:  # 针对特定命令
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000
  threadpool:
    UserServicePool:  # 线程池配置
      coreSize: 10
      maximumSize: 20
      maxQueueSize: 100

资源隔离策略

1. 线程池隔离(THREAD)- 默认推荐

原理:每个服务使用独立线程池

┌──────────────────────────────────┐
│       Tomcat线程池 (200)          │
├──────────────────────────────────┤
│  UserService线程池 (10)          │
│  OrderService线程池 (20)         │
│  PaymentService线程池 (15)       │
└──────────────────────────────────┘

优点

  • 完全隔离,某个服务故障不影响其他服务
  • 支持超时,可以强制中断
  • 异步执行,释放容器线程

缺点

  • 线程切换开销
  • 内存占用较高

适用场景

  • 依赖网络调用(HTTP、RPC)
  • 执行时间不确定
  • 需要强隔离的场景
@HystrixCommand(
    commandProperties = {
        @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD")
    },
    threadPoolKey = "UserServicePool",
    threadPoolProperties = {
        @HystrixProperty(name = "coreSize", value = "10")
    }
)
public User getUserById(Long id) {
    // 在独立线程池中执行
}

2. 信号量隔离(SEMAPHORE)

原理:使用计数器限制并发数,不创建额外线程

请求1 ──┐
请求2 ──┤
请求3 ──┼──> Semaphore(10) ──> 业务逻辑
...    │
请求11 ─┘ (被拒绝)

优点

  • 无线程切换开销
  • 性能更高

缺点

  • 无法超时中断
  • 无法异步执行
  • 隔离性较弱

适用场景

  • 本地计算或内存操作
  • 执行时间可控
  • 性能要求高
@HystrixCommand(
    commandProperties = {
        @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
        @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10")
    }
)
public User getUserFromCache(Long id) {
    // 在调用线程中执行,不创建新线程
    return cache.get(id);
}

熔断器核心源码

1. HystrixCircuitBreaker接口

public interface HystrixCircuitBreaker {
    // 是否允许请求通过
    boolean allowRequest();
    
    // 是否处于熔断状态
    boolean isOpen();
    
    // 尝试关闭熔断器
    void markSuccess();
    
    // 尝试打开熔断器
    void markNonSuccess();
}

2. 核心实现

class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
    // 熔断器状态(AtomicReference保证线程安全)
    private AtomicReference<Status> status = new AtomicReference<>(Status.CLOSED);
    
    // 熔断打开时间
    private AtomicLong circuitOpened = new AtomicLong(-1);
    
    @Override
    public boolean allowRequest() {
        // 强制打开,拒绝所有请求
        if (properties.circuitBreakerForceOpen().get()) {
            return false;
        }
        
        // 强制关闭,允许所有请求
        if (properties.circuitBreakerForceClosed().get()) {
            return true;
        }
        
        // 熔断器打开状态
        if (circuitOpened.get() == -1) {
            return true;  // 初始状态,允许通过
        } else {
            // 判断是否超过休眠窗口期
            if (isAfterSleepWindow()) {
                // 尝试进入半开状态
                if (status.compareAndSet(Status.OPEN, Status.HALF_OPEN)) {
                    return true;  // 允许一个请求通过
                } else {
                    return false;  // 其他请求仍然拒绝
                }
            } else {
                return false;  // 休眠窗口期内,拒绝请求
            }
        }
    }
    
    @Override
    public boolean isOpen() {
        if (circuitOpened.get() == -1) {
            return false;
        }
        
        if (isAfterSleepWindow()) {
            return false;  // 休眠窗口后不算打开状态
        }
        
        return true;
    }
    
    @Override
    public void markSuccess() {
        // 半开状态下请求成功,关闭熔断器
        if (status.compareAndSet(Status.HALF_OPEN, Status.CLOSED)) {
            // 重置统计信息
            metrics.resetStream();
            circuitOpened.set(-1L);
        }
    }
    
    @Override
    public void markNonSuccess() {
        // 半开状态下请求失败,重新打开熔断器
        if (status.compareAndSet(Status.HALF_OPEN, Status.OPEN)) {
            circuitOpened.set(System.currentTimeMillis());
        }
    }
    
    // 判断是否超过休眠窗口
    private boolean isAfterSleepWindow() {
        long circuitOpenTime = circuitOpened.get();
        long currentTime = System.currentTimeMillis();
        long sleepWindowTime = properties.circuitBreakerSleepWindowInMilliseconds().get();
        return currentTime > circuitOpenTime + sleepWindowTime;
    }
    
    // 判断是否达到熔断条件
    private boolean shouldTripCircuit() {
        HealthCounts health = metrics.getHealthCounts();
        
        // 请求数量不足,不熔断
        if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {
            return false;
        }
        
        // 错误率达到阈值,触发熔断
        if (health.getErrorPercentage() >= properties.circuitBreakerErrorThresholdPercentage().get()) {
            return true;
        }
        
        return false;
    }
}

3. 健康统计

class HealthCounts {
    private final long totalCount;  // 总请求数
    private final long errorCount;  // 错误请求数
    private final int errorPercentage;  // 错误率
    
    public boolean isHealthy() {
        return errorPercentage < 50;  // 默认阈值50%
    }
}

// 滑动窗口统计
class RollingNumber {
    // 使用环形数组存储统计数据
    private final BucketCircularArray buckets;
    
    // 10秒滑动窗口,分为10个桶
    // 每个桶统计1秒内的成功、失败、超时、拒绝等指标
}

Dashboard监控

1. 配置Dashboard

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
@SpringBootApplication
@EnableHystrixDashboard
public class DashboardApplication {
    public static void main(String[] args) {
        SpringApplication.run(DashboardApplication.class, args);
    }
}

访问:http://localhost:8080/hystrix

2. 暴露监控端点

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

监控地址:http://localhost:8080/actuator/hystrix.stream

Hystrix vs Sentinel

对比项 Hystrix Sentinel
维护状态 已停更 活跃维护
隔离策略 线程池/信号量 信号量
熔断策略 基于错误率 多种策略(慢调用、错误率、异常比例)
流控规则 不支持 支持(QPS、并发数、关联、链路)
控制台 Hystrix Dashboard Sentinel Dashboard
性能 较好 更好(无线程池开销)
推荐度 不推荐新项目 推荐

Sentinel示例

@Service
public class UserService {
    @SentinelResource(
        value = "getUserById",
        fallback = "getUserFallback",
        blockHandler = "getUserBlockHandler"
    )
    public User getUserById(Long id) {
        // 业务逻辑
    }
    
    // 降级方法(业务异常)
    public User getUserFallback(Long id, Throwable ex) {
        return new User(id, "降级用户");
    }
    
    // 限流方法(被限流/熔断)
    public User getUserBlockHandler(Long id, BlockException ex) {
        return new User(id, "系统繁忙");
    }
}

最佳实践

1. 合理设置超时时间

超时时间 > (重试次数 + 1) × 单次超时时间

例如:Ribbon重试1次,单次超时1秒
Hystrix超时 > 2 × 1000 = 2000ms

2. 降级方法设计

// ❌ 错误:降级方法中调用其他服务
public User getUserFallback(Long id) {
    return orderService.getDefaultUser();  // 可能再次失败
}

// ✅ 正确:返回静态数据或缓存
public User getUserFallback(Long id) {
    return cache.get(id, () -> new User(id, "默认用户"));
}

3. 线程池隔离粒度

// 按服务分组,而非每个方法一个线程池
@HystrixCommand(threadPoolKey = "UserService")  // ✅
@HystrixCommand(threadPoolKey = "getUserById")  // ❌ 过细

面试总结

Hystrix熔断机制核心

  1. 三种状态:CLOSED(闭合)、OPEN(打开)、HALF_OPEN(半开)
  2. 熔断条件:10秒内至少20个请求,且错误率达到50%
  3. 恢复机制:熔断5秒后进入半开状态,尝试放行请求,成功则恢复
  4. 资源隔离:线程池隔离(默认)或信号量隔离

关键配置

  • requestVolumeThreshold:最小请求数(默认20)
  • errorThresholdPercentage:错误率阈值(默认50%)
  • sleepWindowInMilliseconds:休眠窗口(默认5秒)
  • timeoutInMilliseconds:超时时间(默认1秒)

Hystrix已停更,新项目推荐

  • Sentinel(阿里开源,功能更强大)
  • Resilience4j(轻量级,函数式编程风格)

核心价值:通过快速失败服务降级防止服务雪崩,保证系统整体可用性。