1. 程式人生 > 其它 >Spring Cloud Hystrix資源隔離策略(執行緒、訊號量)

Spring Cloud Hystrix資源隔離策略(執行緒、訊號量)

Hystrix 的資源隔離策略有兩種,分別為執行緒池和訊號量。那我們為什麼需要資源隔離呢?

在一個分散式系統中,服務之間都是相互呼叫的,例如,我們容器(Tomcat)配置的執行緒個數為 1000,服務 A-服務 R,其中服務 I 的併發量非常的大,需要 500 個執行緒來執行,此時,服務 I 又掛了,那麼這 500 個執行緒很可能就夯死了,那麼剩下的服務,總共可用的執行緒為 500 個,隨著併發量的增大,剩餘服務掛掉的風險就會越來越大,最後導致整個系統的所有服務都不可用,直到系統宕機。

以上就是服務的雪崩效應。Hystrix 就是用來做資源隔離的,比如說,當客戶端向服務端傳送請求時,給服務 I 分配了 10 個執行緒,只要超過了這個併發量就走降級服務

,就算服務 I 掛了,最多也就導致服務 I 不可用,容器的 10 個執行緒不可用了,但是不會影響系統中的其他服務。

下面,我們就來具體說下這兩種隔離策略。

訊號量策略配置

用於隔離原生代碼可快速返回的遠端呼叫可以直接使用訊號量隔離,降低執行緒隔離的上下文切換開銷。如 memcached,redis。

執行緒隔離會帶來執行緒開銷,有些場景(比如無網路請求場景)可能會因為用開銷換隔離得不償失,為此 hystrix 提供了訊號量隔離

主要適用於併發需求不大的依賴呼叫,因為如果併發需求較大,相應的訊號量的數量就要設定得夠大,因為 Tomcat 執行緒與處理執行緒為同一個執行緒,那麼這個依賴呼叫就會佔用過多的 Tomcat 執行緒資源,有可能會影響到其他服務的接收。

訊號量策略配置方法程式碼如下所示。

super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
            .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE
            )));
    this.name = name;
}

之前在 run 方法中特意輸出了執行緒名稱,通過這個名稱就可以確定當前是執行緒隔離還是訊號量隔離。

執行緒隔離策略配置

執行依賴程式碼的執行緒與請求執行緒(比如 Tomcat 執行緒)分離,請求執行緒可以自由控制離開的時間,這也是我們通常說的非同步程式設計,Hystrix 是結合 RxJava來實現的非同步程式設計。

通過為每個包裹了 HystrixCommand 的 API 介面設定獨立的、固定大小的執行緒池(hystrix.threadpool.default.coreSize)來控制併發訪問量,當執行緒飽和的時候可以拒絕服務,防止依賴問題擴散。

系統預設採用執行緒隔離策略,我們可以通過 andThreadPoolPropertiesDefaults 配置執行緒池的一些引數,程式碼如下所示。

public MyHystrixCommand(String name) {
    super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
            .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                    .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))
            .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10)
                    .withMaxQueueSize(100).withMaximumSize(100)));
    this.name = name;
}

執行緒隔離策略的優點如下:

  • 一個依賴呼叫可以給予一個執行緒池,這個依賴的異常不會影響其他的依賴。
  • 使用執行緒可以完全隔離業務程式碼,請求執行緒可以快速返回。
  • 可以完全模擬非同步呼叫,方便非同步程式設計。

執行緒隔離策略的缺點:使用執行緒池的缺點主要是增加了計算的開銷。每一個依賴呼叫都會涉及到佇列,排程,上下文切換,而這些操作都有可能在不同的執行緒中執行。