hystrix熔斷器


在一個具有多服務的應用中,假如由於其中某一個服務出現問題,導致響應速度變慢,或是根本沒有響應返回,會導致它的服務消費者由於長時間的等待,消耗盡線程,進而影響到對其他服務的線程調用,進而會轉變為整個應用的故障。這也被稱之為雪崩效應。

而Hystrix熔斷器,正是用來幫助我們解決這種問題的工具。

Hystrix提供了熔斷、隔離、fallback、cache、監控等功能,能夠在一個或多個服務出現問題的時候保證整個應用依然處於可用狀態。

 

沒有做熔斷處理的應用,出現問題后:

正常情況:                              A→B→C→D

D服務出現了問題:                              A→B→C×D

從而導致C服務無法獲取正確的響應,出現對應的問題:              A→B×C×D

最后導致B服務,甚至A服務都同樣出現問題,由服務不可用變為應用不可用:   A×B×C×D

 

針對於上面的這種情況,在Hystrix中采用了如下的幾種方式進行處理。

1.Hystrix請求超時

用hystrix監控請求的響應時間,如果超過我們設置的時間,將會被判定為請求超時,拋出TimeoutException。

(1)引入Maven依賴

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.2.7.RELEASE</version>
    </dependency>

(2)在properties中進行配置。

關於參數詳解可以參考https://blog.csdn.net/u013889359/article/details/80118884https://blog.csdn.net/tongtong_use/article/details/78611225https://blog.csdn.net/nb7474/article/details/84440822

#超時時間,默認1000,單位ms。
#注意這里配置的default,默認所有的請求服務都被設定為這個值。如果要針對某一個服務,可以將default改為服務名如user,或在請求類中通過注解進行單獨配置 hystrix.command.
default.execution.isolation.thread.timeoutInMilliseconds=1000

(3)在啟動類中添加注解@EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class RoleServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(RoleServerApplication.class, args);
    }

}

(4)在需要被Hystrix控制請求時間的方法上添加注解@HystrixCommand。如果方法沒有被配置這個注解,請求將不會達到指定時間后拋出超時異常。

    @GetMapping("roles/{id}")
    @HystrixCommand
    public String getRole(@PathVariable("id") String id) {
        System.out.println("接收到請求[/roles/" + id + "]");
        return restTemplate.getForObject(rest_url_prefix + "/users/" + id, String.class);
    }

如此完成了一個請求的超時配置,假如方法getRole()對/users/{id}請求的時間超過了一秒沒有得到相應,那么會拋出如下異常:

 

2. 對服務分別配置線程池調用

不同的服務配置了不同的線程池,這樣可以即使向服務A發送的請求都超時,占滿了線程數。但是向服務B發送的請求仍然處於正常狀態,不會受到A服務的干擾。

(1)引入MAVEN依賴

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.2.7.RELEASE</version>
    </dependency>

(2)在properties中進行配置(注意這里配置的都是default,默認適應所有的被@HystrixCommand修飾的方法中的請求,如果需要分別針對不同的服務,替換defalut即可)。

#超時時間,默認1000,單位ms。
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=100000 #線程池核心線程數,最多同時只有2個線程在執行 hystrix.threadpool.default.coreSize=2 #線程池最大隊列數,也可以理解為最多只能添加4個請求進來。包括正在執行的請求。 hystrix.threadpool.default.maxQueueSize=4 #線程池最大線程數。最多只能接收2+3=5個線程數。 hystrix.threadpool.default.maximumSize=3 #隊列拒絕閾值,即使隊列數沒有達到maxQueueSize,也會拒絕接收任務 hystrix.threadpool.default.queueSizeRejectionThreshold=6

(3)在啟動類中添加注解@EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class RoleServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(RoleServerApplication.class, args);
    }

}

(4)在需要被Hystrix控制請求時間的方法上添加注解@HystrixCommand,同時在注解內填入應急方法的方法名,並定義好應急方法。

    @GetMapping("roles/{id}")
    @HystrixCommand(fallbackMethod = "getRoleFallbackMethod") public String getRole(@PathVariable("id") String id) { System.out.println(LocalDateTime.now().toString() + "接收到請求[/roles/" + id + "]"); return restTemplate.getForObject(rest_url_prefix + "/users/" + id, String.class); } public String getRoleFallbackMethod(String id) { System.out.println(LocalDateTime.now().toString() + "進入fallBackMethod!"); return "進入fallBackMethod"; }

 

上面的步驟執行完成后,我們再多次調用getRole(String)方法,根據我們上面配置的參數,設置超時時間100秒是為了讓請求一直保持存活狀態。

假如請求的線程數超過了線程池中允許的最大線程,會拋出線程池拒絕異常,或是進入fallback方法。

 

3.Hystrix服務熔斷

不論是請求超時還是線程池的配置,服務熔斷做的更為徹底。

在一定的時間范圍內,向A服務發送的請求失敗率達到了一個指定的比例,會開啟熔斷器。熔斷器開啟后,所有向A服務發起的請求都將不會被發起請求,而是或拋出異常,或調用fallback方法。當熔斷器開啟達到指定時間后,會重新向A服務發起一次請求,如果請求失敗,熔斷器繼續保持開啟狀態。如果請求成功,則熔斷器關閉。

(1)引入MAVEN依賴

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.2.7.RELEASE</version>
    </dependency>

(2)在properties中進行配置(注意這里配置的都是default,默認適應所有的被@HystrixCommand修飾的方法中的請求)。

#一個rolling window內最小的請求數。如果請求數少於該值,則不論如何也不會觸發短路。
hystrix.command.default.circuitBreaker.requestVolumeThreshold=3
#錯誤率閾值。如果一個rolling window內的請求錯誤率超過了該值,則會開啟熔斷器
hystrix.command.default.circuitBreaker.errorThresholdPercentage=0.5
#觸發短路的時間值,單位毫秒。
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000

(3)在啟動類中添加注解@EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class RoleServerApplication { public static void main(String[] args) { SpringApplication.run(RoleServerApplication.class, args); } }

(4)在需要被Hystrix控制請求時間的方法上添加注解@HystrixCommand,同時在注解內填入應急方法的方法名,並定義好應急方法。

    @GetMapping("roles/{id}")
    @HystrixCommand(fallbackMethod = "getRoleFallbackMethod")
    public String getRole(@PathVariable("id") String id) {
        System.out.println(LocalDateTime.now().toString() + "接收到請求[/roles/" + id + "]");
        return restTemplate.getForObject(rest_url_prefix + "/users/" + id, String.class);
    }
    
    public String getRoleFallbackMethod(String id) {
        System.out.println(LocalDateTime.now().toString() + "進入fallBackMethod!");
        return "進入fallBackMethod";
    }

(5)這里我們編寫一個服務提供者代碼,假如接收到的id中有1,那么會正確返回,如果接收到的id中沒有1,那么會休眠100秒,導致請求超時。

    @GetMapping("users/{id}")
    public String getUser(@PathVariable("id") String id) {
        if (StringUtils.contains(id, "1")) {
            return "ok";
        }
        try {
            Thread.sleep(100*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String user = service.findUser(id);
        return user;
    }

請求結果:

我們可以先測試id=1的請求,如下圖,發現請求正常,此時circuit處於closed狀態。

然后我們再發送幾條id為其他值的請求,此時發現請求error,circuit已經變成了open狀態。這個時候即使我們發送id=1的請求也同樣會被進入到fallback方法中。

只有當circuit被開啟了指定的sleepWindowInMillisecond數后,再發送id=1的數據,circuit會重新變為close。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM