什麼是Hystrix,阿里技術最終面,遺憾的倒在Hystrix面前!

首發地址什麼是Hystrix,阿里技術最終面,遺憾的倒在Hystrix面前 !面試

什麼是服務雪崩?

在分佈式架構中,很常見的一個情形就是某一個請求須要調用多個服務。sql

如客戶端訪問 user 服務,而 user 服務須要調用 order 服務,order 服務須要調用 goods 服務,因爲網絡緣由或者自身的緣由,若是 order 服務或者 goods 服務不能及時響應,user 服務將處於阻塞狀態,直到 order 服務 goods 服務響應。數據庫

此時如有大量的請求涌入,容器的線程資源會被消耗完畢,致使服務癱瘓。緩存

服務與服務之間的依賴性,故障會傳播,形成連鎖反應,會對整個微服務系統形成災難性的嚴重後果,這就是服務故障的「雪崩」效應。tomcat

1.如圖所示,此時的系統正在愉快的運行中。服務器

2.忽然這個時候,goods服務節點的網絡發生了故障。goods服務節點癱瘓,goods服務不可用。網絡

3.因爲good服務癱瘓致使order服務向goods服務發送的請求得不到返回,一直處於阻塞,此時user服務仍然一直 向order服務發送請求,最終致使order服務節點的資源耗盡,order服務節點癱瘓,order服務不可用。架構

4.因爲good服務癱瘓致使order服務向goods服務發送的請求得不到返回,一直處於阻塞,此時user服務仍然一直 向order服務發送請求,最終致使order服務節點的資源耗盡,也癱瘓掉。此時user服務向order服務發送的請求一樣也得不到返回,而客戶端依然源源不斷的向user服務節點發送請求,最終user服務節點和order服務節點同樣,因爲資源耗盡致使服務器癱瘓,user服務也不可用。併發

如上所述,一個服務節點的癱瘓,致使整條鏈路的服務節點都癱瘓的情形,咱們稱之爲服務雪崩。app

爲何會產生服務雪崩?

流量激增:好比異常流量、用戶重試致使系統負載升高;

緩存穿透:假設A爲client端,B爲Server端,假設A系統請求都流向B系統,請求超出了B系統的承載能力,就會形成B系統崩潰;

程序有Bug:代碼循環調用的邏輯問題,資源未釋放引發的內存泄漏等問題;

硬件故障:好比宕機,機房斷電,光纖被挖斷等。

數據庫嚴重瓶頸,好比:長事務、慢sql等。

線程同步等待:系統間常常採用同步服務調用模式,核心服務和非核心服務共用一個線程池和消息隊列。若是一個核心業務線程調用非核心線程,這個非核心線程交由第三方系統完成,當第三方系統自己出現問題,致使核心線程阻塞,一直處於等待狀態,而進程間的調用是有超時限制的,最終這條線程將斷掉,也可能引起雪崩。

有什麼辦法解決服務雪崩?

當發生突發流量激增的狀況下,咱們可使用自動擴容,或者是在負載均衡器中添加服務限流功能

對於緩存穿透形成的服務雪崩問題,能夠經過緩存預加載、緩存異步加載等方式來解決。

對於程序bug,emmm...,只能改bug了。

對於數據庫查詢時間過長致使的服務雪崩能夠進行sql優化,硬件升級等。

對於硬件故障形成的服務雪崩, ,跨機房路由,異地多活等方式。

對於不一樣的形成服務雪崩的場景,有着不少不一樣的解決方案,可是沒有一個通用的解決方案能夠解決全部的問題。

在經過大量的實踐證實,線程同步等待是最多見引起的雪崩效應的場景,此刻,本章節的主人公Hystrix將粉墨登場,咱們將詳細介紹如何使用Hystrix作故障隔離,熔斷器機制等能夠解決依賴服務不可用的問題。

Hystrix總體認知

Hystrix是一個用於處理微服務架構中的服務之間調用故障和容錯的開源庫。

在微服務架構裏,各個服務之間的調用均可能會失敗,好比超時、異常等。

Hystrix可以保證在一個依賴出問題的狀況下,不會致使整個服務鏈路全線崩潰,提升微服務架構的可用性。

Hystrix,咱們又稱「斷路器」,其自己是一種開關裝置,當某個服務單元發生故障以後,經過斷路器的故障監控(相似熔斷保險絲),向調用方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調用方沒法處理的異常,這樣就保證了服務調用方的線程不會被長時間、沒必要要地佔用,從而避免了故障在分佈式系統中的蔓延,乃至雪崩。

Hystrix設計目標,實現方式

設計目標

(1)對依賴服務調用時出現的調用延遲和調用失敗進行控制和容錯保護。
(2)阻止某一個依賴服務的故障在整個系統中蔓延,服務A->服務B->服務C,服務C故障了,服務B也故障了,服務A故障了,整個系統所有故障,總體宕機。(3)提供fail-fast(快速失敗)和快速恢復的支持。
(4)提供fallback優雅降級的支持。
(5)支持近實時的監控、報警以及運維操做。

實現方式

  1. 經過hystrixCommand或者HystrixObservableCommand來封裝對外部依賴的訪問請求,這個訪問請求通常會運行在獨立的線程中。

  2. 對於超出咱們設定的閾(yu)值服務調用,直接進行超時返回,不容許它長時間的阻塞。

  3. 對每個依賴服務進行資源隔離。經過線程池或者是semaphore這兩種方式。

  4. 對依賴服務被調用的成功次數,失敗次數,拒絕次數,超時次數進行統計。

  5. 若是對某一個依賴服務的調用失敗次數超過了一點的閾值,Hystrix自動進行熔斷,並在一段時間內對該服務的調用直接進行降級,一段時間後再自動嘗試恢復

  6. 當對一個服務調用出現失敗、被拒絕、超時、短路等異常狀況時,自動調用fallback降級機制。

  7. 對屬性和配置的修改提供近實時的支持

Hystrix工做流程

首先咱們看一下管網的Hystrix工做流程圖:

下面咱們針對這張圖詳細解讀下Hystrix的工做流程。

1.每次調用都會建立HystrixCommand或者HystrixObservableCommand對象

2.執行execute(observe)或queue(toObservable)作同步\異步調用

3.檢查請求結果是否被緩存,若是緩存直接返回

4.檢查是否開啓了斷路器,若是開啓直接跳到步驟8

5.檢查線程池/信號量是否跑滿,若是跑滿進入步驟8

6.執行 HystrixObservableCommand.construct() or HystrixCommand.run(),若是執行異常或者調用超時直接跳到步驟8

7.計算斷路器狀態,全部的運行狀態(成功, 失敗, 拒絕,超時)上報給斷路器,用於統計從而判斷斷路器狀態

8.調用fallback降級機制,經過上述步驟會有(熔斷器打開,線程池/信號量跑滿,調用超時,調用失敗)四種狀況會進行降級處理

9.返回依賴請求的真正結果

工做流程詳解

第一步,建立HystrixCommand或者HystrixObservableCommand對象

HytrixCommand和HystrixObservableCommand包裝了對外部依賴訪問的邏輯。

整個流程的第一個步驟就是實例化HystrixCommand或者HystrixObservableCommand對象。

在構造這兩個Command對象時,能夠經過構造方法傳遞任何執行過程當中須要的參數。

若是對外部依賴調用只返回一個結果值,那麼能夠實例化一個HystrixCommand對象。

HystrixCommand command = newHystrixCommand(arg1, arg2);

若是在調用外部依賴時須要返回多個結果值時,能夠實例化一個HystrixObservableCommand對象

HystrixObservableCommand command = newHystrixObservableCommand(arg1, arg2);

第二步,執行execute(observe)或queue(toObservable)作同步\異步調用

HystrixCommand主要是使用如下兩個命令

execute():同步執行,從依賴的服務返回一個單一的結果對象,或者是在發生錯誤的時候拋出異常。

queue():異步執行,直接返回一個Future對象,其中包含了服務執行結束時要返回的單一結果對象。

HystrixObservableCommand使用如下兩個命令

observe():返回Observable對象,返回 Observable 對象,當即發出請求,在依賴服務響應(或者拋出異常/超時)時,經過註冊的 Subscriber 獲得返回結果,它是一個Hot Observable。

toObservable():返回Observable對象,但只有在訂閱該對象時,纔會發出請求,而後在依賴服務響應(或者拋出異常/超時)時,經過註冊的 Subscriber 獲得返回結果,它是一個Cold Observable。

第三步,檢查請求結果是否被緩存,若是緩存直接返回

若當前命令的請求緩存功能是被啓用的,而且該命令緩存命中,那麼緩存的結果會當即以Observable對象的形式返回。

這個結果緩存的好處爲:

一、在同一個請求上下文中,能夠減小使用相同參數請求原始服務的開銷。
二、請求緩存在步驟5執行以前生效,因此能夠有效減小沒必要要的線程開銷。

第四步,檢查是否開啓了斷路器

在緩存沒有被命中時,Hystrix會在執行步驟5以前先檢查斷路器是否被打開。若是打開了,Hystrix不會執行任何命令執行跳轉到步驟8

斷路器開關控制條件: 1.對外部依賴調用的次數知足配置的閾值  2.對外部依賴調用發生錯誤的比率知足配置的閾值

在知足以上兩個條件時,斷路器打開熔斷開關,以後全部對外部依賴調用都將被直接斷開。

在開關打開時長超過試探窗口期後,斷路器將嘗試放行部分外部依賴的調用,

根據試探的結果決定從新開啓或者關閉熔斷開關。

第五步,檢查線程池/信號量是否跑滿

咱們知道,Hystrix引入了線程池和信號量兩種方式實現資源隔離機制。若是此時命令對應的線程池或隊列或信號量已經滿了,直接跳轉到步驟8。

第六步,執行 HystrixObservableCommand.construct() or HystrixCommand.run()

Hystrix會根據咱們編寫的方法來決定採起什麼方式去請求依賴服務。

1.HystrixCommand.run()——返回單個響應或拋出異常。

2.HystrixObservableCommand.construct()——返回 Observable 對象來發射多個結果,或經過onError發送錯誤通知。

若是run()或construct()方法執行時長超過了命令的超時閥值,其線程將拋出一個TimeoutException(或者在一個單獨的線程拋出,若是命令沒有運行在它本身的線程)。

這種狀況下 Hystrix轉接到fallback處理邏輯(第8步)。

而且若是該命令沒有取消或中斷,它將放棄run()或construct()方法最終的返回值。

若是命令沒有拋出異常而且返回了響應,Hystrix 將會在執行一些日誌記錄和度量報告以後返回結果給調用者。

若是是經過run()運行,Hystrix 將返回 Observable 發射單個結果,而後發送一個onCompleted的通知;若是是經過construct()運行,Hystrix 直接返回該方法產生的Observable對象。

第七步,計算斷路器狀態

Hystrix會將每個依賴服務的調用成功,失敗,拒絕,超時,等事件,都會發送給circuit breaker斷路器。

HystrixCircuitBreaker經過維護一系列的counter記錄外部依賴請求的執行狀況。

斷路器根據維護的這些信息,在符合觸發條件下開啓斷路功能,在條件合適的時候關閉斷路開關。

若是打開了斷路器,那麼在一段時間內就會直接短路,而後若是在以後第一次檢查發現調用成功了,就關閉斷路器。

第八步,調用fallback降級機制

經過對上述步驟的詳細解讀,咱們發現有如下幾種狀況是會調用fallback降級機制的。
1.斷路器打開

2.線程池或者信號量已經滿了

3.command執行異常

4.執行超時

在服務降級邏輯中,須要實現一個通用的響應結果,而且該結果的處理邏輯應當是從緩存或是根據一些靜態邏輯來獲取,而不是依賴網絡請求獲取。

若是必定要在服務降級邏輯中包含網絡請求,那麼該請求也必須包裝在HystrixCommand或HystrixObservableCommand中,從而造成級聯的降級策略。

而最終的降級邏輯必定不是一個依賴網絡請求的處理,而是一個可以穩定的返回結果的處理邏輯。

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

2.在 HystrixObservableCommand 中,在HystrixObservableCommand.resumeWithFallback() 方法中提供自定義的回調邏輯,方法返回一個Observable對象來發射一個或多個降級結果

若是fallback返回告終果,那麼Hystrix就會返回這個結果。

對於HystrixCommand,會返回一個Observable對象,其中會發返回對應的結果;

對於HystrixObservableCommand,會返回一個原始的Observable對象。

若是沒有實現fallback,或者是fallback拋出了異常,Hystrix會返回一個Observable,可是不會返回任何數據。

不一樣的command執行方式,其fallback爲空或者異常時的返回結果不一樣

1.對於execute(),直接拋出異常

2.對於queue(),返回一個Future,調用get()時拋出異常

3.對於observe(),返回一個Observable對象,可是調用subscribe()方法訂閱它時,拋出調用者的onError方法

4.對於toObservable(),返回一個Observable對象,可是調用subscribe()方法訂閱它時,拋出調用者的onError方法

第九步,返回依賴請求的真正結果

若是Hystrix命令執行成功,它將以Observable形式返回響應給調用者。根據你在步驟2的調用方式不一樣,在返回Observablez以前可能會作一些轉換。

execute():經過調用queue()來獲得一個Future對象,而後調用get()方法來獲取Future中包含的值。

queue():將Observable轉換成BlockingObservable,在將BlockingObservable轉換成一個Future。

observe():訂閱返回的Observable,而且當即開始執行命令的邏輯。

toObservable():返回一個沒有改變的Observable,你必須訂閱它,它纔可以開始執行命令的邏輯。

上述就是整個Hystrix的工做流程,固然沒有很深刻的講解,可是仍是建議多看幾遍,我面試的時候碰到好幾回讓我簡述Hystrix工做流程,多看幾遍,記在內心,面試不慌。

Hystrix使用框架搭建

固然了,Hystrix也能和Feign 和 Zuul 的集成使用,這些在這裏就不贅述了,後續介紹Feign和Zuul的文章中會詳細說明。

本文主要介紹HystrixCommand 註解方式的使用。

首先咱們搭建一個HystrixClient項目。

添加配置文件application.properties

新建RestConfiguration類,用來全局配置RestTemplate

新建HystrixController

而後在啓動類的上添加@EnableHystrix註解。

改造上一篇萬字詳解Ribbon架構,針對面試高頻題多角度細說Ribbon中提供的OrderService,讓代碼休眠5秒後在返回。

在HystrixController中的三個方法中分別配置了2000ms,10000ms,10000ms若是沒有返回結果,那麼將直接回調用咱們指定的fallback。

OrderService

上述三步,基本的Hystrix使用框架就搭建完成了,而後咱們啓動上一篇萬字詳解Ribbon架構,針對面試高頻題多角度細說Ribbon中提到的Eureka-Server,並按照上篇文章的啓動方式,分別啓動OrderServeice的7777,8888,9999三個端口,此時咱們打開 http://localhost:8761/ 頁面,咱們發現已經有三個服務名爲order-service,端口號分別7777,8888,9999的服務註冊了進來。

最後咱們啓動HystrixClient啓動類,而後咱們先訪問設置超時時間爲10000ms的 localhost:8088/test2 ,由於咱們在OrderService中設置的休眠時間爲3000ms因此能在超時時間內返回請求,因此不用調用fallback。

Hystrix核心配置詳解

Execution相關的屬性的配置

hystrix.command.default.execution.isolation.strategy 

隔離策略,默認是Thread, 可選Thread,Semaphore

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 

命令執行超時時間,默認1000ms。

hystrix.command.default.execution.timeout.enabled 

執行是否啓用超時,默認啓用true。

hystrix.command.default.execution.isolation.thread.interruptOnTimeout

發生超時是是否中斷,默認true。

hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 

理論上選擇semaphore size的原則和選擇thread size一致,但選用semaphore時每次執行的單元要比較小且執行速度快(ms級別),不然的話應該用thread。semaphore應該佔整個容器(tomcat)的線程池的一小部分。

Fallback相關配置

hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 

若是併發數達到該設置值,請求會被拒絕和拋出異常而且fallback不會被調用。默認10。

hystrix.command.default.fallback.enabled 

當執行失敗或者請求被拒絕,是否會嘗試調用hystrixCommand.getFallback() 。默認true。

Metrics相關屬性配置

hystrix.command.default.metrics.rollingStats.timeInMilliseconds

設置統計的時間窗口值的,毫秒值,circuit break 的打開會根據1個rolling window的統計來計算。若rolling window被設爲10000毫秒,則rolling window會被分紅n個buckets,每一個bucket包含success,failure,timeout,rejection的次數的統計信息。默認10000。

hystrix.command.default.metrics.rollingStats.numBuckets 

設置一個rolling window被劃分的數量,若numBuckets=10,rolling window=10000,那麼一個bucket的時間即1秒。必須符合rolling window % numberBuckets == 0。默認10。

hystrix.command.default.metrics.rollingPercentile.enabled

執行時是否enable指標的計算和跟蹤,默認true。

hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds

設置rolling percentile window的時間,默認60000。

hystrix.command.default.metrics.rollingPercentile.numBuckets

設置rolling percentile window的numberBuckets。邏輯同上。默認6。

hystrix.command.default.metrics.rollingPercentile.bucketSize

若是bucket size=100,window=10s,若這10s裏有500次執行,只有最後100次執行會被統計到bucket裏去。增長該值會增長內存開銷以及排序的開銷。默認100。

hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds

記錄health 快照(用來統計成功和錯誤綠)的間隔,默認500ms。

ThreadPool 相關屬性配置

hystrix.threadpool.default.coreSize

併發執行的最大線程數,默認10。

hystrix.threadpool.default.maxQueueSize

BlockingQueue的最大隊列數,當設爲-1,會使用SynchronousQueue,值爲正時使用LinkedBlcokingQueue。該設置只會在初始化時有效,以後不能修改threadpool的queue size,除非reinitialising thread executor。默認-1。

hystrix.threadpool.default.queueSizeRejectionThreshold

即便maxQueueSize沒有達到,達到queueSizeRejectionThreshold該值後,請求也會被拒絕。由於maxQueueSize不能被動態修改,這個參數將容許咱們動態設置該值。if maxQueueSize == -1,該字段將不起做用。

hystrix.threadpool.default.keepAliveTimeMinutes

若是corePoolSize和maxPoolSize設成同樣(默認實現)該設置無效。

hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds

線程池統計指標的時間,默認10000。

hystrix.threadpool.default.metrics.rollingStats.numBuckets

將rolling window劃分爲n個buckets,默認10。

Hystrix容錯機制之回退降級‍‍‍‍‍‍‍‍‍

1.什麼是降級?

降級,一般指事務高峯期,爲了保證核心服務正常運行,須要停掉一些不過重要的業務,或者某些服務不可用時,執行備用邏輯從故障服務中快速失敗或快速返回,以保障主體業務不受影響。

Hystrix提供的降級主要是爲了容錯,保證當前服務不受依賴服務故障的影響,從而提升服務的健壯性。

要支持回退或降級處理,能夠重寫HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。

2.什麼狀況下才會走降級?

從Hystrix的工做流程圖中咱們能夠看到如下狀況會走降級邏輯。
1.斷路器打開
2.線程池或者信號量已經滿了
3.command執行異常
4.執行超時

3.回退降級有哪些處理方式?

  1. 快速失敗:發生故障後直接拋出,不作處理。

  2. 無聲失敗:發生故障後,返回無心義內容,如null,空Map等,故障會被屏蔽。

  3. 靜態失敗:這種配置下,發生故障會返回靜態的默認值,如返回值是boolean,則結果爲默認true。

  4. Stubbed:這種配置適用於返回值是一個複合對象的情形,發生故障時,會手動建立一個複合對象的實例,實例中每每包含了一些默認值或錯誤信息。

  5. 依賴緩存:這種狀況下,當下層服務故障時,會從緩存中取得以前的舊數據供使用。

  6. 主次模式:這是回退降級的一種特殊使用方法。

主次模式解釋:

有時候,咱們可能會遇到這樣的場景。針對某個業務,可能會有兩種處理方案,A方案高效,可是沒有通過規模化測試,不敢保證可靠性。B方案保守,雖然效率較低,可是不會出現。這時候,咱們就能夠嘗試採用主次模式。主流程基於A方案運行,fallback基於B方案運行。在運行過程當中,如不出錯,則一直使用A方案,一時出錯,可經過回退降級,迅速切換爲B方案,以免問題的不受控擴散。

Hystrix監控系統搭建

什麼是Hystrix Dashboard?

Hystrix提供了準實時的調用監控(Hystrix DashBoard),Hystrix會持續的記錄經過Hystrix發起的請求的執行信息,以統計報表和圖形的形式展現給客戶,包括每秒執行多少,請求多少成功,請求失敗多少等。

Netflix經過Hystrix-metics-event-stream項目實現了對以上指標的監控,SpringCloud也提供了Hystrix DashBoard的整合,對監控內容轉化成可視化的界面,以便於用戶可以直接的看到服務和集羣的狀態,在實際使用中,咱們每每還要結合Turbine來使用。

開始搭建Hystrix Dashboard

Hystrix Dashboard的搭建其實很簡單,分爲三步:

  1. 建立監控Hystrix Dashboard項目模塊

  2. 配置application.yml

  3. 配置啓動類

首先咱們建立一個HystrixDashboard項目,配置pom.xml文件以下

配置端口爲9001

server.port = 9001

配置啓動類,添加@EnableHystrixDashboard註解

啓動後訪問http://localhost:9001/hystrix只要咱們能看到一隻豪豬就說明啓動成功了。

 

Hystrix使用總結

本文從介紹服務雪崩引入Hystrix,首先帶領你們對Hystrix進行了一個總體認知,而且介紹了Hystrix的設計目標以及實現方式。

而後詳細分九步了Hystrix的整個工做流程,而且帶領你們實戰搭建了Hystrix框架和Hystrix監控系統。

最後詳細介紹了Hystrix的核心配置,以及Hystrix的重中之重之回退降級。

Hystrix斷路器一樣是SpringCloud生態系統中不可缺乏的一環,一樣也是面試中常常會出現的高頻面試題。

原創不易,若是你們喜歡,賞個分享點贊在看三連吧。和你們一塊兒成爲這世界上最優秀的人。

相關文章
相關標籤/搜索