微服務架構的特點就是:“一解釋就懂,一問就不知,一討論就吵架”
服務熔斷:一般是指軟件系統中,由于某些原因使得服務出現了過載現象,為防止造成整個系統故障,從而采用的一種保護措施,所以很多地方把熔斷亦稱為過載保護。
服務降級:就是整體資源快不夠了,忍痛將某些服務先關掉,待渡過難關,再開啟回來。
兩者類似性的:
- 目的很一致,都是從可用性可靠性著想,為防止系統的整體緩慢甚至崩潰,采用的技術手段;
- 最終表現類似,對于兩者來說,最終讓用戶體驗到的是某些功能暫時不可達或不可用;
- 粒度一般都是服務級別,當然,業界也有不少更細粒度的做法,比如做到數據持久層(允許查詢,不允許增刪改);
- 自治性要求很高,熔斷模式一般都是服務基于策略的自動觸發,降級雖說可人工干預,但在微服務架構下,完全靠人顯然不可能,開關預置、配置中心都是必要手段;
兩者的區別:
- 觸發原因不太一樣,服務熔斷一般是某個服務(下游服務)故障引起,而服務降級一般是從整體負荷考慮;
- 管理目標的層次不太一樣,熔斷其實是一個框架級的處理,每個微服務都需要(無層級之分),而降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)
- 實現方式不太一樣;
工作流程
1.創建 HystrixCommand 或 HystrixObservableCommand 對象
首先,創建一個 HystrixCommand 或 HystrixObservableCommand 對象,用來表示對依賴服務的操作請求,同時傳遞所有需要的參數。從其命名中我們就能知道它采用了“命令模式” 來實現服務調用操作的封裝。而這兩個 Command 對象分別針對不同的應用場景。
- HystrixCommand :用在依賴的服務返回單個操作結果的時候。
- HystrixObservableCommand :用在依賴的服務返回多個操作結果的時候。
命令模式,將來自客戶端的請求封裝成一個對象,從而讓你可以使用不同的請求對客戶端進行參數化。它可以被用于實現“行為請求者” 與 “行為實現者” 的解耦,以便使兩者可以適應變化。
2. 命令執行
命令執行方式一共有4種,而 Hystrix 在執行時會根據創建的Command對象以及具體的情況來選擇一種執行。其中 HystrixCommand 實現了下面兩個執行方式。
- execute():同步執行,從依賴的服務返回一個單一的結果對象,或是在發生錯誤的時候拋出異常。
- queue():異步執行,直接返回一個 Future 對象,其中包含了服務執行結束時要返回的單一結果對象。
而 HystrixObservableCommand 實現了另外兩種執行方式。
- observe():返回 Observable 對象,它代表了操作的多個結果,它是一個 HotObservable。
- toObservable():同樣返回 Observable 對象,也代表了操作的多個結果,但它返回的是一個 Cold Observable。
在 Hystrix 的底層實現中大量使用了 RxJava ,為了更容易的理解后續內容,在這里對 RxJava 的觀察者-訂閱者模式做一個簡單的入門介紹。
上面提到的 Observable 對象就是 RxJava 中的核心內容之一,可以理解為 “事件源” 或者 “被觀察者”,與其對應的 Subscriber 對象,可以理解為 “訂閱者” 或者 “觀察者”。這兩個對象是 RxJava 響應式編程的重要組成部分。
- Observable 用來向訂閱者 Subscriber 對象發布事件,Subscriber 對象則在接收到事件后對其進行處理,而在這里所指的事件通常就是對依賴服務的調用。
- 一個 Observable 可以發出多個事件,知道結束或者發生異常。
- Observable 對象每發出一個事件,就會調用對應觀察者 Subscriber 對象的 onNext() 方法。
- 每一個 Observable 的執行,最后一定會通過調用 Subscriber.onCompleted() 或者 Subscriber.onError() 來結束該事件的操作流。
3. 結果是否被緩存
若當前命令的請求緩存功能是被啟用的,并且該命令緩存命中,那么緩存的結果會立即以 Observable 對象的形式返回。
4. 斷路器是否打開
在命令結果沒有緩存命中的時候,Hystrix 在執行命令前需要檢查斷路器是否為打開狀態。
- 打開:Hystrix不執行命令,轉到 fallback 處理邏輯(對應下面第8步)。
- 關閉:Hystrix 跳到第5步,檢查是否有可用資源來執行命令。
5. 線程池 / 請求隊列 / 信息量是否占滿
如果與命令相關的線程池 / 請求隊列 / 信息量已經占滿,那么 Hystrix 不會執行命令,跳轉到 fallback 處理邏輯(對應下面第8步)。
注意:此處的線程池并非容器的線程池,而是每個依賴服務的專有線程池。Hystrix 為了保證不會因為某個依賴服務的問題影響到其他依賴服務而采用了 “艙壁模式” 來隔離每個依賴的服務。
6. HystrixObservableCommand.construct() 或 HystrixCommand.run()
Hystrix 會根據編寫的方法來決定采取什么樣的方式去請求依賴服務。
- HystrixCommand.run() :返回一個單一的結果,或者拋出異常。
- HystrixObservableCommand.construct():返回一個 Observable 對象來發射多個結果,或通過 onError 發送錯誤通知。
如果 run() 或 construct() 方法的執行時間超過了命令設置的超時閾值,當前處理線程會拋出 TimeoutException。這種情況下,也會跳轉到 fallback 處理邏輯(第8步)。
7. 計算斷路器的健康度
Hystrix 會將 “成功”、“失敗”、“拒絕”、“超時” 等信息報告給斷路器,而斷路器會維護一組計數器來統計這些數據。
斷路器會使用這些統計數據來決定是否要將斷路器打開,來對某個依賴服務的請求進行 “熔斷 / 短路”,直到恢復期結束。
8. fallback 處理
當命令執行失敗的時候,Hystrix 會進入 fallback 嘗試回退處理,我們通常也稱為 “服務降級”。下面就是能夠引發服務降級處理的幾種情況:
- 第4步,當前命令處于 “熔斷 / 短路” 狀態,斷路器是打開的時候。
- 第5步,當前命令的線程池、請求隊列或者信號量被占滿的時候。
- 第6步,HystrixObservableCommand.construct() 或者 HystrixCommand.run() 拋出異常的時候。
9、返回成功的響應