天天看點

熔斷器使用

1、雪崩效應

現如今SOA、微服務風愈演愈烈,越來越多的業務和資源被以服務的形式包裝和釋出,服務間又可能會依賴其他各種服務。由此而來不可避免的會産生很多問題。

比如一個服務,其依賴了另外30個服務。假設每個服務的可用率都有三個9(99.9%),那麼我們計算一下:

99.99%^30 = 99.7%      

現實很殘酷,這個服務的實際可用性隻能是99.7%,也就是說每個月這個服務都要好當機8000+秒~~~

正常使用者請求時,服務内部依次請求A\P\H\I服務,并傳回響應結果。

熔斷器使用

非常不幸,我們的I服務出了某些問題,此時我們的使用者請求就被堵塞在I服務處。

熔斷器使用

更加悲劇的是,後續越來越多的請求都被堵塞在I服務處,而這些被堵塞的請求會占用線程、IO、網絡等系統資源,随着資源被占用的越來越多,本來不存在的性能問題也會随之而來,造成系統中的其他服務出現問題,甚至導緻系統奔潰。

這也就是我們常說的雪崩效應

熔斷器使用

2、服務容災

為了避免出現服務的雪崩,我們需要對服務做容災處理。

正常的服務容災處理思路有:

  • 資源隔離
  • 逾時設定
  • 服務降級
  • 服務限流

其中每種思路又可以有不同的解決方案。

比如資源隔離可以通過将不同的服務釋出在獨立的docker容器或伺服器中,這樣即使一個服務出現問題,也不會殃及池魚。

服務降級和服務限流可以通過前端nginx+lua來實作,當服務處理延遲或當機時,nginx可以直接傳回固定的降級/失敗響應,已快速跳過問題服務。

3、Hystrix

Hystrix,是Netflix的一個開源熔斷器,通過Hystrix,我們可以很友善的實作資源隔離、限流、逾時設計、服務降級等服務容災措施,并且還提供了強大的監控,可以檢視各個熔斷器的允許情況。

熔斷器使用

通過上圖,可以看出,Hystrix提供了一個HystrixCommand用來包裝調用請求。HystrixCommand的執行流程大概如下:

1.首先檢查緩存中是否有結果。如果有則直接傳回緩存結果。

2.判斷斷路器是否開啟,如果斷路器閉合,執行降級業務邏輯并傳回降級結果。

3.判斷信号量/線程池資源是否飽和,如飽和則執行降級業務邏輯并傳回降級結果。

4.調用實際服務,如發生異常,執行降級業務邏輯并傳回降級結果,并調整斷路器門檻值。

5.判斷實際業務是否逾時,逾時則傳回逾時響應結果,并調整斷路器門檻值。

了解了流程,來看下如何使用Hystrix。首先我們需要定義一個指令類來包裝我們的業務調用:

//繼承HystrixCommand
public class CommandHelloFailure extends HystrixCommand<String> {

    private final String name;

    public CommandHelloFailure(String name) {
        //設定分組key,分組key可以用在報表、監控中,預設的線程池隔離也基于分組key
         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
            //指定指令key,可
            .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
            //指定線程池key,取代預設的分組key
            .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
        /*
        //線程池隔離模式,不寫預設是線程池隔離模式
        HystrixCommandProperties.Setter()
           .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
        //信号量隔離模式
        HystrixCommandProperties.Setter()
           .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
        //逾時時間,預設1秒
        HystrixCommandProperties.Setter()
           .withExecutionTimeoutInMilliseconds(int value)  
        //信号量模式下,最大并發請求限流,預設值10
        HystrixCommandProperties.Setter()
           .withFallbackIsolationSemaphoreMaxConcurrentRequests(int value)  
        //熔斷器門檻值,預設20
        HystrixCommandProperties.Setter()
            .withCircuitBreakerRequestVolumeThreshold(int value)
        //熔斷器關閉時間,預設5秒
        HystrixCommandProperties.Setter()
            .withCircuitBreakerSleepWindowInMilliseconds(int value)
        */
        this.name = name;
    }

    @Override
    //執行實際服務,這裡模拟全部傳回異常
    protected String run() {
        throw new RuntimeException("this command always fails");
    }

    @Override
    //執行降級業務
    protected String getFallback() {
        return "Hello Failure " + name + "!";
    }

    @Override
    //從緩存中擷取
    protected String getCacheKey() {
        ...
    }
}      

使用這個指令類也非常簡單:

//同步執行
String s = new CommandHelloWorld("Bob").execute();
//異步執行
Future<String> s = new CommandHelloWorld("Bob").queue();
//響應式
Observable<String> s = new CommandHelloWorld("Bob").observe();      

4、Hystrix和Spring boot

想在spring boot中使用Hystrix就更加簡單了,隻需要引入spring-cloud-starter-hystrix,

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>      

然後添加注解使用Hystrix

@EnableCircuitBreaker

@EnableHystrixDashboard

最後在需要使用熔斷器的地方标記注解即可。

@HystrixCommand(groupKey = "xxx", fallbackMethod = "yyy")
public String doSomething()