首發地址:什麼是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)支持近實時的監控、報警以及運維操做。
實現方式
-
經過hystrixCommand或者HystrixObservableCommand來封裝對外部依賴的訪問請求,這個訪問請求通常會運行在獨立的線程中。
-
對於超出咱們設定的閾(yu)值服務調用,直接進行超時返回,不容許它長時間的阻塞。
-
對每個依賴服務進行資源隔離。經過線程池或者是semaphore這兩種方式。
-
對依賴服務被調用的成功次數,失敗次數,拒絕次數,超時次數進行統計。
-
若是對某一個依賴服務的調用失敗次數超過了一點的閾值,Hystrix自動進行熔斷,並在一段時間內對該服務的調用直接進行降級,一段時間後再自動嘗試恢復
-
當對一個服務調用出現失敗、被拒絕、超時、短路等異常狀況時,自動調用fallback降級機制。
-
對屬性和配置的修改提供近實時的支持
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.回退降級有哪些處理方式?
-
快速失敗:發生故障後直接拋出,不作處理。
-
無聲失敗:發生故障後,返回無心義內容,如null,空Map等,故障會被屏蔽。
-
靜態失敗:這種配置下,發生故障會返回靜態的默認值,如返回值是boolean,則結果爲默認true。
-
Stubbed:這種配置適用於返回值是一個複合對象的情形,發生故障時,會手動建立一個複合對象的實例,實例中每每包含了一些默認值或錯誤信息。
-
依賴緩存:這種狀況下,當下層服務故障時,會從緩存中取得以前的舊數據供使用。
-
主次模式:這是回退降級的一種特殊使用方法。
主次模式解釋:
有時候,咱們可能會遇到這樣的場景。針對某個業務,可能會有兩種處理方案,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的搭建其實很簡單,分爲三步:
-
建立監控Hystrix Dashboard項目模塊
-
配置application.yml
-
配置啓動類
首先咱們建立一個HystrixDashboard項目,配置pom.xml文件以下
配置端口爲9001
server.port = 9001
配置啓動類,添加@EnableHystrixDashboard註解
啓動後訪問http://localhost:9001/hystrix
只要咱們能看到一隻豪豬就說明啓動成功了。
Hystrix使用總結
本文從介紹服務雪崩引入Hystrix,首先帶領你們對Hystrix進行了一個總體認知,而且介紹了Hystrix的設計目標以及實現方式。
而後詳細分九步了Hystrix的整個工做流程,而且帶領你們實戰搭建了Hystrix框架和Hystrix監控系統。
最後詳細介紹了Hystrix的核心配置,以及Hystrix的重中之重之回退降級。
Hystrix斷路器一樣是SpringCloud生態系統中不可缺乏的一環,一樣也是面試中常常會出現的高頻面試題。
原創不易,若是你們喜歡,賞個分享點贊在看三連吧。和你們一塊兒成爲這世界上最優秀的人。