Hystrix斷路器
Hystrix斷路器
解決問題: 主要防止伺服器叢集發生雪崩, 起到對伺服器的保護作用
github地址: https://github.com/Netflix/Hystrix/wiki
介紹
背景
分散式系統環境下,服務間類似依賴非常常見,一個業務呼叫通常依賴多個基礎服務。如下圖,對於同步呼叫,當庫存服務不可用時,商品服務請求執行緒被阻塞,當有大批量請求呼叫庫存服務時,最終可能導致整個商品服務資源耗盡,無法繼續對外提供服務。並且這種不可用可能沿請求呼叫鏈向上傳遞,這種現象被稱為雪崩效應。
圖解
雪崩效應常見場景
- 硬體故障:如伺服器宕機,機房斷電,光纖被挖斷等。
- 流量激增:如異常流量,重試加大流量等。
- 快取穿透:一般發生在應用重啟,所有快取失效時,以及短時間內大量快取失效時。大量的快取不命中,使請求直擊後端服務,造成服務提供者超負荷執行,引起服務不可用。
- 程式BUG:如程式邏輯導致記憶體洩漏,JVM長時間FullGC等。
- 同步等待:服務間採用同步呼叫模式,同步等待造成的資源耗盡。
雪崩效應應對策略
針對造成雪崩效應的不同場景,可以使用不同的應對策略,沒有一種通用所有場景的策略,參考如下:
- 硬體故障:多機房容災、異地多活等。
- 流量激增:服務自動擴容、流量控制(限流、關閉重試)等。
- 快取穿透:快取預載入、快取非同步載入等。
- 程式BUG:修改程式bug、及時釋放資源等。
- 同步等待:資源隔離、MQ解耦、不可用服務呼叫快速失敗等。資源隔離通常指不同服務呼叫採用不同的執行緒池;不可用服務呼叫快速失敗一般通過熔斷器模式結合超時機制實現。
綜上所述,如果一個應用不能對來自依賴的故障進行隔離,那該應用本身就處在被拖垮的風險中。 因此,為了構建穩定、可靠的分散式系統,我們的服務應當具有自我保護能力,當依賴服務不可用時,當前服務啟動自我保護功能,從而避免發生雪崩效應。本文將重點介紹使用Hystrix解決同步等待的雪崩問題。
Hystrix兩大功能
- 降級,超時、出錯、不可到達時,對服務降級,返回錯誤資訊或者是快取資料
- 熔斷,當服務壓力過大,錯誤比例過多時,熔斷所有請求,所有請求直接降級
降級
一個服務呼叫後臺服務失敗(出現異常、等待超時、不能連線),可以執行當前服務中的一段程式碼,向前返回響應(錯誤提示、快取資料)
系統容錯,當後臺服務出現錯誤,還可以向客戶端返回結果
熔斷
10秒內20次請求,50%呼叫失敗,執行了降級程式碼,會觸發熔斷
熔斷可以避免故障的傳播,避免引起雪崩效應
限流,後臺服務壓力過大出現故障,可以斷開連線,限制訪問流量
熔斷的條件(兩個條件必須都滿足)
- 10秒20次請求(首先滿足)
- 50%失敗,執行了降級程式碼
半開狀態
斷路器開啟5秒後,會進入半開狀態,
客戶端請求時,會嘗試傳送一次呼叫,
如果成功,會自動關閉斷路器,恢復正常
如果失敗,就繼續保持開啟狀態
Hystrix的使用
和ribbon聯用 [跳轉ribbon]
1. maven依賴
在springboot中匯入Hystrix [Maintenance]
依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2. 新增主程式註解
主要是把@EnableCircuitBreaker
註解到主啟動類
以下3個註解可以使用@SpringCloudApplication
註解代替
@EnableCircuitBreaker // 開啟Hystrix的註解, 啟動斷路器
//@EnableDiscoveryClient // 開啟eureka的註解, 高版本可省略
@SpringBootApplication
public class Sp06RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(Sp06RibbonApplication.class, args);
}
// ribbon配置, RestTemplate物件
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
f.setConnectTimeout(1000);
f.setReadTimeout(1000);
return new RestTemplate();
}
}
3. 降級斷路示例
使用@HystrixCommand
註解來實現降級, 實現步驟如下:
- 使用
@HystrixCommand(fallbakMethod="降級方法名")
註解, 放在正常執行的業務程式碼方法上, 這個業務員程式碼中呼叫了後端的伺服器, 引數fallbakMethod為字串型別, 指向降級的方法名 - 然後再同一個類下, 宣告降級的方法, 即上面fallbakMethod引數指定的方法
如下程式碼
@RestController
@Slf4j
public class RibbonController {
// 注入RestTemplate物件 (ribbon)
@Autowired
private RestTemplate restTemplate;
// 處理請求業務, 呼叫後端伺服器
@GetMapping("/item-service/{orderId}")
@HystrixCommand(fallbackMethod = "getItemsFB") // 使用降級註解
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
log.info("呼叫後臺商品服務, 獲取商品列表");
JsonResult r = restTemplate.getForObject(
"http://item-service/{1}",
JsonResult.class,
orderId);
return r;
}
// 降級後執行的方法
public JsonResult<List<Item>> getItemsFB(@PathVariable String orderId) {
return JsonResult.err().msg("獲取商品失敗");
}
}
即, 當我們的正常業務getItems方法呼叫後端伺服器(出現異常、等待超時[超時時間預設為1秒]、不能連線)時, 執行getItemsFB方法
Hystrix 超時設定
hystrix等待超時後, 會執行降級程式碼, 快速向客戶端返回降級結果, 預設超時時間是1000毫秒
思考: 當呼叫後端伺服器超時的時候(Hystrix預設超時時間為1秒), 伺服器是否會進行重試或者更換伺服器的操作(ribbon)??????
假如如下為ribbon的超時時間(1秒)
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
f.setConnectTimeout(1000);
f.setReadTimeout(1000);
return new RestTemplate();
}
以及重試和更換伺服器的次數
ribbon:
MaxAutoRetriesNextServer: 2
MaxAutoRetries: 1
OkToRetryOnAllOperations: true
答案也是很明顯的重試依然會執行, 也會執行降級方法的執行結果, 但是我們的重試和更換伺服器的操作幾乎沒有意義了
那麼我們如何解決這一問題呢?
我們可以設定Hystrix 超時時間, 即降級執行的時間, 此設定一般應大於 ribbon 的重試超時時長,例如 10 秒
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10000
如果呼叫後端服務超時, hystrix 才會立即執行降級方法
如果呼叫的後端服務未啟動, hystrix也會立即執行降級方法
dashboard 斷路器儀表盤
hystrix 對請求的降級和熔斷,可以產生監控資訊,hystrix dashboard可以實時的進行監控
儀表盤一般都是獨立執行的
斷路儀表盤依賴springboot的actuator工具 關於actuator功能 [actuator監控]
1. actuator依賴
在被監控的專案中(Hystrix專案)新增actuator依賴, 並配置了配置檔案
依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yml配置檔案
management:
endpoints:
web:
exposure:
include: "*" # 一定要加引號
被監控專案啟動後訪問: http://localhost:3001/actuator
(ip和埠寫自己的) 檢視效果
如果一直顯示ping:
, 可傳送一次請求, 出現一大坨資訊就是配置成功了
2. 建立儀表盤專案
我們重新新建一個專案, 用來監控
匯入Hystrix Dashboard
依賴 :
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
3. 配置檔案
配置檔案只需要進行簡單的配置即可
spring:
application:
name: hystrix-dashboard # 服務名
server:
port: 4001 # 埠號
4. 添加註解
在主啟動類上新增一個註解@EnableHystrixDashboard
@EnableHystrixDashboard
@SpringBootApplication
public class Sp08HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(Sp08HystrixDashboardApplication.class, args);
}
}
5. 訪問hystrix dashboard
http://localhost:4001/hystrix
ip/域名和埠寫自己的即可
可以看到如下頁面:
然後輸入我們的被監控的Hystrix服務的網址, 點選Monitor Stream即可
我的是http://localhost:3001/actuator
, 我就填入這個
關於儀表盤的資訊如何檢視:
hystrix 熔斷
整個鏈路達到一定的閾值,預設情況下,10秒內產生超過20次請求,則符合第一個條件。
滿足第一個條件的情況下,如果請求的錯誤百分比大於閾值,則會開啟斷路器,預設為50%。
Hystrix的邏輯,先判斷是否滿足第一個條件,再判斷第二個條件,如果兩個條件都滿足,則會開啟斷路器
斷路器開啟 5 秒後,會處於半開狀態,會嘗試轉發請求,如果仍然失敗,保持開啟狀態,如果成功,則關閉斷路器
併發訪問測試
使用 apache 的併發訪問測試工具 ab
http://httpd.apache.org/docs/current/platform/windows.html#down
-
用 ab 工具,以併發50次,來發送20000個請求
ab -n 20000 -c 50 http://localhost:3001/item-service/35
-
斷路器狀態為 Open,所有請求會被短路,直接降級執行 fallback 方法
hystrix 配置
https://github.com/Netflix/Hystrix/wiki/Configuration
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
請求超時時間,超時後觸發失敗降級hystrix.command.default.circuitBreaker.requestVolumeThreshold
10秒內請求數量,預設20,如果沒有達到該數量,即使請求全部失敗,也不會觸發斷路器開啟hystrix.command.default.circuitBreaker.errorThresholdPercentage
失敗請求百分比,達到該比例則觸發斷路器開啟hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
斷路器開啟多長時間後,再次允許嘗試訪問(半開),仍失敗則繼續保持開啟狀態,如成功訪問則關閉斷路器,預設 5000