springcloud 系列 -- 簡單瞭解一下 hystrix

寫在前面

思考的過程每每比直接獲得結論更加劇要html

一、爲何須要熔斷器

服務雪崩

在分佈式環境下,不可避免的就是服務之間的調用。A 調 B,B 可能會失敗,若是此時 B 服務掛掉,那麼會致使服務 A 由於服務 B 的失敗而失敗。從而致使 客戶端認爲 A 也是失敗的。 簡單說就是,牽一髮而動全身java

這也是,咱們須要熔斷器的緣由。咱們須要有保護服務調用的組件。當服務 B 掛掉時,服務 B 須要可以快速失敗。git

二、若是本身寫一個斷路器,你會怎麼作呢?

隔離策略

思考一下,什麼是隔離?
我對他的理解,大概就是,服務 A 調用服務 B,服務 C。不能由於調用服務 B 出現問題,而致使調用服務 C 也出現問題。也就是,服務B、服務C 的調用應該放在不一樣的環境下。github

常見的資源隔離,有線程池隔離,信號量隔離算法

線程池隔離 信號量隔離
線程 請求線程和調用 provider 不是同一個線程 請求線程和調用 provider 是同一個線程
開銷 排隊、調度、上下文開銷等 無線程切換,開銷低
異步 支持 不支持
併發支持 支持(線程池大小) 支持(信號量上限)
傳遞 Header 沒法傳遞 Http Header 能夠傳遞 Http Header
快速失敗

當 provider 提供的服務不可用,或出現異常時,應該有可供回調的降級方法。編程

  • provider 調用失敗拋出異常,可能針對某種異常,不想執行快速失敗策略,而是須要直接拋出異常
  • provider 調用失敗,可能不想執行快速失敗策略,也不想拋出任何異常。
限流

當 provider 被大量調用時,爲了保護鏈路,須要作限流。那麼其實核心的問題是,如何進行統計。設計模式

統計

每一個 provider 的調用狀況須要統計。這樣能夠更好的監控到 provider 提供的服務的狀況。統計的算法,應該是基於滑動窗口進行統計。tomcat

熔斷

由於有對每一個 provider 調用狀況統計,在調用以前,失敗次數達到某個閾值時,能夠認爲該 provider 已是有問題的,能夠直接快速失敗,以防止服務雪崩狀況。併發

系統自適應保護

熔斷機制是針對每一個 provider 的。可是,有可能服務系統已經要達到極限了,不能再接收任何請求了,那麼此時,出於系統的保護,也應該快速失敗。異步

擴展

做爲一個組件,支持擴展那是必須。
常見的擴展方式:(其實就是面向接口編程,在某些執行流程中,暴露出部分接口。剩下的就看你怎麼封裝了)

  • 觀察者設計模式 + 策略設計模式。 例如
public interface SayListener {
  String say();
}

public class App {
    List<SayListener> sayListener = new ArrayList<>();
    public void doSomething() {
      // ...
       
      sayAction();
       // 觸發了 say 的動做
      if (null != sayListener && sayListener.size() > 0) {
          sayListener.forEach(listener -> {
            listener.say();
          });
      }
       
       
      // ...
    }
    
    public void sayAction() {}
    
    public void registerSayListener(SayListener listener) {
       sayListener.add(listener);
    }
}

三、現有相似功能組件對比

sentinel hystrix resilience4j
隔離策略 信號量隔離(併發線程數限流) 線程池隔離/信號量隔離 信號量隔離
熔斷降級策略 基於響應時間、異常比率、異常數 基於異常比率 基於異常比率、響應時間
實時統計實現 滑動窗口(LeapArray) 滑動窗口(RxJava) Ring Bit Buffer
動態規則配置 支持多種數據源 支持多種數據源 有限支持
擴展性 多個擴展點 插件形式 接口形式
基於註解的支持 支持 支持 支持
限流 基於 QPS, 支持基於調用關係的限流 基於線程池個數有限支持 Rate Limiter
系統自適應保護 支持 不支持 不支持
控制檯 豐富 簡單 不提供控制檯,可對接其餘監控系統

hystrix wiki 介紹實在太全了,這裏就不必在介紹了,主要是從我的的角度去思考若是讓本身也實現一個斷路器中間件,你會怎麼作?(鑑於 hystrix 中止維護,就沒看源碼了,以及 sentinel 的活躍,重心會放在 sentinel 上)

四、使用注意

在使用 hystrix 須要注意的幾個地方。

hystrix 超時設置

設置 hystrix 超時時間時,須要大於等於 ribbon 的超時時間。 例如 ribbon 的配置以下

ReadTimeout=1000 
ConnectTimeout=1000
MaxAutoRetries=1
MaxAutoRetriesNextServer=1

那麼 hystrix 的超時時間公式爲:

execution.isolation.thread.timeoutInMilliseconds >= (MaxAutoRetriesNextServer + 1) * (MaxAutoRetries + 1) * (ReadTimeout + ConnectTimeout)
hystrix 使用線程池隔離時,沒法傳遞綁定在 tomcat 線程上下文的值

由於使用線程池隔離時(execution.isolation.strategy=THREAD),會新建立一個線程,所以 tomcat 線程的變量則沒法傳遞給新的線程。那麼此時可使用 信號量隔離(execution.isolation.strategy=SEMAPHORE)。由於使用信號量隔離時,會使用 tomcat 線程調用遠程服務。
其實 hystrix 也想到了會有這樣的需求, 所以在 wiki 中,推薦咱們繼承 HystrixConcurrencyStrategy,重寫 wrapCallable() 方法。 具體代碼參考 線程池隔離傳遞 ThreadLocal 值
該做者是基於 spi 實現的(牛逼),其實 hystrix 提供了可配置的參數供咱們配置

hystrix:
  plugin:
    HystrixConcurrencyStrategy:
      implementation: com.csp.hystrix.MyHystrixConcurrencyStrategy
相關文章
相關標籤/搜索