圖解resilience4j容錯機制

東溪陳姓少年發表於2020-06-30

Resilience4j是一個輕量級、易於使用的容錯庫,其靈感來自Netflix Hystrix,但專為Java 8和函數語言程式設計設計。輕量級,因為庫只使用Vavr,它沒有任何其他外部庫依賴項。相比之下,Netflix Hystrix對Archaius有一個編譯依賴關係,Archaius有更多的外部庫依賴關係,如Guava和Apache Commons。

Resilience4j提供高階函式(decorators)來增強任何功能介面、lambda表示式或方法引用,包括斷路器、速率限制器、重試或艙壁。可以在任何函式介面、lambda表示式或方法引用上使用多個裝飾器。優點是您可以選擇所需的裝飾器,而無需其他任何東西。

有了Resilience4j,你不必全力以赴,你可以選擇你需要的。

https://resilience4j.readme.io/docs/getting-started

概覽

本文將介紹resilience4j中的四種容錯機制,不過鑑於容錯機制原理的通用性,後文所介紹的這幾種容錯機制也可以脫離resilience4j而獨立存在(你完全可以自己編碼實現它們或者採用其他類似的第三方庫,如Netflix Hystrix)。下面將會用圖例來解釋艙壁(Bulkhead)、斷路器(CircuitBreaker)、限速器(RateLimiter)、重試(Retry)機制的概念和原理。

艙壁(Bulkhead)

Resilience4j提供了兩種艙壁模式的實現,可用於限制併發執行的次數:

  • SemaphoreBulkhead(訊號量艙壁,預設),基於Java併發庫中的Semaphore實現。
  • FixedThreadPoolBulkhead(固定執行緒池艙壁),它使用一個有界佇列和一個固定執行緒池。

SemaphoreBulkhead應該在各種執行緒和I / O模型上都能很好地工作。它基於訊號量,與Hystrix不同,它不提供“影子”執行緒池選項。取決於客戶端,以確保正確的執行緒池大小將與艙壁配置保持一致。

訊號量艙壁(SemaphoreBulkhead)

img

?原圖地址:訊號量艙壁(SemaphoreBulkhead)

如上圖,當訊號量存在剩餘時進入系統的請求會直接獲取訊號量並開始業務處理。當訊號量全被佔用時,接下來的請求將會進入阻塞狀態,SemaphoreBulkhead提供了一個阻塞計時器,如果阻塞狀態的請求在阻塞計時內無法獲取到訊號量則系統會拒絕這些請求。若請求在阻塞計時內獲取到了訊號量,那將直接獲取訊號量並執行相應的業務處理。

固定執行緒池艙壁(FixedThreadPoolBulkhead)

img

?原圖地址:固定執行緒池艙壁(FixedThreadPoolBulkhead)

FixedThreadPoolBulkhead的功能與SemaphoreBulkhead一樣也是用於限制併發執行的次數的,但是二者的實現原理存在差別而且表現效果也存在細微的差別。FixedThreadPoolBulkhead使用一個固定執行緒池和一個等待佇列來實現艙壁。當執行緒池中存在空閒時,則此時進入系統的請求將直接進入執行緒池開啟新執行緒或使用空閒執行緒來處理請求。當執行緒池無空閒時接下來的請求將進入等待佇列,若等待佇列仍然無剩餘空間時接下來的請求將直接被拒絕。在佇列中的請求等待執行緒池出現空閒時,將進入執行緒池進行業務處理。

可以看到FixedThreadPoolBulkhead和SemaphoreBulkhead一個明顯的差別是FixedThreadPoolBulkhead沒有阻塞的概念,而SemaphoreBulkhead沒有一個佇列容量的限制。

限速器(RateLimiter)

img

?原圖地址:限速器(RateLimiter)

限速器(RateLimiter)的功能是防止突然的過量請求導致系統不堪重負,RateLimiter使用一個重新整理週期的概念,限定在一個固定重新整理週期內可處理的最大請求數量。若在某一個重新整理週期內的請求數量已經達到最大,則本週期內接下來的請求將進入阻塞狀態,如果在最大阻塞計時內新的重新整理週期開啟,則阻塞狀態的請求將進入新的週期內進行處理。如最大的阻塞計時內新的重新整理週期並未開啟,則此時超出阻塞計時的那些請求將被直接拒絕。

斷路器(CircuitBreaker)

img

?原圖地址:斷路器(CircuitBreaker)

斷路器(CircuitBreaker)相對於前面幾個熔斷機制更復雜,CircuitBreaker通常存在三種狀態(CLOSE、OPEN、HALF_OPEN),並通過一個時間或數量視窗來記錄當前的請求成功率或慢速率,從而根據這些指標來作出正確的容錯響應。

當CircuitBreaker為CLOSE狀態時客戶端發起的請求將正常進入服務端系統,CircuitBreaker會計算出當前請求前的一個視窗裡所有請求的異常率(失敗率或慢速率),若異常率低於預期配置值,則系統將繼續正常處理接下來的請求。當異常率不低於預期配置值時,此時服務端會進入OPEN狀態,此時服務端將會暫時性的拒絕所有請求。在一段冷卻時間(自定義配置)之後,服務端將自動進入HALF_OPEN狀態,在半開狀態服務端將嘗試接受一定數量的請求(自定義配置),若這一定數量的請求的異常率低於預期,則此時服務端將再次恢復CLOSE狀態,正常處理請求。而如果異常率還是高於預期則會繼續退回到OPEN狀態。

重試(Retry)

img

?原圖地址:重試(Retry)

重試機制比較簡單,當服務端處理客戶端請求異常時,服務端將會開啟重試機制,重試期間內,服務端將每隔一段時間重試業務邏輯處理。 如果最大重試次數內成功處理業務,則停止重試,視為處理成功。如果在最大重試次數內處理業務邏輯依然異常,則此時系統將拒絕該請求。

總結

本文介紹了常用的幾種容錯機制,與其說是resilience4j中的容錯機制不如直接把resilience4j去掉,因為可以看到這些機制原理並不只來源於某個庫或只與某個特定庫有關,它更是一種設計理念,他的通用性應該是跨語言的。此外雖然本文只介紹了這幾種容錯機制,但是如何使用他們完全取決於你的業務場景和架構設計。你甚至可以隨意組合使用它們,並且完全看不出這些組合最後所展示的效果像哪一種機制,那也沒有關係,怎麼使用、怎麼組合完全取決於你所處的技術/業務環境。


??????????????????

歡迎訪問筆者部落格:blog.dongxishaonian.tech

關注筆者公眾號,推送各類原創/優質技術文章 ⬇️

WechatIMG6

相關文章