Hystrix的断路器配置+源码解析

王守钰 2020-05-16 20:05:42

Hystrix的断路器配置

通过设置circuitBreaker.enabled将断路器开启,设置circuitBreaker.errorThresholdPercentage为50%,也就是说如果10秒内有100个请求,其中50个请求发生了异常,那么就说明错误率超过了50%,断路器开启。设置circuitBreaker.requestVolumeThreshold为3,也就是说10秒内至少要有3个请求。

断路器代码

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;

/**
 * @author 王守钰
 * @program quan
 * @date 2020年05月16日 18:32
 * @description: 熔断配置
 */
public class HystrixBreakerCommand extends HystrixCommand<String> {

    public static final Integer DEFAULT_TIMEOUT = 3 * 1000;

    private Integer id;

    protected HystrixBreakerCommand(Integer id) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))
                .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.defaultSetter()
                        .withCoreSize(100))
                .andCommandPropertiesDefaults(HystrixCommandProperties.defaultSetter()
                        .withCircuitBreakerEnabled(true)
                        .withCircuitBreakerErrorThresholdPercentage(50)
                        .withCircuitBreakerRequestVolumeThreshold(3)
                        .withExecutionTimeoutInMilliseconds(DEFAULT_TIMEOUT)
                ));
        this.id = id;
    }

    @Override
    protected String run() throws Exception {
        if(id % 2 == 0){
            Thread.sleep(DEFAULT_TIMEOUT);
        }
        return "success";
    }

    @Override
    protected String getFallback() {
        return "timeout";
    }
}

测试代码

@Test
public void testBreaker(){
    for (int i = 0; i < 30; i++){
        HystrixBreakerCommand command = new HystrixBreakerCommand(i);
        String result = command.execute();
        log.info("{}, execute id:{} CircuitBreakerStatus:{} result:{}", Thread.currentThread().getName(), i, command.isCircuitBreakerOpen(), result);
    }
    while (true){

    }
}

执行结果

20:23:20.555 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:0 CircuitBreakerStatus:false result:timeout
20:23:20.560 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:1 CircuitBreakerStatus:false result:success
20:23:23.564 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:2 CircuitBreakerStatus:false result:timeout
20:23:23.568 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:3 CircuitBreakerStatus:false result:success
20:23:26.572 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:4 CircuitBreakerStatus:true result:timeout
20:23:26.573 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:5 CircuitBreakerStatus:true result:timeout
20:23:26.573 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:6 CircuitBreakerStatus:true result:timeout
20:23:26.574 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:7 CircuitBreakerStatus:true result:timeout
20:23:26.575 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:8 CircuitBreakerStatus:true result:timeout
20:23:26.575 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:9 CircuitBreakerStatus:true result:timeout
20:23:26.576 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:10 CircuitBreakerStatus:true result:timeout
20:23:26.576 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:11 CircuitBreakerStatus:true result:timeout
20:23:26.577 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:12 CircuitBreakerStatus:true result:timeout
20:23:26.578 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:13 CircuitBreakerStatus:true result:timeout
20:23:26.578 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:14 CircuitBreakerStatus:true result:timeout
20:23:26.578 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:15 CircuitBreakerStatus:true result:timeout
20:23:26.579 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:16 CircuitBreakerStatus:true result:timeout
20:23:26.579 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:17 CircuitBreakerStatus:true result:timeout
20:23:26.579 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:18 CircuitBreakerStatus:true result:timeout
20:23:26.580 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:19 CircuitBreakerStatus:true result:timeout
20:23:26.580 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:20 CircuitBreakerStatus:true result:timeout
20:23:26.580 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:21 CircuitBreakerStatus:true result:timeout
20:23:26.581 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:22 CircuitBreakerStatus:true result:timeout
20:23:26.581 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:23 CircuitBreakerStatus:true result:timeout
20:23:26.581 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:24 CircuitBreakerStatus:true result:timeout
20:23:26.582 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:25 CircuitBreakerStatus:true result:timeout
20:23:26.582 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:26 CircuitBreakerStatus:true result:timeout
20:23:26.582 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:27 CircuitBreakerStatus:true result:timeout
20:23:26.583 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:28 CircuitBreakerStatus:true result:timeout
20:23:26.583 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:29 CircuitBreakerStatus:true result:timeout

设置断路器重试时间

通过设置circuitBreaker.sleepWindowInMilliseconds来进行控制断路器重试时间,让熔断器释放一部分流量过去试探。

protected HystrixBreakerCommand(Integer id) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))
            .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.defaultSetter()
                    .withCoreSize(100))
            .andCommandPropertiesDefaults(HystrixCommandProperties.defaultSetter()
                    .withCircuitBreakerEnabled(true)
                    .withCircuitBreakerErrorThresholdPercentage(50)
                    .withCircuitBreakerRequestVolumeThreshold(3)
                    .withCircuitBreakerSleepWindowInMilliseconds(500)
                    .withExecutionTimeoutInMilliseconds(DEFAULT_TIMEOUT)
            ));
    this.id = id;
}

测试执行

@Test
public void testBreaker(){
    for (int i = 0; i < 30; i++){
        HystrixBreakerCommand command = new HystrixBreakerCommand(i);
        String result = command.execute();
        log.info("{}, execute id:{} CircuitBreakerStatus:{} result:{}", Thread.currentThread().getName(), i, command.isCircuitBreakerOpen(), result);
    }
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    for (int i = 0; i < 3; i++){
        HystrixBreakerCommand command = new HystrixBreakerCommand(i);
        String result = command.execute();
        log.info("{}, execute id:{} CircuitBreakerStatus:{} result:{}", Thread.currentThread().getName(), i, command.isCircuitBreakerOpen(), result);
    }
    while (true){

    }
}

执行结果

20:33:11.078 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:0 CircuitBreakerStatus:false result:timeout
20:33:11.081 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:1 CircuitBreakerStatus:false result:success
20:33:14.085 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:2 CircuitBreakerStatus:false result:timeout
20:33:14.088 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:3 CircuitBreakerStatus:false result:success
20:33:17.092 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:4 CircuitBreakerStatus:true result:timeout
20:33:17.093 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:5 CircuitBreakerStatus:true result:timeout
20:33:17.094 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:6 CircuitBreakerStatus:true result:timeout
20:33:17.094 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:7 CircuitBreakerStatus:true result:timeout
20:33:17.095 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:8 CircuitBreakerStatus:true result:timeout
20:33:17.095 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:9 CircuitBreakerStatus:true result:timeout
20:33:17.096 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:10 CircuitBreakerStatus:true result:timeout
20:33:17.096 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:11 CircuitBreakerStatus:true result:timeout
20:33:17.097 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:12 CircuitBreakerStatus:true result:timeout
20:33:17.097 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:13 CircuitBreakerStatus:true result:timeout
20:33:17.098 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:14 CircuitBreakerStatus:true result:timeout
20:33:17.098 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:15 CircuitBreakerStatus:true result:timeout
20:33:17.098 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:16 CircuitBreakerStatus:true result:timeout
20:33:17.099 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:17 CircuitBreakerStatus:true result:timeout
20:33:17.099 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:18 CircuitBreakerStatus:true result:timeout
20:33:17.099 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:19 CircuitBreakerStatus:true result:timeout
20:33:17.100 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:20 CircuitBreakerStatus:true result:timeout
20:33:17.100 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:21 CircuitBreakerStatus:true result:timeout
20:33:17.100 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:22 CircuitBreakerStatus:true result:timeout
20:33:17.101 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:23 CircuitBreakerStatus:true result:timeout
20:33:17.101 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:24 CircuitBreakerStatus:true result:timeout
20:33:17.101 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:25 CircuitBreakerStatus:true result:timeout
20:33:17.102 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:26 CircuitBreakerStatus:true result:timeout
20:33:17.102 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:27 CircuitBreakerStatus:true result:timeout
20:33:17.103 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:28 CircuitBreakerStatus:true result:timeout
20:33:17.103 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:29 CircuitBreakerStatus:true result:timeout
20:33:20.615 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:0 CircuitBreakerStatus:true result:timeout
20:33:20.632 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:1 CircuitBreakerStatus:false result:success
20:33:23.638 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:2 CircuitBreakerStatus:false result:timeout

熔断器强制关闭或开启

强制关闭熔断器

protected HystrixBreakerCommand(Integer id) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))
            .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.defaultSetter()
                    .withCoreSize(100))
            .andCommandPropertiesDefaults(HystrixCommandProperties.defaultSetter()
                    .withCircuitBreakerEnabled(true)
                    .withCircuitBreakerErrorThresholdPercentage(50)
                    .withCircuitBreakerRequestVolumeThreshold(3)
                    .withCircuitBreakerSleepWindowInMilliseconds(500)
                    .withCircuitBreakerForceClosed(true)
                    .withExecutionTimeoutInMilliseconds(DEFAULT_TIMEOUT)
            ));
    this.id = id;
}

执行结果

20:42:11.540 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:0 CircuitBreakerStatus:false result:timeout
20:42:11.556 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:1 CircuitBreakerStatus:false result:success
20:42:14.562 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:2 CircuitBreakerStatus:false result:timeout
20:42:14.567 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:3 CircuitBreakerStatus:false result:success
20:42:17.588 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:4 CircuitBreakerStatus:false result:timeout
20:42:17.597 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:5 CircuitBreakerStatus:false result:success
20:42:20.603 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:6 CircuitBreakerStatus:false result:timeout
20:42:20.605 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:7 CircuitBreakerStatus:false result:success
20:42:23.608 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:8 CircuitBreakerStatus:false result:timeout
20:42:23.611 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:9 CircuitBreakerStatus:false result:success
20:42:26.613 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:10 CircuitBreakerStatus:false result:timeout
20:42:26.615 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:11 CircuitBreakerStatus:false result:success
20:42:29.619 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:12 CircuitBreakerStatus:false result:timeout
20:42:29.630 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:13 CircuitBreakerStatus:false result:success
20:42:32.632 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:14 CircuitBreakerStatus:false result:timeout
20:42:32.633 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:15 CircuitBreakerStatus:false result:success
20:42:35.640 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:16 CircuitBreakerStatus:false result:timeout
20:42:35.642 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:17 CircuitBreakerStatus:false result:success
20:42:38.644 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:18 CircuitBreakerStatus:false result:timeout
20:42:38.646 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:19 CircuitBreakerStatus:false result:success
20:42:41.647 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:20 CircuitBreakerStatus:false result:timeout
20:42:41.654 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:21 CircuitBreakerStatus:false result:success
20:42:44.656 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:22 CircuitBreakerStatus:false result:timeout
20:42:44.658 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:23 CircuitBreakerStatus:false result:success
20:42:47.663 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:24 CircuitBreakerStatus:false result:timeout
20:42:47.666 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:25 CircuitBreakerStatus:false result:success
20:42:50.669 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:26 CircuitBreakerStatus:false result:timeout
20:42:50.670 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:27 CircuitBreakerStatus:false result:success
20:42:53.673 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:28 CircuitBreakerStatus:false result:timeout
20:42:53.677 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:29 CircuitBreakerStatus:false result:success

熔断器强制开启

protected HystrixBreakerCommand(Integer id) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))
            .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.defaultSetter()
                    .withCoreSize(100))
            .andCommandPropertiesDefaults(HystrixCommandProperties.defaultSetter()
                    .withCircuitBreakerEnabled(true)
                    .withCircuitBreakerErrorThresholdPercentage(50)
                    .withCircuitBreakerRequestVolumeThreshold(3)
                    .withCircuitBreakerSleepWindowInMilliseconds(500)
                    .withCircuitBreakerForceClosed(true)
                    .withCircuitBreakerForceOpen(true)
                    .withExecutionTimeoutInMilliseconds(DEFAULT_TIMEOUT)
            ));
    this.id = id;
}

执行结果

20:43:45.000 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:0 CircuitBreakerStatus:true result:timeout
20:43:45.002 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:1 CircuitBreakerStatus:true result:timeout
20:43:45.003 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:2 CircuitBreakerStatus:true result:timeout
20:43:45.005 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:3 CircuitBreakerStatus:true result:timeout
20:43:45.006 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:4 CircuitBreakerStatus:true result:timeout
20:43:45.007 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:5 CircuitBreakerStatus:true result:timeout
20:43:45.009 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:6 CircuitBreakerStatus:true result:timeout
20:43:45.010 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:7 CircuitBreakerStatus:true result:timeout
20:43:45.010 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:8 CircuitBreakerStatus:true result:timeout
20:43:45.011 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:9 CircuitBreakerStatus:true result:timeout
20:43:45.012 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:10 CircuitBreakerStatus:true result:timeout
20:43:45.012 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:11 CircuitBreakerStatus:true result:timeout
20:43:45.013 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:12 CircuitBreakerStatus:true result:timeout
20:43:45.014 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:13 CircuitBreakerStatus:true result:timeout
20:43:45.015 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:14 CircuitBreakerStatus:true result:timeout
20:43:45.016 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:15 CircuitBreakerStatus:true result:timeout
20:43:45.017 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:16 CircuitBreakerStatus:true result:timeout
20:43:45.024 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:17 CircuitBreakerStatus:true result:timeout
20:43:45.027 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:18 CircuitBreakerStatus:true result:timeout
20:43:45.030 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:19 CircuitBreakerStatus:true result:timeout
20:43:45.031 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:20 CircuitBreakerStatus:true result:timeout
20:43:45.032 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:21 CircuitBreakerStatus:true result:timeout
20:43:45.032 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:22 CircuitBreakerStatus:true result:timeout
20:43:45.033 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:23 CircuitBreakerStatus:true result:timeout
20:43:45.033 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:24 CircuitBreakerStatus:true result:timeout
20:43:45.034 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:25 CircuitBreakerStatus:true result:timeout
20:43:45.035 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:26 CircuitBreakerStatus:true result:timeout
20:43:45.049 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:27 CircuitBreakerStatus:true result:timeout
20:43:45.050 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:28 CircuitBreakerStatus:true result:timeout
20:43:45.052 [main] INFO com.wangshouyu.hystrix.HystrixBreakerTest - main, execute id:29 CircuitBreakerStatus:true result:timeout

从上面的执行结果可以看出ForceOpen的优先级要高于ForceClosed,两者同时添加时,会执行ForceOpen。

源码解析

public interface HystrixCircuitBreaker {

    // 请求是否允许通过
    public boolean allowRequest();

    // 是否开启断路器
    public boolean isOpen();

    // 标记断路器状态为false
    /* package */void markSuccess();

    // 断路器工程
    public static class Factory {
        // 断路器Map
        private static ConcurrentHashMap<String, HystrixCircuitBreaker> circuitBreakersByCommand = new ConcurrentHashMap<String, HystrixCircuitBreaker>();

        // 获取实例
        public static HystrixCircuitBreaker getInstance(HystrixCommandKey key, HystrixCommandGroupKey group, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
            // 获取缓存实例
            HystrixCircuitBreaker previouslyCached = circuitBreakersByCommand.get(key.name());
            if (previouslyCached != null) {
                return previouslyCached;
            }

            // 创建一个断路器并放入缓存
            HystrixCircuitBreaker cbForCommand = circuitBreakersByCommand.putIfAbsent(key.name(), new HystrixCircuitBreakerImpl(key, group, properties, metrics));
            if (cbForCommand == null) {
                // 返回当前断路器
                return circuitBreakersByCommand.get(key.name());
            } else {
                // 并发创建直接返回当前断路器
                return cbForCommand;
            }
        }

         // 获取断路器实例
        public static HystrixCircuitBreaker getInstance(HystrixCommandKey key) {
            return circuitBreakersByCommand.get(key.name());
        }

        // 重置断路器
        /* package */static void reset() {
            circuitBreakersByCommand.clear();
        }
    }

    // 断路器实现类
    /* package */static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
        private final HystrixCommandProperties properties;
        private final HystrixCommandMetrics metrics;

        // 断路器是否开启
        private AtomicBoolean circuitOpen = new AtomicBoolean(false);

        // 断路器开启或者最后一次尝试执行时间
        private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();

        protected HystrixCircuitBreakerImpl(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
            this.properties = properties;
            this.metrics = metrics;
        }
        
        // 标记关闭
        public void markSuccess() {
            // 判断断路器是否开启
            if (circuitOpen.get()) {
                // cas设置断路器为关闭状态
                if (circuitOpen.compareAndSet(true, false)) {
                    // 同步stream
                    metrics.resetStream();
                }
            }
        }

        // 是否允许访问
        @Override
        public boolean allowRequest() {
            // 判断是否强制开启断路器,circuitBreaker.forceOpen
            if (properties.circuitBreakerForceOpen().get()) {
                return false;
            }
            // 判断是否强制关闭断路器,circuitBreaker.forceClosed
            if (properties.circuitBreakerForceClosed().get()) {
                isOpen();
                return true;
            }
            // 断路器关闭或者允许访问测试
            return !isOpen() || allowSingleTest();
        }

        // 尝试放过去一次请求
        public boolean allowSingleTest() {
            // 获取最后一次断路器开启时间
            long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();
            // 断路器开启,并且当前时间>最后一次断路器开启时间+熔断间隔请求时间,放行一次
            if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {
                // cas设置设置最后一次放行时间
                if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {
                    return true;
                }
            }
            return false;
        }

        // 断路器是否开启
        @Override
        public boolean isOpen() {
            // 断路器开启直接返回true
            if (circuitOpen.get()) {
                return true;
            }

            // 健康检查
            HealthCounts health = metrics.getHealthCounts();

            // 时间窗口请求数量:circuitBreaker.requestVolumeThreshold
            // 如果流量小于时间窗口请求数量,直接返回false。
            // check if we are past the statisticalWindowVolumeThreshold
            if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {
                return false;
            }

            // 失败率阈值:circuitBreaker.errorThresholdPercentage
            // 判断错误率是否小于失败率阈值。
            if (health.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {
                return false;
            } else {
                // 大于失败阈值,cas修改断路器状态为true
                if (circuitOpen.compareAndSet(false, true)) {
                    // 修改断路器最后开启时间
                    circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
                    return true;
                } else {
                    // cas设置失败,直接返回true
                    return true;
                }
            }
        }

    }

    // 没有断路器,设置开启为false
    /* package */static class NoOpCircuitBreaker implements HystrixCircuitBreaker {

        @Override
        public boolean allowRequest() {
            return true;
        }

        @Override
        public boolean isOpen() {
            return false;
        }

        @Override
        public void markSuccess() {

        }

    }

}