spring cloud微服务架构(四):Hystrix的使用之熔断与隔离机制

第二篇文章中提到的熔断机制,是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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容