Netflix Hystrix 是如何運行的

項目地址:Netflix Hystrix Github
文章譯自:Hystrix/wiki/How-it-Works
閱讀本文章前,請先了解 Hystrix 的一些基本概念( What is Hystrix )。

流程圖

下圖展示了當使用 Hystrix 構造請求,請求到一個服務依賴項時所發生的流程:
hystrix 運行流程圖
下面部分將更詳細地解釋上述流程:
  1. 構造一個 HystrixCommand 或 HystrixObservableCommand 對象
  2. 執行 Command
  3. 是否緩存 Response
  4. 斷路器是否打開
  5. 線程池 / 隊列 / 信號量 是否已
  6. 執行 HystrixObservableCommand.construct() 或 HystrixCommand.run()
  7. 計算線路健康狀況
  8. 獲取回調
  9. 返回成功的 Response

1. 構造一個 HystrixCommand 或 HystrixObservableCommand 對象

第一步就是構造一個 HystrixCommand 或 HystrixObservableCommand 對象,**Command 對象代表對依賴項的請求。傳遞構造函數在請求發生時所需要的各個參數。

當依賴項預計會返回一個Response時,構造一個 HystrixCommand 對象,如:

HystrixCommand command = new HystrixCommand(arg1, arg2);

當依賴項預計會返回一個可傳播 Response 的 Observable 時(rxJava),構造一個 HystrixObservableCommand 對象,如:

HystrixObservableCommand command = new HystrixObservableCommand(arg1, arg2);

2. 執行 Command

執行命令有如下四種方式,可以選擇一種方法去執行 Hystrix 的 Command 對象(第一,二個方法只適合簡單的命令對象 HystrixCommand 執行,不適合 HystrixObservableCommand 對象):

  • execute()——阻塞,返回從依賴項接收到的響應(或有異常時拋出異常)
  • queue()——返回一個 java.util.concurrent.Future,可以通過 Future.get()來獲取一個依賴項返回的響應
  • observe()——訂閱 Observable(這個 Observable 代表從依賴項返回的響應),並返回複製該源 Observable 的 Observable
  • toObservable()——返回一個 Observable,當這個 Observable 被訂閱時,將會執行對應的 Hystrix 的 Command 對象,並且傳播返回的響應
K              value   = command.execute();
Future<K>      fValue  = command.queue();
Observable<K>  ohValue = command.observe();         //hot observable
Observable<K>  ocValue = command.toObservable();    //cold observable

同步調用方法execute()實際上調用的是 queue().get()queue()反過來調用toObservable().toBlocking().toFuture(),也就是說所有的 HystrixCommand 的調用最終都是通過 Observable 來實現(netflix 的 oss 項目中大量使用了 rxJava),即使這些命令只是想返回單個值或者一些簡單的值。

3. 是否緩存 Response

如果一個 Hystrix Command 的請求緩存被啓用了,並且這個請求的響應在緩存中可用,那麼這個被緩存的響應將會立即以 Observable 的形式返回(更詳細看下面的“請求緩存”部分)。

4. 斷路器是否開啓

當執行一個命令,Hystrix 會檢查斷路器(circuit-breaker)確認斷路器是否是開啓狀態。

如果斷路器是開啓狀態(或者“跳閘”),那麼 Hystrix 將不會執行這些命令,這些失敗的命令將會被路由到回調邏輯進行後續處理。

如果斷路器是關閉狀態,那麼執行流程將往下走到第5步:檢查是否有足夠的容量來運行該命令

5. 線程池 / 隊列 / 信號量 是否已滿

Hystrix 的執行隔離策略有兩種:Thread 和 Semaphore

如果命令相關聯的線程池和隊列(不是線程模式時,判斷依據爲信號量)已滿,那麼 Hystrix 將不會執行命令,這些失敗的命令也會被路由到回調邏輯進行後續處理。

6. 執行 Command 中的業務邏輯

到這裏,Hystrix 調用對依賴項的這些請求,方式如下:

  • HystrixCommand.run()——返回單個響應或拋出異常
  • HystrixObservableCommand.construct()——返回 Observable 傳播收到的響應或者發送一個 onError的通知
    如果run()construct()方法執行時長超過了命令的超時閥值,其線程將拋出一個TimeoutException(或者在一個單獨的線程拋出,如果命令沒有運行在它自己的線程)。這種情況下 Hystrix 將路由響應到第8步,獲取回調邏輯;並且如果該方法沒有取消或中斷,它將放棄run()construct()方法最終的返回值。

請注意,沒有辦法強制地停止延遲線程——Hystrix 能做的就是在 JVM 上拋出一個 InterruptedException。如果由 Hystrix 包裝過的邏輯沒有注意處理 InterruptedExceptions,則 Hystrix 線程池中的線程將會繼續運行,即使客戶端已收到TimeoutException。這種行爲會填滿 Hystrix 對應命令的線程池,儘管負載是“correctly shed”。很多 Java Http Client 庫沒有說明InterruptedExceptions,因此請確保在HTTP客戶端上正確配置連接和讀/寫的超時時長。

如果命令沒有拋出異常並且返回了響應,Hystrix 將會在執行一些日誌記錄和度量報告之後返回響應給調用者。如果是通過run()運行,Hystrix 將返回 Observable 傳播單個響應,然後發送一個onCompleted的通知;如果是通過construct()運行,Hystrix 返回與construct()返回的相同的Observable。

7. 計算線路健康狀況

Hystrix 向斷路器報告成功,失敗,拒絕和超時的數據,斷路器維持一組實時跳動的計數器來統計數據。(HystrixCommandMetrics)

斷路器使用這些統計數據來確定電路何時應該“跳閘”,什麼時候該將所有後續的請求短路,直到恢復期過去,並在首次檢查某些健康檢查後會再次關閉電路。

8. 獲取回調

當命令執行失敗時,Hystrix 會試圖恢復到 fallback 狀態:當執行construct()run()時拋出異常(第6步);當命令因爲斷路器跳閘而短路時(第4步);當該命令的線程池隊列或信號量滿時(第5步),或者當命令執行時長超過閥值時。

編寫回調邏輯提供一個通用的響應,以便在不存在任何網絡依賴項或者所有依賴項都失效時,能夠從內存中的緩存中或其他靜態邏輯中獲取一個通用的響應(不至於在單個或多個依賴項失效時,產生連鎖反應帶崩整個應用)。如果必須在回調邏輯中使用網絡請求,應該通過另一個HystrixCommand 或 HystrixObservableCommand 來完成。

在 HystrixCommand 中,在 HystrixCommand.getFallback()方法中提供自定義的回調邏輯,方法返回單個回調值。

在 HystrixObservableCommand 中,在HystrixObservableCommand.resumeWithFallback() 方法中提供自定義的回調邏輯,方法返回一個 可傳播回調值的 Observable。

如果回調方法返回了響應,Hystrix 會將該響應返回給調用者。在 HystrixCommand 中,Hystrix 返回給調用者一個可傳播響應值的 Observable;在 HystrixObservableCommand 中,Hystrix 將直接返回resumeWithFallback()返回的 Observable 對象。

如果沒有爲 Hystrix 的命令提供回調邏輯,或者回調邏輯會拋出異常,Hystrix 仍然會返回一個 Observable 對象,但是沒有傳播值並且會立即終止傳播,併發送一個onError通知。正是這個onError的通知會將導致命令失敗的異常信息返回給調用者。(用戶提供可能會失敗的回調邏輯是一個很不好的做法,用戶應該提供沒有任何可能執行失敗的回調邏輯)

根據調用 Hystrix 命令方式的不同,失敗時或不存在依賴項時的回調結果也會有所不同:

  • execute()——拋出異常
  • queue()——成功時返回java.util.concurrent.Future,但如果調用 Future.get()將拋出異常
  • observe()——返回 Observable 對象,當你訂閱該 Observable 時,將會立即終止並且調用訂閱者的onError方法
  • toObservable()——同observe()

9. 返回成功的 Response

如果 Hystrix 命令執行成功,那麼將以 Observable 的形式返回單個響應或多個響應給調用者。取決於上面第2步執行命令的方式不同,返回的 Observable 在返回給你之前會通過以下方式傳播:
Observable Transformed
- execute()——和queue()獲取的方式一樣獲取一個 Future,然後通過Future.get()方法通過 Obsevable 獲取返回的單個值
- queue()——將 Observable 轉換成 BlockingObservable,以便可以轉換成Future並返回
- observe()——快速訂閱返回的 Observable 並開始執行訂閱命令的流程;返回 Observable,當被訂閱時可以重新傳播和重新通知
- toObservable()——返回相同的 Observable;用戶必須訂閱它才能真正開始執行訂閱命令的流程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章