微服務熔斷隔離機制及注意事項

用友雲平臺發表於2018-12-03

導讀:本文重點分析微服務化過程中熔斷機制及應用注意事項,包括微服務呼叫與“雪崩效應”及解決方案、熔斷機制及考慮因素、隔離機制及實現方式考量等內容。

  隨著企業微服務化戰略的實施,業務功能細分,越來越多的服務從原有的單體應用中分解成一系列獨立開發、部署、運維的微小服務,服務之間則依賴於各種RPC框架互相通訊。縱然,微服務化有著很多優勢,但與之伴隨而來的是各種複雜性,對開發人員來說,除了業務領域本身外,還需要考慮由於服務拆分之後諸如分散式事務、服務部署及運維、rpc呼叫等系列問題,本文將重點分析微服務化過程中熔斷機制及應用注意事項。

微服務呼叫與“雪崩效應”:

  微服務化之後服務之間呼叫關係複雜,呼叫層級深,服務之間依靠rpc框架進行通訊,如下圖1,實線是同步rpc呼叫,虛

微服務熔斷隔離機制及注意事項
圖1 服務呼叫關係

線則是非同步rpc呼叫,整個呼叫鏈路從webapi開始到dinnerservice結束,紅色節點則表示該服務不可用或高延遲,非同步呼叫msgservice異常對鏈路返回結果並無影響,而同步呼叫(memberservice服務)的效能對鏈路則有很大影響,其會造成鏈路上planeservice、orderservice及webapi服務堵住,堵著的請求會耗費執行緒及io資源,隨著此類請求越來越多,特別是在流量高峰時,如果不能及時解決memberservice的問題,最終將把整條鏈路堵死,造成webapi不能對外提供服務,提供崩潰,這就是所謂的雪崩效應。

雪崩效應解決方案:

  針對雪崩效應的情況,通常我們可以有如下幾中方案來解決。   

  一、同步呼叫非同步化方案。如圖所示,非同步呼叫對於呼叫方來說,不會造成堵塞,從而將呼叫方保護起來。因此,可從業務層面設計入手,將不需要及時返回結果的業務呼叫設計成非同步來呼叫。典型場景,註冊驗證碼傳送,訊息通知等。

  二、限流方案。通過限制入口流量,將併發限制在一定範圍內,能在一定程度上避免雪崩效應,如果不可用服務是部分不可用或超時時。   以上方案都不能徹底解決問題癥結,那真正比較可行的則是第三種,應用熔斷隔離機制的方案。熔斷,就像電路短路,當電壓過高,負載加重時,保險絲就會自動斷開,避免事故發生。在微服務中,當鏈路上某個服務不可用或延遲嚴重,達到熔斷器設定指標閾值時,則觸發熔斷機制,對於後續請求直接返回預設結果或丟擲異常,避免整個鏈路因為部分服務不可用而雪崩。隔離則是服務呼叫方將耗時的方法或rpc呼叫與業務程式碼隔離開來,避免耗時方法或rpc呼叫造成服務堵塞。

熔斷機制及考慮因素:

  熔斷機制具體實現體現為一個熔斷器,如何實現熔斷器,主要考慮以下幾個方面。

  第一,熔斷請求判斷演算法即熔斷在什麼條件處於開啟狀態,什麼條件處於關閉或半關閉狀態。使用滑動時間視窗來記錄每個時間片內相關熔斷計數指標及熔斷器狀態,這個時間片段稱作為一個bucket,預設維護10個bucket,每1秒一個bucket,隨著時間的滾動,最早的bucket拋棄,建立新的bucket到滑動視窗右邊。每個blucket記錄請求總數、成功數、超時數、拒絕數及熔斷器狀態,預設錯誤超過50%且10秒內超過20個請求進行中斷攔截。

微服務熔斷隔離機制及注意事項
圖2 滑動視窗

  第二、熔斷恢復。預設情況下,熔斷器處於閉合狀態,當熔斷指標達到閾值時,熔斷器狀態變為開啟狀態,此時,所有請求直接返回或丟擲異常。過了一段時間後,後端異常服務經過開發運維人員及時解決了問題,熔斷器如何知曉呢?如果沒有一定的熔斷恢復機制,那一旦熔斷器開啟,就不能再閉合上,顯然不合情理。因此,熔斷器需要有放行規則,對於熔斷器開啟狀態超5s以內的請求,直接熔斷,如果熔斷器開啟超過5s,則進入半開啟狀態,可以按一定規則,允許部分請求通過,試探性的呼叫被隔離的服務,若請求如是健康狀態,則恢復關閉熔斷器,如下圖3是熔斷器狀態轉換關係。

微服務熔斷隔離機制及注意事項
圖3熔斷器狀態轉換

  第三、熔斷後如何處理請求。當熔斷器處於開啟狀態時,請求直接返回,業務如何知道當前發生了狀況?可向業務層丟擲特定異常,用於標識當前熔斷器開啟,但熔斷器通常通過降級措施來處理,提供提供降級介面或實現,由熔斷器自行處理降級措施,開發人員只需要實現降級邏輯即可,其它事情就交給熔斷器來處理。

隔離機制及實現方式考量:

  隔離機制也是為了保護微服務鏈路呼叫中避免雪崩效應的一種策略,與熔斷配合使用,隔離機制可以有兩種實現。

  一、執行緒池隔離模式:使用一個執行緒池來儲存當前的請求,執行緒池對請求作處理,設定任務返回處理超時時間,堆積的請求堆積入執行緒池佇列。這種方式需要為每個依賴的服務申請執行緒池,有一定的資源消耗,好處是可以應對突發流量(流量洪峰來臨時,處理不完可將資料儲存到執行緒池隊裡慢慢處理)。   二、訊號量隔離模式:使用一個原子計數器(或訊號量)來記錄當前有多少個執行緒在執行,請求來先判斷計數器的數值,若超過設定的最大執行緒個數則丟棄改型別的新請求,若不超過則執行計數操作請求來計數器+1,請求返回計數器-1.這種方式是嚴格的控制執行緒且立即返回模式,無法應對突發流量(流量洪峰來臨時,處理的執行緒超過數量,其他的請求會直接返回,不繼續去請求依賴的服務)。   執行緒池隔和限號量隔離機制各有利弊,在使用訊號量隔離時,最大的弊端是不能實現超時返回,這有時對業務是致命的,一旦後端服務超時時間過長,已經發起的呼叫無法及時返回,導致資源堵塞,呼叫方長時間等待。而執行緒池隔離機制可以解決超時返回的問題,執行緒池隔離機制問題在於在微服務之間通過rpc呼叫,無論是我們自研的rpc框架,還是開源的rpc框架如dububo等,都可能會使用Threadlocal來快取本地執行緒變數來傳遞上下文資訊,服務端接收到呼叫的傳過來請求時,需要將請求中附帶的上下文資訊儲存到當前執行緒的Threadlocal變數中,當服務端呼叫其它其它服務時,需要將上下文資訊從Threadlocal取出來再傳遞給下游服務,在tomcat執行緒模型下工作正常,但此時如果將對rpc的呼叫進行執行緒隔離後,由於執行緒複用問題,導致在隔離執行緒中執行rpc呼叫時服務獲取不到呼叫執行緒中的Threadlocal變數,這會導致鏈路跟蹤資訊無法傳遞等問題,在實踐中需要引起特別注意,此問題關鍵是要解決跨執行緒間Threadlocal變數傳遞,至於如何傳遞,可以參考jdk的InheritableThreadlocal機制,他解決了父子程式間Threadlocal變數繼承問題,提供了一種解決此問題的思路,但執行緒隔離機制,比如Hystrix通常都是通過執行緒池來實現,避免反覆建立銷燬執行緒帶來的效能損耗,但隔離執行緒與呼叫執行緒沒有父子關係,因此需要自行解決Threadlocal變數跨執行緒的問題。

相關文章