接上一篇:《Hystrix介紹》
流程圖
下面這幅圖相當重要
稍微解釋一下上面的流程:
- Construct a HystrixCommand or HystrixObservableCommand Object
- Execute the Command
- Is the Response Cached?
- Is the Circuit Open?
- Is the Thread Pool/Queue/Semaphore Full?
- HystrixObservableCommand.construct() or HystrixCommand.run()
- Calculate Circuit Health
- Get the Fallback
- Return the Successful Response
1. 構造一個HystrixCommand或者HystrixObservableCommand對象
第一步是構造一個HystrixCommand或HystrixObservableCommand對象來表示對依賴項的請求。例如:
HystrixCommand command = new HystrixCommand(arg1, arg2); HystrixObservableCommand command = new HystrixObservableCommand(arg1, arg2);
2. 執行命令
你可以用下列四種中的任意一種方式執行命令:
- execute() — 阻塞,直到收到響應或者拋出異常.
- queue() — 返回一個Future
- observe() — 訂閱代表響應的Observable
- toObservable() — 返回一個Observable,當你訂閱它以后,將會執行Hystrix命令並且推送它的響應
execute()方法是同步執行的,它是調用queue().get()
queue()方法是異步執行的,它調用的是toObservable().toBlocking().toFuture()
所以最終每個HystrixCommand都是一個Observable的實現
3. 響應是否已經被緩存?
如果請求在緩存中可用,並且該請求對應的響應在緩存中也是可用的,那么緩存的這個響應將立即以一個Observable的形式被返回
4. 斷路器是否打開?
當你執行命令的時候,Hystrix檢查斷路器是否是開着的。如果是開着的,那么Hystrix不會執行命令,而是路由到第8步執行回退邏輯。如果是關着的,將執行第5步,繼續檢查容量是否可用。
5. 線程池/隊列/信號量是否已經滿了?
如果這個命令所關聯的線程池和隊列(或者信號量)是否滿了,如果是,那么Hystrix不會執行命令,而是立即路由到第8不執行回退邏輯
6. HystrixObservableCommand.construct() or HystrixCommand.run()
我們知道對依賴的調用請求都是封裝成HystrixCommand或者HystrixObservableCommand執行的,而真正執行的邏輯是寫在HystrixObservableCommand.construct()或者HystrixCommand.run()中的:
- HystrixCommand.run() — 返回一個響應或者拋出一個異常
- HystrixObservableCommand.construct() — 返回一個Observable,並且推送響應或者發送一個onError通知
如果在執行run()或者construct()方法超時,那么線程將拋出一個TimeoutException。
7. 計算電路健康
Hystrix報告成功、失敗、拒絕、超時給斷路器,斷路器維護一組計算統計的計數器。
斷路器用這些統計數據來決定什么時候應該“跳閘”,此時后續所有的請求都會被短路,直到一個恢復周期耗盡以后在第一次檢查某些健康檢查之后才會打開電路。
(PS:想象一下生活中的漏電保護器,電壓過高時會自動跳閘,跳閘以后就沒電了,家用電器都用不了了,之后你可以自己不去合上,當然前提是你不能再用那些大功率電器了,於是來電了)
8. 回退
當命令執行失敗時,Hystrix試圖恢復到您的fallback:當run()或者construct()拋出異常;當由於斷路器跳閘導致命令被短路;當命令的線程池或隊列容量滿了;或者當命令執行超時。
在HystrixCommand的情況下,為了提供回退邏輯,你可以實現HystrixCommand.getfallback(),它返回一個單一的回退值。
對於HystrixObservableCommand(),為了提供回退邏輯,你需要實現hystrixobservablecomman.resumewithfallback(),它會返回一個Observable,這個Observable可能返回一個回退值或者多個值。
如果你沒有實現一個fallback方法,或者fallback它自己拋了一個異常,此時Hystrix仍然會返回一個Observable,但是這個Observable什么都不會推送並立即發送一個onError通知。通過這個onError通知,造成命令失敗的異常會傳回給調用者。
9. 返回成功響應
如果Hystrix命令成功,它會返回響應給調用者,或者返回一個Observable。這取決於在第2步的時候你是如果調用命令的。
Circuit Breaker(斷路器)
下圖顯示了HystrixCommand或HystrixObservableCommand是如何與HystrixCircuitBreaker交互的,以及它的邏輯和決策流程,包括斷路器中計數器的行為。
上面的流程可以這樣描述:
- 假設整個電路的體積達到一定的閾值
- 假設錯誤百分比超過設定的錯誤百分比閾值
- 斷路器從CLOSED變成OPEN
- 當它打開時,經過這個斷路器的所有請求被短路
- 過了一段時間以后,下一個單個請求被允許通過(此時是半打開狀態)。如果這個請求失敗,在接下來的睡眠窗口期間斷路器保持OPEN狀態;如果這個請求成功,斷路器轉成CLOSED狀態;然后繼續執行第1步,如此反復。
隔離
Hystrix使用隔板模式來隔離彼此的依賴關系,並限制對其中任何一個的並發訪問。
線程和線程池
Hystrix使用獨立的、每個依賴項的線程池作為約束任何給定依賴項的一種方式,因此底層執行的延遲只會使該池中的可用線程飽和。
線程池的好處
- 應用程序被完全保護而不受失控的客戶端的影響。給定的依賴項的線程池可以填滿,而不會影響應用程序的其余部分。
- 應用程序可以接收新的客戶端請求
- 當失敗的客戶端再次恢復正常時,線程池將被清理,應用程序將立即恢復正常的性能
- 如果一個客戶端配置錯誤,線程池的健康將會很快地證明這一點(通過增加錯誤、延遲、超時、拒絕等),並且您可以處理它(通常是通過動態屬性進行實時處理),而不會影響應用程序的功能。
Semaphores(信號量)
你可以用信號量(或者計數器)來限制對任意依賴項並發調用的數量,代替用線程池的大小。
HystrixCommand 和 HystrixObservableCommand 在兩個地方支持用信號量:
- Fallback:當Hystrix恢復fallbacks時它總是調用Tomcat的線程這樣做
- Execution:如果設置屬性execution.isolation.strategy為SEMAPHORE,那么,Hystrix將使用信號量而不是線程來限制調用該命令的發父線程的並數量。
https://github.com/Netflix/Hystrix/wiki/How-it-Works