Spring Cloud(四):服務容錯保護 Hystrix【Finchley 版】

来源:https://www.cnblogs.com/chenweida/archive/2018/05/11/9025597.html
-Advertisement-
Play Games

Spring Cloud(四):服務容錯保護 Hystrix【Finchley 版】 發表於 2018-04-15 | 更新於 2018-05-07 | 分散式系統中經常會出現某個基礎服務不可用造成整個系統不可用的情況,這種現象被稱為服務雪崩效應。為了應對服務雪崩,一種常見的做法是手動服務降級。而 ...


Spring Cloud(四):服務容錯保護 Hystrix【Finchley 版】

分散式系統中經常會出現某個基礎服務不可用造成整個系統不可用的情況,這種現象被稱為服務雪崩效應。為了應對服務雪崩,一種常見的做法是手動服務降級。而 Hystrix 的出現,給我們提供了另一種選擇。

Hystrix [hɪst’rɪks] 的中文含義是 “豪豬”,豪豬周身長滿了刺,能保護自己不受天敵的傷害,代表了一種防禦機制,這與 Hystrix 本身的功能不謀而合,因此 Netflix 團隊將該框架命名為 Hystrix,並使用了對應的卡通形象做作為 logo。

服務雪崩效應

定義

服務雪崩效應是一種因 服務提供者 的不可用導致 服務調用者 的不可用,並將不可用 逐漸放大 的過程。如果所示:

上圖中,A 為服務提供者,B 為 A 的服務調用者,C 和 D 是 B 的服務調用者。當 A 的不可用,引起 B 的不可用,並將不可用逐漸放大 C 和 D 時,服務雪崩就形成了。

形成的原因

我把服務雪崩的參與者簡化為 服務提供者 和 服務調用者,並將服務雪崩產生的過程分為以下三個階段來分析形成的原因:

  1. 服務提供者不可用
  2. 重試加大流量
  3. 服務調用者不可用

服務雪崩的每個階段都可能由不同的原因造成,比如造成 服務不可用 的原因有:

  • 硬體故障
  • 程式 Bug
  • 緩存擊穿
  • 用戶大量請求

硬體故障可能為硬體損壞造成的伺服器主機宕機,網路硬體故障造成的服務提供者的不可訪問。
緩存擊穿一般發生在緩存應用重啟,所有緩存被清空時,以及短時間內大量緩存失效時。大量的緩存不命中,使請求直擊後端,造成服務提供者超負荷運行,引起服務不可用。
在秒殺和大促開始前,如果準備不充分,用戶發起大量請求也會造成服務提供者的不可用。

而形成 重試加大流量 的原因有:

  • 用戶重試
  • 代碼邏輯重試

在服務提供者不可用後,用戶由於忍受不了界面上長時間的等待,而不斷刷新頁面甚至提交表單。
服務調用端的會存在大量服務異常後的重試邏輯。
這些重試都會進一步加大請求流量。

最後, 服務調用者不可用 產生的主要原因是:

  • 同步等待造成的資源耗盡

當服務調用者使用 同步調用 時,會產生大量的等待線程占用系統資源。一旦線程資源被耗盡,服務調用者提供的服務也將處於不可用狀態,於是服務雪崩效應產生了。

應對策略

針對造成服務雪崩的不同原因,可以使用不同的應對策略:

  1. 流量控制
  2. 改進緩存模式
  3. 服務自動擴容
  4. 服務調用者降級服務

流量控制 的具體措施包括:

  • 網關限流
  • 用戶交互限流
  • 關閉重試

因為 Nginx 的高性能,目前一線互聯網公司大量採用 Nginx+Lua 的網關進行流量控制,由此而來的 OpenResty 也越來越熱門。

用戶交互限流的具體措施有: 1. 採用載入動畫,提高用戶的忍耐等待時間。2. 提交按鈕添加強制等待時間機制。

改進緩存模式 的措施包括:

  • 緩存預載入
  • 同步改為非同步刷新

服務自動擴容 的措施主要有:

  • AWS 的 auto scaling

服務調用者降級服務 的措施包括:

  • 資源隔離
  • 對依賴服務進行分類
  • 不可用服務的調用快速失敗

資源隔離主要是對調用服務的線程池進行隔離。

我們根據具體業務,將依賴服務分為: 強依賴和若依賴。強依賴服務不可用會導致當前業務中止,而弱依賴服務的不可用不會導致當前業務的中止。

不可用服務的調用快速失敗一般通過 超時機制熔斷器 和熔斷後的 降級方法 來實現。

使用 Hystrix 預防服務雪崩

服務降級(Fallback)

對於查詢操作,我們可以實現一個 fallback 方法,當請求後端服務出現異常的時候,可以使用 fallback 方法返回的值。fallback 方法的返回值一般是設置的預設值或者來自緩存。

資源隔離

貨船為了進行防止漏水和火災的擴散,會將貨倉分隔為多個,如下圖所示:

這種資源隔離減少風險的方式被稱為: Bulkheads(艙壁隔離模式)。
Hystrix 將同樣的模式運用到了服務調用者上。

在 Hystrix 中,主要通過線程池來實現資源隔離。通常在使用的時候我們會根據調用的遠程服務劃分出多個線程池。例如調用產品服務的 Command 放入 A 線程池,調用賬戶服務的 Command 放入 B 線程池。這樣做的主要優點是運行環境被隔離開了。這樣就算調用服務的代碼存在 bug 或者由於其他原因導致自己所線上程池被耗盡時,不會對系統的其他服務造成影響。
通過對依賴服務的線程池隔離實現,可以帶來如下優勢:

  • 應用自身得到完全的保護,不會受不可控的依賴服務影響。即便給依賴服務分配的線程池被填滿,也不會影響應用自身的額其餘部分。
  • 可以有效的降低接入新服務的風險。如果新服務接入後運行不穩定或存在問題,完全不會影響到應用其他的請求。
  • 當依賴的服務從失效恢復正常後,它的線程池會被清理並且能夠馬上恢復健康的服務,相比之下容器級別的清理恢復速度要慢得多。
  • 當依賴的服務出現配置錯誤的時候,線程池會快速的反應出此問題(通過失敗次數、延遲、超時、拒絕等指標的增加情況)。同時,我們可以在不影響應用功能的情況下通過實時的動態屬性刷新(後續會通過 Spring Cloud Config 與 Spring Cloud Bus 的聯合使用來介紹)來處理它。
  • 當依賴的服務因實現機制調整等原因造成其性能出現很大變化的時候,此時線程池的監控指標信息會反映出這樣的變化。同時,我們也可以通過實時動態刷新自身應用對依賴服務的閾值進行調整以適應依賴方的改變。
  • 除了上面通過線程池隔離服務發揮的優點之外,每個專有線程池都提供了內置的併發實現,可以利用它為同步的依賴服務構建非同步的訪問。

總之,通過對依賴服務實現線程池隔離,讓我們的應用更加健壯,不會因為個別依賴服務出現問題而引起非相關服務的異常。同時,也使得我們的應用變得更加靈活,可以在不停止服務的情況下,配合動態配置刷新實現性能配置上的調整。

雖然線程池隔離的方案帶瞭如此多的好處,但是很多使用者可能會擔心為每一個依賴服務都分配一個線程池是否會過多地增加系統的負載和開銷。對於這一點,使用者不用過於擔心,因為這些顧慮也是大部分工程師們會考慮到的,Netflix 在設計 Hystrix 的時候,認為線程池上的開銷相對於隔離所帶來的好處是無法比擬的。同時,Netflix 也針對線程池的開銷做了相關的測試,以證明和打消 Hystrix 實現對性能影響的顧慮。

下圖是 Netflix Hystrix 官方提供的一個 Hystrix 命令的性能監控,該命令以每秒 60 個請求的速度(QPS)向一個單服務實例進行訪問,該服務實例每秒運行的線程數峰值為 350 個。

從圖中的統計我們可以看到,使用線程池隔離與不使用線程池隔離的耗時差異如下表所示:

比較情況未使用線程池隔離使用了線程池隔離耗時差距
中位數 2ms 2ms 2ms
90 百分位 5ms 8ms 3ms
99 百分位 28ms 37ms 9ms

在 99% 的情況下,使用線程池隔離的延遲有 9ms,對於大多數需求來說這樣的消耗是微乎其微的,更何況為系統在穩定性和靈活性上所帶來的巨大提升。雖然對於大部分的請求我們可以忽略線程池的額外開銷,而對於小部分延遲本身就非常小的請求(可能只需要 1ms),那麼 9ms 的延遲開銷還是非常昂貴的。實際上 Hystrix 也為此設計了另外的一個解決方案:信號量(Semaphores)。

Hystrix 中除了使用線程池之外,還可以使用信號量來控制單個依賴服務的併發度,信號量的開銷要遠比線程池的開銷小得多,但是它不能設置超時和實現非同步訪問。所以,只有在依賴服務是足夠可靠的情況下才使用信號量。在 HystrixCommand 和 HystrixObservableCommand 中 2 處支持信號量的使用:

  • 命令執行:如果隔離策略參數 execution.isolation.strategy 設置為 SEMAPHORE,Hystrix 會使用信號量替代線程池來控制依賴服務的併發控制。
  • 降級邏輯:當 Hystrix 嘗試降級邏輯時候,它會在調用線程中使用信號量。

信號量的預設值為 10,我們也可以通過動態刷新配置的方式來控制併發線程的數量。對於信號量大小的估算方法與線程池併發度的估算類似。僅訪問記憶體數據的請求一般耗時在 1ms 以內,性能可以達到 5000rps,這樣級別的請求我們可以將信號量設置為 1 或者 2,我們可以按此標準並根據實際請求耗時來設置信號量。

斷路器模式

斷路器模式源於 Martin Fowler 的 Circuit Breaker 一文。“斷路器” 本身是一種開關裝置,用於在電路上保護線路過載,當線路中有電器發生短路時,“斷路器” 能夠及時的切斷故障電路,防止發生過載、發熱、甚至起火等嚴重後果。

在分散式架構中,斷路器模式的作用也是類似的,當某個服務單元發生故障(類似用電器發生短路)之後,通過斷路器的故障監控(類似熔斷保險絲),直接切斷原來的主邏輯調用。但是,在 Hystrix 中的斷路器除了切斷主邏輯的功能之外,還有更複雜的邏輯,下麵我們來看看它更為深層次的處理邏輯。

斷路器開關相互轉換的邏輯如下圖:

當 Hystrix Command 請求後端服務失敗數量超過一定閾值,斷路器會切換到開路狀態 (Open)。這時所有請求會直接失敗而不會發送到後端服務。

這個閾值涉及到三個重要參數:快照時間窗、請求總數下限、錯誤百分比下限。這個參數的作用分別是:
快照時間窗:斷路器確定是否打開需要統計一些請求和錯誤數據,而統計的時間範圍就是快照時間窗,預設為最近的 10 秒。
請求總數下限:在快照時間窗內,必須滿足請求總數下限才有資格進行熔斷。預設為 20,意味著在 10 秒內,如果該 Hystrix Command 的調用此時不足 20 次,即時所有的請求都超時或其他原因失敗,斷路器都不會打開。
錯誤百分比下限:當請求總數在快照時間窗內超過了下限,比如發生了 30 次調用,如果在這 30 次調用中,有 16 次發生了超時異常,也就是超過 50% 的錯誤百分比,在預設設定 50% 下限情況下,這時候就會將斷路器打開。

斷路器保持在開路狀態一段時間後 (預設 5 秒),自動切換到半開路狀態 (HALF-OPEN)。這時會判斷下一次請求的返回情況,如果請求成功,斷路器切回閉路狀態 (CLOSED),否則重新切換到開路狀態 (OPEN)。

使用 Feign Hystrix

因為熔斷只是作用在服務調用這一端,因此我們根據上一篇的示例代碼只需要改動 eureka-consumer-feign 項目相關代碼就可以。

POM 配置

因為 Feign 中已經依賴了 Hystrix 所以在 maven 配置上不用做任何改動。

配置文件

在原來的 application.yml 配置的基礎上修改

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: eureka-consumer-feign-hystrix
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
server:
port: 9003
feign:
hystrix:
enabled: true

 

創建回調類

創建 HelloRemoteHystrix 類實現 HelloRemote 中實現回調的方法

1
2
3
4
5
6
7
8
9
@Component
public class HelloRemoteHystrix implements HelloRemote {

@Override
public String hello(@RequestParam(value = "name") String name) {
return "Hello World!";
}

}

 

添加 fallback 屬性

HelloRemote類添加指定 fallback 類,在服務熔斷的時候返回 fallback 類中的內容。

1
2
3
4
5
6
7
@FeignClient(name = "eureka-producer", fallback = HelloRemoteHystrix.class)
public interface HelloRemote {

@GetMapping("/hello/")
String hello(@RequestParam(value = "name") String name);

}

 

別的就不用動了,很簡單吧!

測試

依次啟動 eureka-server、eureka-producer 和剛剛的 eureka-consumer-hystrix 這三個項目。

訪問:http://localhost:9003/hello/windmt
返回:[0]Hello, windmt! Sun Apr 15 23:14:25 CST 2018

說明加入 Hystrix 後,不影響正常的訪問。接下來我們手動停止 eureka-producer 項目再次測試:

訪問:http://localhost:9003/hello/windmt
返回:Hello World!

這時候我們再次啟動 eureka-producer 項目進行測試:

訪問:http://localhost:9003/hello/windmt
返回:[0]Hello, windmt! Sun Apr 15 23:14:52 CST 2018

根據返回結果說明熔斷成功。

總結

通過使用 Hystrix,我們能方便的防止雪崩效應,同時使系統具有自動降級和自動恢復服務的效果。

相關閱讀

Spring Cloud(一):服務治理技術概覽
Spring Cloud(二):服務註冊與發現 Eureka
Spring Cloud(三):服務提供與調用 Eureka
Spring Cloud(四):服務容錯保護 Hystrix
Spring Cloud(五):Hystrix 監控面板
Spring Cloud(六):Hystrix 監控數據聚合 Turbine
Spring Cloud(七):配置中心(Git 版與動態刷新)
Spring Cloud(八):配置中心(服務化與高可用)
Spring Cloud(九):配置中心(消息匯流排)
Spring Cloud(十):服務網關 Zuul(路由)
Spring Cloud(十一):服務網關 Zuul(過濾器)
Spring Cloud(十二):分散式鏈路跟蹤(Sleuth 與 Zipkin)

示例代碼:GitHub

參考

Spring Cloud - Feign Hystrix Support
springcloud(四):熔斷器 Hystrix
防雪崩利器:熔斷器 Hystrix 的原理與使用 
Spring Cloud 構建微服務架構:服務容錯保護(Hystrix 服務降級)【Dalston 版】
Spring Cloud 構建微服務架構:服務容錯保護(Hystrix 依賴隔離)【Dalston 版】
Spring Cloud 構建微服務架構:服務容錯保護(Hystrix 斷路器)【Dalston 版】
微服務框架 Spring Cloud 介紹 Part5: 在微服務系統中使用 Hystrix, Hystrix Dashboard 與 Turbine
使用 Spring Cloud 與 Docker 實戰微服務


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在介紹js中Object.defineProperty()和defineProperties()之前,我們瞭解下js中對象兩種屬性的類型:數據屬性和訪問器屬性。 數據屬性 數據屬性包含一個數據的位置,在這個位置可以讀取和寫入。其有4個描述其行為的特性 [[Configurable]] 表示能否通過d ...
  • JavaScript中對數組和數組API的認識 一、數組概念: 數組是JavaScript中的一類特殊的對象,用一對中括弧“[]”表示,用來在單個的變數中存儲多個值。在數組中,每個值都有一個對應的不重覆的索引值。自動匹配索引值的數組稱為索引數組,自定義索引值的數組稱為關聯數組(又叫哈希數組)。以下均 ...
  • 1、身份證 2、軍官證 3、護照 4、營業執照 5、駕照 6、組織機構代碼證 7、台胞證 8、港澳通行證 ...
  • 本文內容: 面向對象 常見內置對象及操作 首發日期:2018-05-11 面向對象: JavaScript 是面向對象的編程語言 (OOP)。OOP 語言使我們有能力定義自己的對象和變數類型。 對象是一種帶有屬性和方法的特殊變數類型。 如何創建對象: 使用內置對象類型創建一個內置對象:變數名=new... ...
  • 本文內容: 函數 函數的定義方式 函數的調用方式 函數的參數 匿名函數 函數中的this 事件 常見事件 綁定事件 首發日期:2018-05-11 函數: 函數的定義方式: 函數可以有參數,參數為局部變數,無需要var修飾: 函數可以有返回值: 函數的調用方式:除了自執行函數,其他函數都要手動調用 ... ...
  • 全局 DOM 變數 你可能已經知道,聲明一個全局變數(使用 var 或者不使用)的結果並不僅僅是創建一個全局變數,而且還會在 global 對象(在瀏覽器中為 window )中創建一個同名屬性。 還有一個不太為人所知的事實是:由於瀏覽器演進的歷史遺留問題,在創建帶有 id 屬性的 DOM 元素時也 ...
  • 點擊當前標簽給其添加class,兄弟標簽class刪除 演示地址: https://xibushijie.github.io/static/addClass.html ...
  • 簡單工廠模式簡介 工廠模式有一種非常形象的描述,建立對象的類就如一個工廠,而需要被建立的對象就是一個個產品;在工廠中加工產品,使用產品的人,不用在乎產品是如何生產出來的。從軟體開發的角度來說,這樣就有效的降低了模塊之間的耦合。 簡單工廠的作用是實例化對象,而不需要客戶瞭解這個對象屬於哪個具體的子類。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...