Hystrix原理分析

1、容錯限流的需求

在複雜的分佈式系統中一般有不少依賴,若是一個應用不能對來自依賴故障進行隔離,那麼應用自己就處於被拖垮的風險中。在一個高流量的網站中,某一個單一後端一旦發生延遲,將會在數秒內致使全部的應用資源被耗盡,這也就是咱們常說的雪崩效應。java

好比在電商系統的下單業務中,在訂單服務建立訂單後同步調用庫存服務進行庫存的扣減,假如庫存服務出現了故障,那麼會致使下單請求線程會被阻塞,當有大量的下單請求時,則會佔滿應用鏈接數從而致使訂單服務沒法對外提供服務。git

2、容錯限流的原理

對於基本的容錯限流模式,主要有如下幾點須要考量:github

  • 主動超時:在調用依賴時儘快的超時,能夠設置比較短的超時時間,好比2s,防止長時間的等待。
  • 限流:限制最大併發數。
  • 熔斷:錯誤數達到閾值時,相似於保險絲熔斷。
  • 隔離:隔離不一樣的依賴調用
  • 服務降級:資源不足時進行服務降級

1.斷路器模式

hystrix5.png

實現流程爲:當斷路器的開關爲關閉時(對應圖中的綠色),每次請求進來都是成功的,當後端服務出現問題,請求出現的錯誤數達到必定的閾值,則會觸發斷路器爲打開狀態(對應圖中的紅色),在斷路器爲打開狀態時,進來的全部請求都會被拒絕,固然也不是一直會拒絕請求,而是彈性的,過了特定的時間後,斷路器會進入半打開狀態(對應圖中的黃色),這是會讓一部分請求經過進行嘗試,若是嘗試仍是有問題,則繼續進入打開狀態,若是嘗試沒有問題了,則會進入關閉狀態。redis

2.艙壁隔離模式

hystrix6.png

艙壁隔離模式能夠對資源進行隔離,相似於船的船艙都是被隔離開來的,當其中一個或者幾個船艙出現問題,好比漏水,是不會影響到其餘的船艙的,從而實現一種資源隔離的效果。後端

3.容錯理念

  • 凡是依賴都有可能會失敗。
  • 凡是資源都有限制,好比CPU、Memory、Threads、Queue。
  • 網絡並不可靠,可能存在網絡抖動等其餘問題。
  • 延遲是應用穩定的殺手,延遲會佔據大量的資源。

3、什麼是Hystrix

Hystrix是Netflix公司開源的一款容錯框架。 它能夠完成如下幾件事情:緩存

  • 資源隔離,包括線程池隔離和信號量隔離,避免某個依賴出現問題會影響到其餘依賴。
  • 斷路器,當請求失敗率達到必定的閾值時,會打開斷路器開關,直接拒絕後續的請求,而且具備彈性機制,在後端服務恢復後,會自動關閉斷路器開關。
  • 降級回退,當斷路器開關被打開,服務調用超時/異常,或者資源不足(線程、信號量)會進入指定的fallback降級方法。
  • 請求結果緩存,hystrix實現了一個內部緩存機制,能夠將請求結果進行緩存,那麼對於相同的請求則會直接走緩存而不用請求後端服務。
  • 請求合併, 能夠實現將一段時間內的請求合併,而後只對後端服務發送一次請求。

4、Hystrix核心概念

1.資源隔離

資源隔離的思想參考上述的艙壁隔離模式,在hystrix中提供了兩種資源隔離策略:線程池隔離、信號量隔離。網絡

1844674407356205960318446744073511537700_wps圖片.png

線程池隔離:線程池隔離會爲每個依賴建立一個線程池來處理來自該依賴的請求,不一樣的依賴線程池相互隔離,就算依賴A出故障,致使線程池資源被耗盡,也不會影響其餘依賴的線程池資源。數據結構

  • 優勢:支持排隊和超時,支持異步調用。
  • 缺點:線程的建立一個調度會形成必定的性能開銷。
  • 適用場景:適合耗時較長的接口場景,好比接口處理邏輯複雜,且與第三方中間件有交互,由於線程池模式的請求線程與實際轉發線程不是同一個,因此能夠保證容器有足夠的線程來處理新的請求。

信號量隔離模式: 初始化信號量currentCount=0,每進來一個請求須要先將currentCount自增,再判斷currentCount的值是否小於系統最大信號量,小於則繼續執行,大於則直接返回,拒絕請求。架構

代碼以下:併發

public boolean tryAcquire() {
    int currentCount = this.count.incrementAndGet();
    if (currentCount > (Integer)this.numberOfPermits.get()) {
        this.count.decrementAndGet();
        return false;
    } else {
        return true;
    }
}
  • 優勢:輕量,無額外的開銷,只是一個簡單的計數器
  • 缺點:不支持任務排隊和主動超時;不支持異步調用
  • 適用場景:適合能快速響應的接口場景,不適合一些耗時較長的接口場景,由於信號量模式下的請求線程與轉發處理線程是同一個,若是接口耗時過長有可能會佔滿容器的線程數。
隔離方式 是否支持超時 是否支持熔斷 隔離原理 是否異步調用 資源消耗
線程池隔離 支持,可直接返回 支持,當線程池到達maxSize後,再請求會觸發fallback接口進行熔斷 每一個服務單獨用線程池,請求線程與轉發處理線程不是同一個 能夠是異步,也能夠是同步。看調用的方法 大,大量線程的上下文切換,容易形成機器負載高
信號量隔離 不支持,若是阻塞,只能經過調用協議(如:socket超時才能返回) 支持,當信號量達到maxConcurrentRequests後。再請求會觸發fallback 經過信號量的計數器,請求線程與轉發處理線程是同一個 同步調用,不支持異步 小,只是個計數器

2.斷路器

斷路器工做原理以下:

hystrix90.png

Hystrix是基於滾筒式來處理,每一秒會產生一個buckets,每產生一個新的buckets就會移除一個最老的buckets,默認是10秒一個窗口。buckets在內存中就是一種數據結構,每一個buckets會記錄Metrics的相關數據,好比成功、失敗、超時、拒絕。

當一個HystrixCommand進來後,會先經過allowRequest()方法判斷是否容許經過該次請求,allowRequest()方法會經過isOpen判斷斷路器是否打開。斷路器關閉,則容許經過該次請求;斷路器打開,則會判斷是否過了睡眠週期。沒有過睡眠週期則返回false,拒絕經過該次請求,過了睡眠週期則會嘗試放行。

isOpen()方法會按照(failure) / (success+failure)公式計算出失敗率,若是失敗率大於閾值,則會觸發熔斷。公式中的成功、失敗的數據就來源於每10秒中一個窗口的滾筒數據。

對於一個依賴調用,要麼調用成功,要麼調用失敗(包括異常、超時、拒絕),這些調用結果都會記錄到buckets中。對於調用成功結果來講,還會判斷斷路器開關是否打開,若是是打開狀態的話,則會關閉斷路器並重置相關的計數器。

3.降級回退

降級,一般指事務高峯期,爲了保證核心服務正常運行,須要停掉一些不過重要的業務,或者某些服務不可用時,執行備用邏輯從故障服務中快速失敗或快速返回,以保障主體業務不受影響。 Hystrix提供的降級主要是爲了容錯,保證當前服務不受依賴服務故障的影響,從而提升服務的健壯性。

1)哪些狀況會進入降級邏輯

  • 斷路器打開
  • 線程池/信號量資源不足
  • 執行依賴調用超時
  • 執行依賴調用異常

2)降級回退方式

(1)Fail Fast快速失敗

快速失敗是最普通的命令執行方法,命令沒有重寫降級邏輯。 若是命令執行發生任何類型的故障,它將直接拋出異常。

(2)Fail Fast無聲失敗

指在降級方法中經過返回null,空Map,空List或其餘相似的響應來完成。

(3)FallBack:Static

指在降級方法中返回靜態默認值。 這不會致使服務以「無聲失敗」的方式被刪除,而是致使默認行爲發生。如:應用根據命令執行返回true / false執行相應邏輯,但命令執行失敗,則默認爲true。

(4)FallBack:Stubbed

當命令返回一個包含多個字段的複合對象時,適合以Stubbed 的方式回退。

(5)FallBack:Cache via Network

有時,若是調用依賴服務失敗,能夠從緩存服務(如redis)中查詢舊數據版本。因爲又會發起遠程調用,因此建議從新封裝一個Command,使用不一樣的ThreadPoolKey,與主線程池進行隔離。

(6)Primary+Secondary with FallBack

有時系統具備兩種行爲- 主要和次要,或主要和故障轉移。主要和次要邏輯涉及到不一樣的網絡調用和業務邏輯,因此須要將主次邏輯封裝在不一樣的Command中,使用線程池進行隔離。爲了實現主從邏輯切換,能夠將主次command封裝在外觀HystrixCommand的run方法中,並結合配置中心設置的開關切換主從邏輯。因爲主次邏輯都是通過線程池隔離的HystrixCommand,所以外觀HystrixCommand可使用信號量隔離,而沒有必要使用線程池隔離引入沒必要要的開銷。

4.請求結果緩存

hystrix-cache.png
實際應用場景不多,不予過多介紹。

5.請求合併

hystrix-xx.png
實際應用場景不多,不予過多介紹。

5、Hystrix工做流程

1844674407355605524124348914_wps圖片.png

對於一次依賴調用,會被封裝在一個HystrixCommand對象中,調用的執行有兩種方式,一種是調用execute()方法同步調用,另外一種是調用queue()方法進行異步調用。

執行時會判斷斷路器開關是否打開,若是斷路器打開,則進入getFallback()降級邏輯;若是斷路器關閉,則判斷線程池/信號量資源是否已滿,若是資源滿了,則進入getFallback()降級邏輯;若是沒滿,則執行run()方法。再判斷執行run()方法是否超時,超時則進入getFallback()降級邏輯,run()方法執行失敗,則進入getFallback()降級邏輯,執行成功則報告Metrics。Metrics中的數據包括執行成功、超時、失敗等狀況的數據,Hystrix會計算一個斷路器的健康值,也就是失敗率,當失敗率超過閾值後則會觸發斷路器開關打開。

getFallback()邏輯爲:若是沒有實現fallback()方法,則直接拋出異常,另外fallback降級也是須要資源的,在fallback時須要獲取一個針對fallback的信號量,只有獲取成功才能fallback,獲取信號量失敗,則拋出異常,獲取信號量成功,纔會執行fallback方法而且會響應fallback方法中的內容。

6、參考資料

楊波老師的《微服務架構實戰160講》

https://github.com/Netflix/Hy...

相關文章
相關標籤/搜索