一、hystrix的作用
- 控制被依賴服務的延時和失敗
- 防止在復雜系統中的級聯失敗
- 可以進行快速失敗(不需要等待)和快速恢復(當依賴服務失效后又恢復正常,其對應的線程池會被清理干凈,即剩下的都是未使用的線程,相對於整個 Tomcat 容器的線程池被占滿需要耗費更長時間以恢復可用來說,此時系統可以快速恢復)
- getFallback(失敗時指定的操作)和優雅降級
- 實現近實時的檢測、報警、運維
二、hystrix實現中需要注意的點
- 為每一個依賴服務維護一個線程池(或者信號量),當線程池占滿+queueSizeRejectionThreshold占滿,該依賴服務將會立即拒絕服務而不是排隊等待
- 引入『熔斷器』機制,在依賴服務失效比例超過閾值時,手動或者自動地切斷服務一段時間
- 當請求依賴服務時出現拒絕服務、超時或者短路(多個依賴服務順序請求,前面的依賴服務請求失敗,則后面的請求不會發出)時,執行該依賴服務的失敗回退邏輯
三、hystrix線程模型
- 為每一個服務提供一個線程池,線程池數量可以配置。(每個Netflix API實例有超過 40 個線程池,每個線程池有 5 到 20 個工作線程(絕大部分設置為 10 個線程))
- 注意:如果不特殊指定ThreadPool,則commandGroupKey就是ThreadPool的配置。By default Hystrix uses this to define the command thread-pool unless a separate one is defined。
- 每個依賴服務都被隔離開來,Hystrix 會嚴格控制其在延遲發生時對資源的占用,並在任何失效發生時,執行失敗回退邏輯
- 注意:隔離是非常好的,隔離后,延時的被調用服務只會耗盡自己的線程池,之后進入失敗,見下圖(附:清晰大圖);如果不隔離,可能會耗盡整個tomcat的線程池,導致整個系統癱瘓。
- tomcat線程(即調用線程)將請求接過來后,交給被依賴服務自己的線程池中的線程去執行(此時調用線程就可以去做其他的事情了,這與mina2的線程模型有相似之處)
四、hystrix執行流程(工作機理)
附:清晰大圖
步驟:(配合上圖去看)
1、構建HystrixCommand或者HystrixObservableCommand對象
2、執行命令(execute()、queue()、observe())
3、如果請求結果緩存這個特性被啟用,並且緩存命中,則緩存的回應會立即通過一個 Observable
對象的形式返回。
4、檢查熔斷器狀態,確定請求線路是否是開路,如果請求線路是開路,Hystrix 將不會執行這個命令,而是直接使用『失敗回退邏輯』(即不會執行run(),直接執行getFallback())
5、如果和當前需要執行的命令相關聯的線程池和請求隊列(或者信號量,如果不使用線程池)滿了,Hystrix 將不會執行這個命令,而是直接使用『失敗回退邏輯』(即不會執行run(),直接執行getFallback())
6、執行HystrixCommand.run()或HystrixObservableCommand.construct(),如果這兩個方法執行超時或者執行失敗,則執行getFallback();如果正常結束,Hystrix 在添加一些日志和監控數據采集之后,直接返回
回應
7、Hystrix 會將請求成功,失敗,被拒絕或超時信息報告給熔斷器,熔斷器維護一些用於統計數據用的計數器。
這些計數器產生的統計數據使得熔斷器在特定的時刻,能短路某個依賴服務的后續請求,直到恢復期結束,若恢復期結束根據統計數據熔斷器判定線路仍然未恢復健康,熔斷器會再次關閉線路。
五、熔斷器執行流程(工作機理)
附:清晰大圖
1、假設線路內的容量(請求QPS)達到一定閾值(通過 HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()
配置),同時,假設線路內的錯誤率達到一定閾值(通過 HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()
配置)
2、熔斷器將從『閉路』轉換成『開路』
3、若此時是『開路』狀態,熔斷器將短路后續所有經過該熔斷器的請求,這些請求直接走『失敗回退邏輯』(即不走run(),直接走getFallback())
4、經過一定時間(即『休眠窗口』,通過 HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()
配置),后續第一個請求將會被允許通過熔斷器(此時熔斷器處於『半開』狀態),若該請求失敗,熔斷器將又進入『開路』狀態,且在休眠窗口內保持此狀態;若該請求成功,熔斷器將進入『閉路』狀態,回到邏輯1循環往復。
六、線程池與信號量
使用場景:對於那些本來延遲就比較小的請求(例如訪問本地緩存成功率很高的請求)來說,線程池帶來的開銷是非常高的,這時,你可以考慮采用其他方法,例如非阻塞信號量(不支持超時),來實現依賴服務的隔離,使用信號量的開銷很小。但絕大多數情況下,Netflix 更偏向於使用線程池來隔離依賴服務,因為其帶來的額外開銷可以接受,並且能支持包括超時在內的所有功能。
如果你對客戶端庫有足夠的信任(延遲不會過高),並且你只需要控制系統負載,那么你可以使用信號量。
七、請求合並
參考:
https://github.com/Netflix/Hystrix/wiki
http://youdang.github.io/categories/%E7%BF%BB%E8%AF%91/ 對官網翻譯的非常好,可惜沒有翻譯完