現狀
分散式場景中。若服務不穩定,會導致呼叫方服務也不可用,從而造成雪崩效應。因此要對在原服務不可用時進行熔斷降級處理。
分析
熔斷降級可以服務端限流、閘道器限流、客戶端限流。
1. 客戶端限流:在呼叫方法發起請求時檢查是否達到閥值。若達到閥值,不發起呼叫請求
優點:可以在服務消費端直接控制流量出口,減少不必要請求的發起。
缺點:客戶端需要感知服務執行指標和容災規則。每個業務方需要重複開發
2. 服務端限流:服務提供方自定義容災邏輯,在收到請求後再根據當前狀態判斷是否走fallback邏輯
優點:容災規則、閥值完全封裝在服務提供者。對呼叫方無感知。
缺點:若服務提供者都掛了,無法進行容災。
3. 閘道器限流:原本直接呼叫提供者的請求都由閘道器層代理轉發。容災規則的配置、降級邏輯都封裝在閘道器層。
優點:客戶端、服務端都無需感知容災邏輯。
缺點:多了一次網路請求、rt變大
大部分情況下,我們都是選擇服務端限流。但客戶端對資料平臺的介面是強依賴的。若搜尋應用掛了,客戶端還是需要看到資料。相比高可用,略微的rt變大是可以接受的,所以啟動一個資料容災閘道器
技術選型
現在瞭解到的開源容災框架有hystrix、sentinel兩種。
hystrix:常用於springcloud的一個熔斷降級元件。主要功能是不同服務之間的資源隔離、失敗降級。底層實現是Rxjava。它提供兩種資源隔離的模式:訊號量隔離和執行緒池隔離。一般使用執行緒池隔離。耗費一定資源,但相比之下支援超時和非同步執行。聽起來可以覆蓋大部分場景,但它不支援更高要求的流控,如qps的控制。所以需要單獨採用令牌漏桶來做流量控制。
sentinel:阿里開源的分散式流量控制元件。支援流控、熔斷降級、系統保護等。所有的資源都對應一個資源名稱以及一個Entry。每一個Entry建立的時候,同時也會建立一系列外掛(系統保護外掛:SystemSlot、流控外掛:FlowSlot、熔斷降級外掛LDegradeSlot等)。每個外掛會監控自己職責範圍內的指標。NodeSelectorSlot將各個資源的呼叫路徑以樹狀儲存,用於限流降級。呼叫者通過建立上下文、請求token來執行方法。若沒有丟擲BlockException,表示請求成功。它支援併發數/qps的流量控制、也支援熔斷降級。
對比:1.hystrix的熔斷都圍繞執行緒池展開。更適合做資源隔離,但單個應用有多個服務時執行緒池開銷會造成浪費。hystrix是單個超時立即熔斷,控制力度更細。多個微服務的場景可以考慮用這種。2.sentinel是基於併發數,支援的場景也更復雜,開銷小,適合在保證服務穩定的情況下提高吞吐量。但它的超時是5次請求的平均響應時間。並不是很嚴格。但對於大多數場景而言可以接受
接入方式
sentinel支援api和註解兩種接入方式。作為容災閘道器,之後可以會接很多介面。為了接入簡單、對程式碼無侵入。需要使用註解的方式。但是原生的@SentinelResource有幾個問題:
1. 只能指定資源名稱、fallback方法。使用者還是需要通過api建立容災規則,
2. 而且fallback方法入參要加上BlockException。這樣的接入方式不是很優雅。
3. 流控異常FlowException的方法要另外指定。
於是基於sentinel封裝了一層自定義註解@AegisResource
@AegisResource(value = "hello",limitThread = 0,timeOut = 100,failRate = 0.5,timeWindows = 100,fallback = "exceptionHandler")
引數說明:
value:資源名稱,預設為方法名
limitThread:最大執行緒數,預設-1,即不啟用
timeOut:介面超時時間,預設-1,即不啟用
failRate:失敗率,預設-1,即不啟用
timeWindows:觸發降級但持續時間,預設100
fallback:降級方法,必須指定
接入demo
/**
* 保護的方法
* @return
*/
@GetMapping("resourcetest")
@AegisResource(value = "hello",limitThread = 0,timeOut = 100,failRate = 0.5,timeWindows = 100,fallback = "exceptionHandler")
public String hello() {
return "ok";
}
/**
* 降級的方法
* @return
*/
public String exceptionHandler() {
// Do some log here.
return "Oops, error occurred at " ;
}
複製程式碼
新介面只需寫好希望執行的方法和降級方法,然後在希望執行的方法上加入@AegisResource(fallBack=“fallback的方法名”)就可以無侵式入地進行容災。切面定義了預設容災閥值。也可以在對應屬性上設定自定義的閥值。
後期規劃
目前容災閘道器可以滿足目前的需求。目前有開源的控制檯,可以檢視服務呼叫大盤,動態調整容災規則。缺點是目前指標的蒐集是http方式。容災規則、執行指標也沒有持久化儲存。後期如果需要,可以藉助現有的開源控制檯進行二次開發。