spring cloud微服務架構(四):Hystrix的使用之熔斷與隔離機制

第二篇文章中提到的熔斷機制,是Hystrix解決“雪崩”的方式之一,本文中內(nèi)容:

  1. 熔斷器的基本原理
  2. Hystrix對熔斷器的實現(xiàn)與使用

1 熔斷器的開啟

熔斷器是和上一篇文章中的命令(每一個命令對應一個熔斷器,是熔斷的最小單元,我也不知道這樣理解對不對...)相對應的,熔斷器同樣是使用在客戶端。

一個命令的熔斷器的開啟,需要滿足下面兩個條件(默認情況下):

  1. 該命令10秒內(nèi)超過20次請求
  2. 滿足第一個條件的情況下,如果請求的錯誤百分比大于50%,則打開熔斷器

下面通過實驗來證明。

創(chuàng)建一個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>

下面創(chuàng)建一個調(diào)用服務的命令,在這個命令中設置了超時的時間為500ms,設置了一個是否超時標志isTimeout,使用該標志控制命令的執(zhí)行是否超時,如下:

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次,這樣更容易測試。然后同一個命令調(diào)用10次(并且在10秒內(nèi))

public static void main(String[] args) throws Exception {
        // 10秒內(nèi)大于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("斷路器狀態(tài):" + c.isCircuitBreakerOpen() + ", 
            請求數(shù)量:" + hc.getTotalRequests());
            //if(c.isCircuitBreakerOpen()) {
                //isTimeout = false;
                //System.out.println("============  斷路器打開了,等待休眠期結束");
                //Thread.sleep(6000);
            //}
        }
    }

下面來看下執(zhí)行的結果,10秒內(nèi)請求次數(shù)3次滿足第一個條件;3次皆為失敗,則熔斷器打開。

斷路器狀態(tài):false, 請求數(shù)量:0
斷路器狀態(tài):false, 請求數(shù)量:1
斷路器狀態(tài):false, 請求數(shù)量:2
斷路器狀態(tài):true, 請求數(shù)量:3
斷路器狀態(tài):true, 請求數(shù)量:3
斷路器狀態(tài):true, 請求數(shù)量:3
斷路器狀態(tài):true, 請求數(shù)量:3
斷路器狀態(tài):true, 請求數(shù)量:3
斷路器狀態(tài):true, 請求數(shù)量:3
斷路器狀態(tài):true, 請求數(shù)量:3

2 熔斷器的關閉

該命令的熔斷器打開后,<font color='red'>則該命令默認會有5秒的睡眠時間,在這段時間內(nèi),之后的請求直接執(zhí)行回退方法;5秒之后,會嘗試執(zhí)行一次命令,如果成功則關閉熔斷器;否則,熔斷器繼續(xù)打開。</font>

將注釋掉的代碼是放開,

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

查看執(zhí)行結果:

斷路器狀態(tài):false, 請求數(shù)量:0
斷路器狀態(tài):false, 請求數(shù)量:1
斷路器狀態(tài):false, 請求數(shù)量:2
斷路器狀態(tài):true, 請求數(shù)量:3
============  斷路器打開了,等待休眠期結束
斷路器狀態(tài):false, 請求數(shù)量:0
斷路器狀態(tài):false, 請求數(shù)量:0
斷路器狀態(tài):false, 請求數(shù)量:0
斷路器狀態(tài):false, 請求數(shù)量:3
斷路器狀態(tài):false, 請求數(shù)量:3
斷路器狀態(tài):false, 請求數(shù)量:5

斷路器關閉之后,請求數(shù)量感覺有點問題,還需要深入理解?

3 線程池隔離

在Hystrix執(zhí)行的流程中,除了要經(jīng)過熔斷器外,還需要過一關:執(zhí)行命令的線程池或者信號量是否滿載。如果滿載,命令就不會執(zhí)行,直接出發(fā)回退邏輯。

線程池針對的最小單元也是命令

創(chuàng)建一個spring boot項目,pom文件內(nèi)容和上一文相同。首先創(chuàng)建我們調(diào)用服務的命令:

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("執(zhí)行方法,當前索引:" 
        + index);
        return "";
    }

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

首先將線程次并發(fā)數(shù)量改為4次,然后通過queue方法異步執(zhí)行命令。4次執(zhí)行命令成功,2次執(zhí)行了回退方法。

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);
    }

}
執(zhí)行回退,當前索引:4
執(zhí)行回退,當前索引:5
執(zhí)行方法,當前索引:2
執(zhí)行方法,當前索引:0
執(zhí)行方法,當前索引:1
執(zhí)行方法,當前索引:3

4 信號量隔離

Hystrix默認是線程池隔離。信號量隔離就是每個命令的并發(fā)執(zhí)行數(shù)量,當并發(fā)數(shù)高于閾值時,就不再執(zhí)行命令。

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);
    }

}
執(zhí)行回退,當前索引:3
執(zhí)行回退,當前索引:5
執(zhí)行回退,當前索引:0
執(zhí)行方法,當前索引:2
執(zhí)行方法,當前索引:4
執(zhí)行方法,當前索引:1
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容