一:為什麼需要Hystrix?
在大中型分布式系統中,通常系統很多依賴(HTTP,hession,Netty,Dubbo等),如下圖:
在高并發通路下,這些依賴的穩定性與否對系統的影響非常大,但是依賴有很多不可控問題:如網絡連接配接緩慢,資源繁忙,暫時不可用,服務脫機等.
如下圖:QPS為50的依賴 I 出現不可用,但是其他依賴仍然可用.
當依賴I 阻塞時,大多數伺服器的線程池就出現阻塞(BLOCK),影響整個線上服務的穩定性.如下圖:
在複雜的分布式架構的應用程式有很多的依賴,都會不可避免地在某些時候失敗。高并發的依賴失敗時如果沒有隔離措施,目前應用服務就有被拖垮的風險。
例如:
一個依賴30個SOA服務的系統,每個服務99.99%可用。
99.99%的30次方 ≈ 99.7%
0.3% 意味着一億次請求 會有 3,000,00次失敗
換算成時間大約每月有2個小時服務不穩定.
随着服務依賴數量的變多,服務不穩定的機率會成指數性提高.
解決問題方案:對依賴做隔離,Hystrix就是處理依賴隔離的架構,同時也是可以幫我們做依賴服務的治理和監控.
Netflix 公司開發并成功使用Hystrix,使用規模如下:
1 2 | |
二:Hystrix如何解決依賴隔離
1:Hystrix使用指令模式HystrixCommand(Command)包裝依賴調用邏輯,每個指令在單獨線程中/信号授權下執行。
2:可配置依賴調用逾時時間,逾時時間一般設為比99.5%平均時間略高即可.當調用逾時時,直接傳回或執行fallback邏輯。
3:為每個依賴提供一個小的線程池(或信号),如果線程池已滿調用将被立即拒絕,預設不采用排隊.加速失敗判定時間。
4:依賴調用結果分:成功,失敗(抛出異常),逾時,線程拒絕,短路。 請求失敗(異常,拒絕,逾時,短路)時執行fallback(降級)邏輯。
5:提供熔斷器元件,可以自動運作或手動調用,停止目前依賴一段時間(10秒),熔斷器預設錯誤率門檻值為50%,超過将自動運作。
6:提供近實時依賴的統計和監控
Hystrix依賴的隔離架構,如下圖:
三:如何使用Hystrix
1:使用maven引入Hystrix依賴
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
2:使用指令模式封裝依賴邏輯
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
note:異步調用使用 command.queue()get(timeout, TimeUnit.MILLISECONDS);同步調用使用command.execute() 等同于 command.queue().get();
3:注冊異步事件回調執行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
4:使用Fallback() 提供降級政策
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
NOTE: 除了HystrixBadRequestException異常之外,所有從run()方法抛出的異常都算作失敗,并觸發降級getFallback()和斷路器邏輯。
HystrixBadRequestException用在非法參數或非系統故障異常等不應觸發回退邏輯的場景。
5:依賴命名:CommandKey
1 2 3 4 5 6 | |
NOTE: 每個CommandKey代表一個依賴抽象,相同的依賴要使用相同的CommandKey名稱。依賴隔離的根本就是對相同CommandKey的依賴做隔離.
6:依賴分組:CommandGroup
指令分組用于對依賴操作分組,便于統計,彙總等.
1 2 3 4 | |
NOTE: CommandGroup是每個指令最少配置的必選參數,在不指定ThreadPoolKey的情況下,字面值用于對不同依賴的線程池/信号區分.
7:線程池/信号:ThreadPoolKey
1 2 3 4 5 6 7 | |
NOTE: 當對同一業務依賴做隔離時使用CommandGroup做區分,但是對同一依賴的不同遠端調用如(一個是redis 一個是http),可以使用HystrixThreadPoolKey做隔離區分.
最然在業務上都是相同的組,但是需要在資源上做隔離時,可以使用HystrixThreadPoolKey區分.
8:請求緩存 Request-Cache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | |
NOTE:請求緩存可以讓(CommandKey/CommandGroup)相同的情況下,直接共享結果,降低依賴調用次數,在高并發和CacheKey碰撞率高場景下可以提升性能.
Servlet容器中,可以直接實用Filter機制Hystrix請求上下文
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 | |
10:fallback降級邏輯指令嵌套
适用場景:用于fallback邏輯涉及網絡通路的情況,如緩存通路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | |
NOTE:依賴調用和降級調用使用不同的線程池做隔離,防止上層線程池跑滿,影響二級降級邏輯調用.
11:顯示調用fallback邏輯,用于特殊業務處理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | |
NOTE:顯示調用降級适用于特殊需求的場景,fallback用于業務處理,fallback不再承擔降級職責,建議慎重使用,會造成監控統計換亂等問題.
12:指令調用合并:HystrixCollapser
指令調用合并允許多個請求合并到一個線程/信号下批量執行。
執行流程圖如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
NOTE:使用場景:HystrixCollapser用于對多個相同業務的請求合并到一個線程甚至可以合并到一個連接配接中執行,降低線程互動次和IO數,但必須保證他們屬于同一依賴.
四:監控平台搭建Hystrix-dashboard
1:監控dashboard介紹
dashboard面闆可以對依賴關鍵名額提供實時監控,如下圖:
2:執行個體暴露command統計資料
Hystrix使用Servlet對目前JVM下所有command調用情況作資料流輸出
配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 | |
3:叢集模式監控統計搭建
1)使用Turbine元件做叢集資料彙總
結構圖如下:
2)内嵌jetty提供Servlet容器,暴露HystrixMetrics
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
3)Turbine搭建和配置
a:配置Turbine Servlet收集器
1 2 3 4 5 6 7 8 9 10 | |
b:編寫config.properties配置叢集執行個體
1 2 3 4 5 6 7 8 9 | |
c:使用Dashboard配置連接配接Turbine
如下圖 :
五:Hystrix配置與分析
1:Hystrix 配置
1):Command 配置
Command配置源碼在HystrixCommandProperties,構造Command時通過Setter進行配置
具體配置解釋和預設值如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
2):熔斷器(Circuit Breaker)配置
Circuit Breaker配置源碼在HystrixCommandProperties,構造Command時通過Setter進行配置,每種依賴使用一個Circuit Breaker
1 2 3 4 5 6 7 8 9 10 11 12 | |
3):指令合并(Collapser)配置
Command配置源碼在HystrixCollapserProperties,構造Collapser時通過Setter進行配置
1 2 3 4 5 6 | |
4):線程池(ThreadPool)配置
1 2 3 4 5 6 7 8 9 10 11 | |
2:Hystrix關鍵元件分析
1):Hystrix流程結構解析
流程說明:
1:每次調用建立一個新的HystrixCommand,把依賴調用封裝在run()方法中.
2:執行execute()/queue做同步或異步調用.
3:判斷熔斷器(circuit-breaker)是否打開,如果打開跳到步驟8,進行降級政策,如果關閉進入步驟.
4:判斷線程池/隊列/信号量是否跑滿,如果跑滿進入降級步驟8,否則繼續後續步驟.
5:調用HystrixCommand的run方法.運作依賴邏輯
5a:依賴邏輯調用逾時,進入步驟8.
6:判斷邏輯是否調用成功
6a:傳回成功調用結果
6b:調用出錯,進入步驟8.
7:計算熔斷器狀态,所有的運作狀态(成功, 失敗, 拒絕,逾時)上報給熔斷器,用于統計進而判斷熔斷器狀态.
8:getFallback()降級邏輯.
以下四種情況将觸發getFallback調用:
(1):run()方法抛出非HystrixBadRequestException異常。
(2):run()方法調用逾時
(3):熔斷器開啟攔截調用
(4):線程池/隊列/信号量是否跑滿
8a:沒有實作getFallback的Command将直接抛出異常
8b:fallback降級邏輯調用成功直接傳回
8c:降級邏輯調用失敗抛出異常
9:傳回執行成功結果
2):熔斷器:Circuit Breaker
Circuit Breaker 流程架構和統計
每個熔斷器預設維護10個bucket,每秒一個bucket,每個blucket記錄成功,失敗,逾時,拒絕的狀态,
預設錯誤超過50%且10秒内超過20個請求進行中斷攔截.
3)隔離(Isolation)分析
Hystrix隔離方式采用線程/信号的方式,通過隔離限制依賴的并發量和阻塞擴散.
(1):線程隔離
把執行依賴代碼的線程與請求線程(如:jetty線程)分離,請求線程可以自由控制離開的時間(異步過程)。
通過線程池大小可以控制并發量,當線程池飽和時可以提前拒絕服務,防止依賴問題擴散。
線上建議線程池不要設定過大,否則大量堵塞線程有可能會拖慢伺服器。
(2):線程隔離的優缺點
線程隔離的優點:
[1]:使用線程可以完全隔離第三方代碼,請求線程可以快速放回。
[2]:當一個失敗的依賴再次變成可用時,線程池将清理,并立即恢複可用,而不是一個長時間的恢複。
[3]:可以完全模拟異步調用,友善異步程式設計。
線程隔離的缺點:
[1]:線程池的主要缺點是它增加了cpu,因為每個指令的執行涉及到排隊(預設使用SynchronousQueue避免排隊),排程和上下文切換。
[2]:對使用ThreadLocal等依賴線程狀态的代碼增加複雜性,需要手動傳遞和清理線程狀态。
NOTE: Netflix公司内部認為線程隔離開銷足夠小,不會造成重大的成本或性能的影響。
Netflix 内部API 每天100億的HystrixCommand依賴請求使用線程隔,每個應用大約40多個線程池,每個線程池大約5-20個線程。
(3):信号隔離
信号隔離也可以用于限制并發通路,防止阻塞擴散, 與線程隔離最大不同在于執行依賴代碼的線程依然是請求線程(該線程需要通過信号申請),
如果用戶端是可信的且可以快速傳回,可以使用信号隔離替換線程隔離,降低開銷.
線程隔離與信号隔離差別如下圖:
解析圖檔出自官網wiki , 更多内容請見官網: https://github.com/Netflix/Hystrix
原文連結:http://hot66hot.iteye.com/blog/2155036