引言
今天和大家聊一聊在Spring Cloud微服務框架實踐中,比較核心但是又很容易把人搞得稀裏糊塗的一個問題,那就是在Spring Cloud中Hystrix、Ribbon以及Feign它們三者之間在處理微服務調用超時從而觸發熔斷降級的關係是什麼?
我們知道在Spring Cloud微服務體系下,微服務之間的互相調用可以通過Feign進行聲明式調用,在這個服務調用過程中Feign會通過Ribbon從服務註冊中心獲取目標微服務的服務器地址列表,之後在網絡請求的過程中Ribbon就會將請求以負載均衡的方式打到微服務的不同實例上,從而實現Spring Cloud微服務架構中最爲關鍵的功能即服務發現及客戶端負載均衡調用。
另一方面微服務在互相調用的過程中,爲了防止某個微服務的故障消耗掉整個系統所有微服務的連接資源,所以在實施微服務調用的過程中我們會要求在調用方實施針對被調用微服務的熔斷邏輯。而要實現這個邏輯場景在Spring Cloud微服務框架下我們是通過Hystrix這個框架來實現的。
調用方會針對被調用微服務設置調用超時時間,一旦超時就會進入熔斷邏輯,而這個故障指標信息也會返回給Hystrix組件,Hystrix組件會根據熔斷情況判斷被調微服務的故障情況從而打開熔斷器,之後所有針對該微服務的請求就會直接進入熔斷邏輯,直到被調微服務故障恢復,Hystrix斷路器關閉爲止。
Hystrix、Feign及Ribbon的配置說明
接下來我們先來看看在Spring Cloud微服務系統中Hystrix、Feign及Ribbon的常用配置都有哪些以及它們的使用場景分別是什麼?
Hystrix配置說明
在Spring Cloud微服務體系中Hystrix主要被用於實現實現微服務之間網絡調用故障的熔斷、過載保護及資源隔離等功能。而要正確使用Hystrix提供的這些功能就需要對Hystrix常用的配置有一定深入的瞭解,否則你會發現使用過程中認爲一定會生效的配置常常不會起作用,接下來我們就按照參數配置的類型對Hystrix中的常見配置做一個梳理。
1)、線程隔離相關配置
Hystrix具備的重要關鍵特性之一就是它能夠實現對第三方服務依賴的資源隔離,而隔離最常見的方式是通過線程池資源的隔離來實現的,Hystrix會爲每個第三方服務依賴配置單獨的線程池資源,從而避免對第三方服務依賴的請求佔用應用主線程資源以免造成系統雪崩。Hystrix中關於線程隔離相關的配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
hystrix:
command:
#全局默認配置
default :
#線程隔離相關
execution:
timeout:
#是否給方法執行設置超時時間,默認爲 true 。一般我們不要改。
enabled: true
isolation:
#配置請求隔離的方式,這裏是默認的線程池方式。還有一種信號量的方式semaphore,使用比較少。
strategy: threadPool
thread:
#方式執行的超時時間,默認爲 1000 毫秒,在實際場景中需要根據情況設置
timeoutInMilliseconds: 1000
#發生超時時是否中斷方法的執行,默認值爲 true 。不要改。
interruptOnTimeout: true
#是否在方法執行被取消時中斷方法,默認值爲 false 。沒有實際意義,默認就好!
interruptOnCancel: false
|
2)、熔斷器相關配置
熔斷器是Hystrix最主要的功能,它開啓和關閉的時機、靈敏度及準確性是Hystrix是否能夠發揮重要的關鍵,而在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
|
hystrix:
command:
#全局默認配置
default :
#熔斷器相關配置
circuitBreaker:
#說明:是否啓動熔斷器,默認爲 true 。我們使用Hystrix的目的就是爲了熔斷器,不要改,否則就不要引入Hystrix。
enabled: true
#說明 1 :啓用熔斷器功能窗口時間內的最小請求數,假設我們設置的窗口時間爲 10 秒,
#說明 2 :那麼如果此時默認值爲 20 的話,那麼即便 10 秒內有 19 個請求都失敗也不會打開熔斷器。
#說明 3 :此配置項需要根據接口的QPS進行計算,值太小會有誤打開熔斷器的可能,而如果值太大超出了時間窗口內的總請求數,則熔斷永遠也不會被觸發
#說明 4 :建議設置一般爲:QPS*窗口描述* 60 %
requestVolumeThreshold: 20
#說明 1 :熔斷器被打開後,所有的請求都會被快速失敗掉,但是何時恢復服務是一個問題。熔斷器打開後,Hystrix會在經過一段時間後就放行一條請求
#說明 2 :如果請求能夠執行成功,則說明此時服務可能已經恢復了正常,那麼熔斷器會關閉;相反執行失敗,則認爲服務仍然不可用,熔斷器保持打開。
#說明 3 :所以此配置的作用是指定熔斷器打開後多長時間內允許一次請求嘗試執行,官方默認配置爲 5 秒。
sleepWindowInMilliseconds: 5000
#說明 1 :該配置是指在通過滑動窗口獲取到當前時間段內Hystrix方法執行失敗的機率後,根據此配置來判斷是否需要打開熔斷器
#說明 2 :這裏官方的默認配置爲 50 ,即窗口時間內超過 50 %的請求失敗後就會打開熔斷器將後續請求快速失敗掉
errorThresholdPercentage: 50
#說明:是否強制啓用熔斷器,默認 false ,沒有什麼場景需要這麼配置,忽略!
forceOpen: false
#說明:是否強制關閉熔斷器,默認 false ,沒有什麼場景需要這麼配置,忽略!
forceClosed: false
|
3)、Metrics(統計器)相關配置
Hystrix是否正常工作最主要的依賴就是根據捕獲的調用指標信息來判斷是否打開或者關閉熔斷器,而影響Hystrix行爲很重要的因素就是以下Hystrix關於Metrics的配置。
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
|
hystrix:
command:
#全局默認配置
default :
metrics:
rollingStats:
#說明:此配置用於設置Hystrix統計滑動窗口的時間,單位爲毫秒,默認設置爲 10000 毫秒,即一個滑動窗口默認統計的是 10 秒內的請求數據。
timeInMilliseconds: 10000
#說明 2 :此屬性指定了滑動統計窗口劃分的桶數。默認爲 10 。
#說明 2 :需要注意的是,metrics.rollingStats.timeInMilliseconds % metrics.rollingStats.numBuckets == 0 必須成立,否則就會拋出異常
numBuckets: 10
rollingPercentile:
#說明 1 :此屬性配置統計方法是否響應時間百分比,默認爲 true 。
#說明 2 :Hystrix會統計方法執行 1 %, 10 %, 50 %, 90 %, 99 %等比例請求的平均耗時用來生成統計圖表。
#說明 3 :如果禁用該參數設置 false ,那麼所有彙總統計信息(平均值、百分位數)將返回- 1 。
enabled: true
#說明:統計響應時間百分比時的窗口大小,默認爲 60000 毫秒,即 1 分鐘
timeInMilliseconds: 60000
#說明 1 :此屬性用於設置滑動百分比窗口要劃分的桶數,默認爲 6 。
#說明 2 :需要注意的是,metrics.rollingPercentile.timeInMilliseconds % metrics.rollingPercentile.numBuckets == 0 必須成立,否則會拋出異常
numBuckets: 6
#說明 1 :該屬性表示統計響應時間百分比,每個滑動窗口的桶內要保存的請求數,默認爲 100 。
#說明 2 :即默認 10 秒的桶內,如果執行了 500 次請求,那麼只有最後 100 次請求執行的信息會被保存到桶內。
#說明 3 :增加這個值會增加內存消耗量,一般情況下無需更改。
bucketSize: 100
healthSnapshot:
#說明 1 :該參數配置了健康數據統計器(會影響Hystrix熔斷)中每個桶的大小,默認爲 500 毫秒。
#說明 2 :在統計時Hystrix通過metrics.rollingStats.timeInMilliseconds / metrics.healthSnapshot.intervalInMilliseconds計算出桶數。
#說明 3 :在窗口滑動時,每滑過一個桶的時間就統計一次當前窗口內請求的失敗率。
intervalInMilliseconds: 500
|
在上述關於Metrics的配置中出現了兩個比較頻繁的概念:滑動窗口、桶,Hystrix的統計器就是由滑動窗口來實現的。關於滑動窗口舉一個非常形象的例子,假設你坐在一輛大巴車的上,車窗外是一排排筆直的大樹,車輛在高速地行駛着,大樹迅速地從車窗滑過,如果用每棵樹來代表一個網絡請求,用大巴車的行駛代表時間的流逝。那麼大巴車的窗口就是一個非常典型的滑動窗口,而你通過這個車窗能夠看到的大樹就是Hystrix要統計的數據。
桶(bucket)是Hystrix統計滑動窗口數據時的最小單位。同樣以上面的例子爲例,在大巴車行駛非常快的情況下,如果每掠過一棵樹就統計一次窗口內大樹的數據的話,會造成比較大的開銷,而如果我們將車窗分成10份,大巴車行駛時每掠過窗口的1/10就統計一次數據,那麼開銷就會小很多了。所以,Hystrix中的桶就是滑動窗口1/N的概念。
4)、線程池相關配置
在前面提到過Hystrix實現對第三方服務依賴資源隔離最主要的方式就是通過線程池,而Hystrix內線程的使用是基於Java內置線程池的簡單封裝,通過以下Hystrix線程池參數我們可以控制執行Hystrix命令的線程池的行爲。具體如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
hystrix:
command:
default :
#說明:核心線程池的大小,默認值是 10
coreSize: 10
#說明:是否允許線程池擴展到最大線程池數量,默認爲 false 。
allowMaximumSizeToDivergeFromCoreSize: false
#說明:線程池中線程的最大數量,默認值是 10 。此配置項單獨配置時並不會生效,需要啓用allowMaximumSizeToDivergeFromCoreSize
maximumSize: 10
#說明 1 :作業隊列的最大值,默認值爲- 1 。表示隊列會使用SynchronousQueue,此時值爲 0 ,Hystrix不會向隊列內存放作業。
#說明 2 :如果此值設置爲一個正 int 型,隊列會使用一個固定size的LinkedBlockingQueue,此時在覈心線程池都忙碌的情況下,會將作業暫時存放在此隊列內,但是超出此隊列的請求依然會被拒絕
maxQueueSize: - 1
#設置隊列拒絕請求的閥值,默認爲 5 。
queueSizeRejectionThreshold: 5
#控制線程在釋放前未使用的時間,默認爲 1 分鐘。
keepAliveTimeMinutes: 1
|
Ribbon配置說明
Ribbon在Spring Cloud中對於支持微服之間的通信發揮着非常關鍵的作用,其主要功能包括客戶端負載均衡器及用於中間層通信的客戶端。在基於Feign的微服務通信中無論是否開啓Hystrix,Ribbon都是必不可少的,Ribbon的配置參數主要如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
ribbon:
#說明:同一臺實例的最大自動重試次數,默認爲 1 次,不包括首次
MaxAutoRetries: 1
#說明:要重試的下一個實例的最大數量,默認爲 1 ,不包括第一次被調用的實例
MaxAutoRetriesNextServer: 1
#說明:是否所有的操作都重試,默認爲 true
OkToRetryOnAllOperations: true
#說明:從註冊中心刷新服務器列表信息的時間間隔,默認爲 2000 毫秒,即 2 秒
ServerListRefreshInterval: 2000
#說明:使用Apache HttpClient連接超時時間,單位爲毫秒
ConnectTimeout: 3000
#說明:使用Apache HttpClient讀取的超時時間,單位爲毫秒
ReadTimeout: 3000
#說明:初始服務器列表,不需要手工配置,在運行時動態根據註冊中心更新
listOfServers: www.microsoft.com: 80 ,www.yahoo.com: 80 ,www.google.com: 80
|
以上配置方式將對所有的微服務調用有效,如果想針對單獨的微服務進行配置,使用“微服務名.ribbon”這樣的配置方式即可,例如:
1
2
3
4
5
6
|
bike:
ribbon:
ReadTimeout: 30000
operation:
ribbon:
ReadTimeout: 30000
|
Feign配置說明
Feign是一款Java語言編寫的HttpClient綁定器,在Spring Cloud微服務中用於實現微服務之間的聲明式調用,Feign自身可以支持多種HttpClient工具包,例如OkHttp及Apache HttpClient,針對不同的HttpClient其默認常見配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
feign:
hystrix:
enabled: true
client:
config:
#JDK默認HttpURLConnection 實現的 Http Client配置
default :
#連接超時時間
connectTimeout: 5000
#讀取超時時間
readTimeout: 5000
#錯誤解碼器
errorDecoder: com.wudimanong.client.common.FeignClientErrorDecoder
#解碼器
encoder: com.wudimanong.client.common.FeignClientEncoder
#編碼器
decoder: com.wudimanong.client.common.FeignClientDecoder
|
Feign、Hystrix、Ribbon的超時配置關係
在前面的內容我們分別單獨梳理了Feign、Hystrix及Ribbon三者常見的配置,針對各自的特性功能配置我們並沒有異議,但是我們也看到它們都有針對微服務超時的配置,而在開啓熔斷器功能後,這些超時配置會影響到熔斷器及服務降級邏輯的行爲,那麼它們之間超時的配置有什麼關係呢?如下:
如上圖所示,在Spring Cloud中使用Feign進行微服務調用分爲兩層:Ribbon的調用及Hystrix的調用。所以Feign的超時時間就是Ribbon和Hystrix超時時間的結合,而如果不啓用Hystrix則Ribbon的超時時間就是Feign的超時時間配置,Feign自身的配置會被覆蓋。
而如果開啓了Hystrix,那麼Ribbon的超時時間配置與Hystrix的超時時間配置則存在依賴關係,因爲涉及到Ribbon的重試機制,所以一般情況下都是Ribbon的超時時間小於Hystrix的超時時間,否則會出現以下錯誤:
1
|
2019 - 07 - 12 11 : 10 : 20 , 238 397194 [http-nio- 8084 -exec- 2 ] WARN o.s.c.n.z.f.r.s.AbstractRibbonCommand - The Hystrix timeout of 40000ms for the command operation is set lower than the combination of the Ribbon read and connect timeout, 80000ms.
|
那麼Ribbon和Hystrix的超時時間配置的關係具體是什麼呢?如下:
1
|
Hystrix的超時時間=Ribbon的重試次數(包含首次)*(ribbon.ReadTimeout+ribbon.ConnectTimeout)
|
而Ribbon的重試次數的計算方式爲:
1
|
Ribbon重試次數(包含首次)= 1 +ribbon.MaxAutoRetries+ribbon.MaxAutoRetriesNextServer+(ribbon.MaxAutoRetries*ribbon.MaxAutoRetriesNextServer)
|
以上圖中的Ribbon配置爲例子,Ribbon的重試次數=1+(1+1+1)*(30000+10000),所以Hystrix的超時配置應該>=160000毫秒。在Ribbon超時但Hystrix沒有超時的情況下,Ribbon便會採取重試機制;而重試期間如果時間超過了Hystrix的超時配置則會立即被熔斷(fallback)。
如果不配置Ribbon的重試次數,則Ribbon默認會重試一次,加上第一次調用Ribbon的重試次數爲2次,以上述配置爲例Hystrix超時時間配置爲2*40000=80000,由於很多情況下,大家一般不會主動配置Ribbon的重試次數,所以這裏需要注意下!強調下,以上超時配置的值只是示範,超時配置有點大不太合適實際的線上場景,大家根據實際情況設置即可!
總結
歡迎關注CSDN:JAVA編程大飛哥
覺得收穫的話可以點個關注評論轉發一波喔,謝謝大佬們支持!
微服務、分佈式、高併發、高可用,性能優化丶源碼分析等等一些技術乾貨等着你來探討學習!
點擊加入,一線互聯網技術等你來學習
點擊加入領取免費技術資料。備註:CSDN