美文网首页
spring cloud微服务架构(四):Hystrix的使用之

spring cloud微服务架构(四):Hystrix的使用之

作者: mxjsxz | 来源:发表于2018-08-03 16:51 被阅读0次

    第二篇文章中提到的熔断机制,是Hystrix解决“雪崩”的方式之一,本文中内容:

    1. 熔断器的基本原理
    2. Hystrix对熔断器的实现与使用

    1 熔断器的开启

    熔断器是和上一篇文章中的命令(每一个命令对应一个熔断器,是熔断的最小单元,我也不知道这样理解对不对...)相对应的,熔断器同样是使用在客户端。

    一个命令的熔断器的开启,需要满足下面两个条件(默认情况下):

    1. 该命令10秒内超过20次请求
    2. 满足第一个条件的情况下,如果请求的错误百分比大于50%,则打开熔断器

    下面通过实验来证明。

    创建一个spring boot项目,pom依赖如下:

    <dependencies>
            <dependency>
                <groupId>com.netflix.hystrix</groupId>
                <artifactId>hystrix-core</artifactId>
                <version>1.5.12</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <version>1.7.25</version>
                <artifactId>slf4j-log4j12</artifactId>
            </dependency>
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.2</version>
            </dependency>
        </dependencies>
    

    下面创建一个调用服务的命令,在这个命令中设置了超时的时间为500ms,设置了一个是否超时标志isTimeout,使用该标志控制命令的执行是否超时,如下:

    static class TestCommand extends HystrixCommand<String> {
            
            private boolean isTimeout;
            
            public TestCommand(boolean isTimeout) {
                super(Setter.withGroupKey(
                        HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                        .andCommandPropertiesDefaults(
                                HystrixCommandProperties.Setter()
                                        .withExecutionTimeoutInMilliseconds(500)));
                this.isTimeout = isTimeout;
            }
    
            @Override
            protected String run() throws Exception {
                if(isTimeout) {
                    Thread.sleep(800);
                } else {
                    Thread.sleep(200);
                }           
                return "";
            }
    
            @Override
            protected String getFallback() {
                return "fallback";
            }
        }
    

    可以通过 netflix.config.ConfigurationManager 配置类来将第一个条件的20次改为3次,这样更容易测试。然后同一个命令调用10次(并且在10秒内)

    public static void main(String[] args) throws Exception {
            // 10秒内大于3次请求,满足第一个条件
            ConfigurationManager
                    .getConfigInstance()
                    .setProperty(
                            "hystrix.command.default.circuitBreaker.requestVolumeThreshold",
                            3);
            boolean isTimeout = true;
            for(int i = 0; i < 10; i++) {
                TestCommand c = new TestCommand(isTimeout);
                c.execute();
                HealthCounts hc = c.getMetrics().getHealthCounts();
                System.out.println("断路器状态:" + c.isCircuitBreakerOpen() + ", 
                请求数量:" + hc.getTotalRequests());
                //if(c.isCircuitBreakerOpen()) {
                    //isTimeout = false;
                    //System.out.println("============  断路器打开了,等待休眠期结束");
                    //Thread.sleep(6000);
                //}
            }
        }
    

    下面来看下执行的结果,10秒内请求次数3次满足第一个条件;3次皆为失败,则熔断器打开。

    断路器状态:false, 请求数量:0
    断路器状态:false, 请求数量:1
    断路器状态:false, 请求数量:2
    断路器状态:true, 请求数量:3
    断路器状态:true, 请求数量:3
    断路器状态:true, 请求数量:3
    断路器状态:true, 请求数量:3
    断路器状态:true, 请求数量:3
    断路器状态:true, 请求数量:3
    断路器状态:true, 请求数量:3
    

    2 熔断器的关闭

    该命令的熔断器打开后,<font color='red'>则该命令默认会有5秒的睡眠时间,在这段时间内,之后的请求直接执行回退方法;5秒之后,会尝试执行一次命令,如果成功则关闭熔断器;否则,熔断器继续打开。</font>

    将注释掉的代码是放开,

    if(c.isCircuitBreakerOpen()) {
        isTimeout = false;
        System.out.println("============  断路器打开了,
        等待休眠期结束");
        Thread.sleep(6000);
    }
    

    查看执行结果:

    断路器状态:false, 请求数量:0
    断路器状态:false, 请求数量:1
    断路器状态:false, 请求数量:2
    断路器状态:true, 请求数量:3
    ============  断路器打开了,等待休眠期结束
    断路器状态:false, 请求数量:0
    断路器状态:false, 请求数量:0
    断路器状态:false, 请求数量:0
    断路器状态:false, 请求数量:3
    断路器状态:false, 请求数量:3
    断路器状态:false, 请求数量:5
    

    断路器关闭之后,请求数量感觉有点问题,还需要深入理解?

    3 线程池隔离

    在Hystrix执行的流程中,除了要经过熔断器外,还需要过一关:执行命令的线程池或者信号量是否满载。如果满载,命令就不会执行,直接出发回退逻辑。

    线程池针对的最小单元也是命令

    创建一个spring boot项目,pom文件内容和上一文相同。首先创建我们调用服务的命令:

    public class MyCommand extends HystrixCommand<String> {
        
        private int index;
    
        public MyCommand(int index) {
            super(Setter.withGroupKey(
            HystrixCommandGroupKey.Factory
            .asKey("TestGroupKey")));
            this.index = index;
        }
    
        @Override
        protected String run() throws Exception {
            Thread.sleep(500);
            System.out.println("执行方法,当前索引:" 
            + index);
            return "";
        }
    
        @Override
        protected String getFallback() {
            + index);
            return "";
        }
    }
    

    首先将线程次并发数量改为4次,然后通过queue方法异步执行命令。4次执行命令成功,2次执行了回退方法。

    public class ThreadMain {
    
        public static void main(String[] args) throws Exception {
            ConfigurationManager.getConfigInstance().
            setProperty(default.coreSize, 4);
            for(int i = 0; i < 6; i++) {
                MyCommand c = new MyCommand(i);
                c.queue();
            }
            Thread.sleep(5000);
        }
    
    }
    
    执行回退,当前索引:4
    执行回退,当前索引:5
    执行方法,当前索引:2
    执行方法,当前索引:0
    执行方法,当前索引:1
    执行方法,当前索引:3
    

    4 信号量隔离

    Hystrix默认是线程池隔离。信号量隔离就是每个命令的并发执行数量,当并发数高于阈值时,就不再执行命令。

    public class SemaphoreMain {
    
        public static void main(String[] args) throws Exception {
            ConfigurationManager
            .getConfigInstance().setProperty(
                    "hystrix.command.default.
                    execution.isolation.strategy", ExecutionIsolationStrategy.SEMAPHORE);
    .getConfigInstance().setProperty(
                    "hystrix.command.default
                    .execution.isolation.semaphore.maxConcurrentRequests", 3);
            for(int i = 0; i < 6; i++) {
                final int index = i;
                Thread t = new Thread() {
                    public void run() {
                        MyCommand c = new MyCommand(index);
                        c.execute();
                    }
                };
                t.start();
            }
            Thread.sleep(5000);
        }
    
    }
    
    执行回退,当前索引:3
    执行回退,当前索引:5
    执行回退,当前索引:0
    执行方法,当前索引:2
    执行方法,当前索引:4
    执行方法,当前索引:1
    

    相关文章

      网友评论

          本文标题:spring cloud微服务架构(四):Hystrix的使用之

          本文链接:https://www.haomeiwen.com/subject/gxkuvftx.html