1. 程式人生 > >服務熔斷、降級、限流、非同步RPC -- HyStrix

服務熔斷、降級、限流、非同步RPC -- HyStrix

在今天,基於SOA的架構已經大行其道。伴隨著架構的SOA化,相關聯的服務熔斷、降級、限流等思想,也在各種技術講座中頻繁出現。本文將結合Netflix開源的Hystrix框架,對這些思想做一個梳理。

背景

伴隨著業務複雜性的提高,系統的不斷拆分,一個面向使用者端的API,其內部的RPC呼叫層層巢狀,呼叫鏈條可能會非常長。這會造成以下幾個問題:

API介面可用性降低

引用Hystrix官方的一個例子,假設tomcat對外提供的一個application,其內部依賴了30個服務,每個服務的可用性都很高,為99.99%。那整個applicatiion的可用性就是:99.99%的30次方 = 99.7%,即0.3%的失敗率。

這也就意味著,每1億個請求,有30萬個失敗;按時間來算,就是每個月的故障時間超過2小時。

系統被block

假設一個請求的呼叫鏈上面有10個服務,只要這10個服務中有1個超時,就會導致這個請求超時。
更嚴重的,如果該請求的併發數很高,所有該請求在短時間內都被block(等待超時),tomcat的所有執行緒都block在此請求上,導致其他請求沒辦法及時響應。

服務熔斷

為了解決上述問題,服務熔斷的思想被提出來。類似現實世界中的“保險絲“,當某個異常條件被觸發,直接熔斷整個服務,而不是一直等到此服務超時。
熔斷的觸發條件可以依據不同的場景有所不同,比如統計一個時間視窗內失敗的呼叫次數。

實現原理

實現原理講起來很簡單,其實就是不讓客戶端“裸調“伺服器的rpc介面,而是在客戶端包裝一層。就在這個包裝層裡面,實現熔斷邏輯。
拿Hystrix的helloword舉例:

public class CommandHelloWorld extends HystrixCommand<String> {

    private final String name;

    public CommandHelloWorld(String name) {
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"
)); this.name = name; } @Override protected String run() { //關鍵點:把一個RPC呼叫,封裝在一個HystrixCommand裡面 return "Hello " + name + "!"; } } //客戶端呼叫:以前是直接呼叫遠端RPC介面,現在是把RPC介面封裝到HystrixCommand裡面,它內部完成熔斷邏輯 String s = new CommandHelloWorld("World").execute();

隔離策略: 執行緒 vs 訊號量

預設的,上面的HystrixCommand是被扔到一個執行緒中執行的,也就是說,預設是執行緒隔離策略。
還有一種策略就是不搞執行緒池,直接在呼叫者執行緒中執行,也就是訊號量的隔離策略。
關於這2者的詳細區別,可以去參見官網。

熔斷的引數配置

Hystrix提供瞭如下的幾個關鍵引數,來對一個熔斷器進行配置:

circuitBreaker.requestVolumeThreshold //滑動視窗的大小,預設為20
circuitBreaker.sleepWindowInMilliseconds //過多長時間,熔斷器再次檢測是否開啟,預設為5000,即5s鍾
circuitBreaker.errorThresholdPercentage //錯誤率,預設50%

3個引數放在一起,所表達的意思就是:
每當20個請求中,有50%失敗時,熔斷器就會開啟,此時再呼叫此服務,將會直接返回失敗,不再調遠端服務。直到5s鍾之後,重新檢測該觸發條件,判斷是否把熔斷器關閉,或者繼續開啟。

服務降級

有了熔斷,就得有降級。所謂降級,就是當某個服務熔斷之後,伺服器將不再被呼叫,此時客戶端可以自己準備一個本地的fallback回撥,返回一個預設值。
這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強,當然這也要看適合的業務場景。

關於Hystrix中fallback的使用,此處不詳述,參見官網。

服務限流

限流在日常生活中也很常見,比如節假日你去一個旅遊景點,為了不把景點撐爆,管理部門通常會在外面設定攔截,限制景點的進入人數(等有人出來之後,再放新的人進去)。

對應到計算機中,比如要搞活動,秒殺等,通常都會限流。

說到限流,有個關鍵問題就是:你根據什麼策略進行限制??

比如在Hystrix中,如果是執行緒隔離,可以通過執行緒數 + 佇列大小限制;如果是訊號量隔離,可以設定最大併發請求數。

另外一個常見的策略就是根據QPS限制,比如我知道我呼叫的一個db服務,qps是3000,那如果不限制,超過3000,db就可能被打爆。這個時候,我可用在服務端做這個限流邏輯,也可以在客戶端做。

現在一般成熟的RPC框架,都有引數直接設定這個。

還有一些場景下,可用限制總數:比如連線數,業務層面限制“庫存“總量等等。。

限流的技術原理 -令牌桶演算法

關於限流的原理,相信很多人都聽說過令牌桶演算法,Guava的RateLimiter也已經有成熟做法,這個自己去搜索之。

此處想強調的是,令牌桶演算法針對的是限制“速率“。至於其他限制策略,比如限制總數,限制某個業務量的count值,則要具體業務場景具體分析。

非同步RPC

非同步RPC主要目的是提高併發,比如你的介面,內部呼叫了3個服務,時間分別為T1, T2, T3。如果是順序呼叫,則總時間是T1 + T2 + T3;如果併發呼叫,總時間是Max(T1,T2,T3)。

當然,這裡有1個前提條件,這3個呼叫直接,互相不依賴。

同樣,一般成熟的RPC框架,本身都提高了非同步化介面,Future或者Callback形式。

同樣,Hystrix也提高了同步呼叫、非同步呼叫方式,此處不再詳述。

總結

服務限流、熔斷、降級、非同步RPC是基於SOA的分散式系統中一些常見的基本策略,並且這些策略現在都有成熟的開源框架支援。用好這些策略,對整個系統的容錯性、穩定性有很大幫助。

後話

有興趣朋友可以關注公眾號“架構之道與術”, 獲取最新文章和進一步討論。

這裡寫圖片描述