javascript
白话SpringCloud | 第五章:服务容错保护(Hystrix)
前言
前一章節,我們知道了如何利用RestTemplate+Ribbon和Feign的方式進行服務的調用。在微服務架構中,一個服務可能會調用很多的其他微服務應用,雖然做了多集群部署,但可能還會存在諸如網絡原因或者服務提供者自身處理的原因,或多或少都會出現請求失敗或者請求延遲問題,若服務提供者長期未對請求做出回應,服務消費者又不斷的請求下,可能就會造成服務提供者服務崩潰,進而服務消費者也一起跟著不可用,嚴重的時候就發生了系統雪崩了。鑒于此,產生了斷路器等一系列的服務保護機制。本章節,就來說下如何利用Hystrix進行容錯處理。
- 一點知識
- 容錯處理手段
- 雪崩效應
- 熔斷器
- Hystrix實踐
- 何為Hystrix
- 常規方式整合Hystrix
- Feign整合Hystrix
- 參考資料
- 總結
- 最后
- 老生常談
一點知識
按照此系列的慣例,我們先來了解下一些相關的知識。
注:以下部分內容轉至大佬純潔的微笑:熔斷器Hystrix。
容錯處理手段
容錯處理是指軟件運行時,能對由非正常因素引起的運行錯誤給出適當的處理或信息提示,使軟件運行正常結束——百度百科
從百度百科的解釋中可以看出,簡單理解,所謂的容錯處理其實就是捕獲異常了,不讓異常影響系統的正常運行,正如java中的try catch一樣。
而在微服務調用中,自身異常可自行處理外,對于依賴的服務若發生錯誤,或者調用異常,或者調用時間過長等原因時,避免長時間等待,造成系統資源耗盡。
一般上都會通過設置請求的超時時間,如http請求中的ConnectTimeout和ReadTimeout;再或者就是使用熔斷器模式,隔離問題服務,防止級聯錯誤等。
雪崩效應
在微服務架構中,存在很多的微服務單元,各個微服務之間通過網絡進行通訊,難免出現依賴關系,若某一個單元出現故障,就很容易因依賴關系而引發故障的蔓延,產生“雪崩效應”,最終導致整個系統的癱瘓。
下面這張圖,相比大家都有看過了。
如圖所示:A作為服務提供者,B為A的服務消費者,C和D是B的服務消費者。A不可用引起了B的不可用,并將不可用像滾雪球一樣放大到C和D時,雪崩效應就形成了。也就應了那句話:星星之火,可以燎原!
熔斷器
熔斷器,和現實生活中的空氣開關作用很像。它可以實現快速失敗,如果它在一段時間內偵測到許多類似的錯誤,會強迫其以后的多個調用快速失敗,不再訪問遠程服務器,從而防止應用程序不斷地嘗試執行可能會失敗的操作,使得應用程序繼續執行而不用等待修正錯誤,或者浪費CPU時間去等到長時間的超時產生。熔斷器也可以使應用程序能夠診斷錯誤是否已經修正,如果已經修正,應用程序會再次嘗試調用操作。
熔斷器模式就像是那些容易導致錯誤的操作的一種代理。這種代理能夠記錄最近調用發生錯誤的次數,然后決定使用允許操作繼續,或者立即返回錯誤。
可以看出,熔斷器一共有三種狀態,之間轉換關系如下:
- 關閉狀態
當熔斷器處于關閉狀態時,請求是可以被放行的;
當熔斷器統計的失敗次數觸發開關時,轉為打開狀態。 - 打開狀態
當熔斷器處于打開狀態時,所有請求都是不被放行的,直接返回失敗;
只有在經過一個設定的時間窗口周期后,熔斷器才會轉換到半開狀態 - 半開狀態
當熔斷器處于半開狀態時,當前只能有一個請求被放行;
這個被放行的請求獲得遠端服務的響應后,假如是成功的,熔斷器轉換為關閉狀態,否則轉換到打開狀態。
個人覺得,主要還是快速失敗,避免請求堆積,壓垮服務器。進而起到保護服務高可用的目的。
Hystrix實踐
何為Hystrix
Hystrix是一個實現了超時機制和斷路器模式的工具類庫。
Hystrix是有Netflix開源的一個延遲和容錯庫,用于隔離訪問遠程系統、服務或第三方庫,防止級聯失敗,從而提升系統的可用性和容錯性。
Hystrix容錯機制:
- 包裹請求:使用HystrixCommand包裹對依賴的調用邏輯,每個命令在獨立線程中執行,這是用到了設計模式“命令模式”。
- 跳閘機制:當某服務的錯誤率超過一定閾值時,Hystrix可以自動或手動跳閘,停止請求該服務一段時間。
- 資源隔離:Hystrix為每個依賴都維護了一個小型的線程池,如果該線程池已滿,發往該依賴的請求就被立即拒絕,而不是排隊等候,從而加速判定失敗。
- 監控:Hystrix可以近乎實時的監控運行指標和配置的變化。如成功、失敗、超時、被拒絕的請求等。
- 回退機制:當請求失敗、超時、被拒絕,或當斷路器打開時,執行回退邏輯。回退邏輯可自定義。
- 自我修復:斷路器打開一段時間后,會自動進入半開狀態,斷路器打開、關閉、半開的邏輯轉換。
下圖就是Hystrix的回退策略,防止級聯故障。
常規方式整合Hystrix
創建個工程spring-cloud-hystrix工程。
0.引入POM依賴。
1.啟動類,加入注解@EnableHystrix,同時申明一個實現負載均衡的RestTemplate。(關于消費者服務可查看:第四章:服務消費者(RestTemple+Ribbon+Feign),這里不再闡述了。)
/*** 熔斷器示例* @author oKong**/ @SpringBootApplication @EnableHystrix @EnableDiscoveryClient @Slf4j public class HystrixApplication {public static void main(String[] args) throws Exception {SpringApplication.run(HystrixApplication.class, args);log.info("sprign-cloud-hystrix啟動!");}@Bean@LoadBalancedpublic RestTemplate restTemplat() {return new RestTemplate();}}2.編寫一個測試類,加入@HystrixCommand,指定fallbackMethod方法。
RibbonController.java
/*** ribbon 常規方式-示例* @author oKong**/ @RestController @Slf4j public class RibbonController {@AutowiredRestTemplate restTemplate;@GetMapping("/ribbon")@HystrixCommand(fallbackMethod="fallback")public String hello(String name) {log.info("使用restTemplate調用服務,參數name:{}", name);return restTemplate.getForObject("http://eureka-client/hello?name=" + name, String.class);}/*** 發生熔斷時調用的方法* @param name* @param throwable 發生異常時的異常信息* @return*/public String fallback(String name,Throwable throwable) {log.error("熔斷發生了:{}", throwable);log.warn("restTemplate調用服務發生熔斷,參數name:{}", name);return "restTemplate調用服務發生熔斷,參數name:" + name;} }注意:這里fallback方法加入了一個參數throwable,當發生熔斷時,可以獲悉發生熔斷的異常信息,便于定位問題和原因。
3.啟動應用,訪問:http://127.0.0.1:8038/ribbon?name=oKong 。正常情況下,spring-cloud-eureka-client應用正常運行時,返回正常結果:
現在我們停止提供者服務,再次訪問,可以看見已經進入熔斷方法了:
控制臺可以看見異常輸出:
由于實例尚未被剔除注冊中心的服務列表,所以提示是連接超時,等待一段時間后,再次訪問服務,可以看見是提示實例不存在了:
注意:對于@HystrixCommand注解,我們可以放在任何一個調用函數里面,以此實現調用方法發生異常或者錯誤時,可以快速返回,避免持續請求,造成資源的耗盡。
Feign整合Hystrix
如上小節說示例的,當我們方法很多時,要是分別編寫一個fallback估計也是崩潰的,雖然可以使用一個通用的fallback,但未進行特殊設置下,也是無法知道具體是哪個方法發生熔斷的。
而對于Feign,我們可以使用一種更加優雅的形式進行。我們可以指定@FeignClient注解的fallback屬性,或者是fallbackFactory屬性,后者可以獲取異常信息的。
修改spring-cloud-hystrix工程。
0.引入Feigin的POM依賴。
<!-- feign --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>1.啟動類,加入@EnableFeignClients啟用Feign.
*** 熔斷器示例* @author oKong**/ @SpringBootApplication @EnableHystrix @EnableDiscoveryClient @EnableFeignClients @Slf4j public class HystrixApplication {public static void main(String[] args) throws Exception {SpringApplication.run(HystrixApplication.class, args);log.info("sprign-cloud-hystrix啟動!");}@Bean@LoadBalancedpublic RestTemplate restTemplat() {return new RestTemplate();}}HelloClientFailImpl.java
@Component("fallback") @Slf4j public class HelloClientFailImpl implements IHelloClient{@Overridepublic String hello(String name) {log.error("restTemplate調用[hello]服務發生熔斷,參數name:{}", name);return "restTemplate調用[hello]服務發生熔斷,參數name:" + name;} }HelloClientFallbackFactory/java
@Component @Slf4j public class HelloClientFallbackFactory implements FallbackFactory<IHelloClient>{@Autowired@Qualifier("fallback")IHelloClient helloClient;@Overridepublic IHelloClient create(Throwable cause) {log.error("feign調用發生異常,觸發熔斷", cause);return helloClient;}}可以知道,正常fallback就是一個接口的實現類,當發送異常時,會調用此接口實現類進行服務調用。而FallbackFactory是也是一個接口實現類,需要實現feign.hystrix.FallbackFactory<T>接口,在發生熔斷時,調用create方法,同時返回被調用接口的實現類,以便進行fallback處理。
3.配置文件開啟feign的熔斷器功能。
feign.hystrix.enabled=true或者,申明一個Feign.Builder類也是可以的,我們從org.springframework.cloud.openfeign.FeignClientsConfiguration可以看出,啟用feign的條件:
所以正常,我們只需要在配置文件中加入feign.hystrix.enabled為true即可,注意:此屬性在IDE下未進行提示的。
或者就如此類一樣,申明一個bean:
也是可以的。
4.編寫一個測試類FeignController:
/*** feign 熔斷器示例* @author oKong**/ @RestController @Slf4j public class FeignController {@AutowiredIHelloClient helloClient;@GetMapping("/feign")public String hello(String name) {log.info("使用feign調用服務,參數name:{}", name);return helloClient.hello(name);}}5.再次啟動應用,訪問:http://127.0.0.1:8038/feign?name=oKong ,正常調用如下:
關閉服務提供者,再次訪問,瀏覽器返回了錯誤提示:
同時,我們使用了FallbackFactory,控制臺打印出了具體異常:
針對熔斷超時時間等相關設置,可以通過@HystrixCommand注解的各屬性進行配置,主要還是commandProperties屬性值,具體的參數可查看com.netflix.hystrix.HystrixCommandProperties類,也可以針對某個調用方法進行特殊設置。具體的可以看看這篇文章:hystrix的基本介紹和配置屬性說明,或者可以去大佬程序員DD博客查閱下關于Hystrix相關知識點:服務容錯保護(Hystrix斷路器)【Dalston版】、服務容錯保護(Hystrix依賴隔離)【Dalston版】,版本雖然是D版的,但原理是差不多的~
參考資料
http://www.ityouknow.com/springcloud/2017/05/16/springcloud-hystrix.html
https://cloud.spring.io/spring-cloud-static/Finchley.SR1/single/spring-cloud.html#_circuit_breaker_hystrix_clients
總結
本章節主要講解了如何整合Hystrix。本身Hystrix已經包含了服務降級、依賴隔離、熔斷器等功能了,我們使用時并沒進行特殊設置,默認都是生效的。對于一些關于Hystrix的高級用法,比如信號量隔離、線程池的設置等等,還有一些像超時時間等,由于此方面了解的不多,這里就不班門弄斧了。大家可去官方網站或者谷歌搜索下相關材料下,對于一些業務場景,可進行一些自定義設置。主要還是針對@HystrixCommand注解的相關配置。關于調用統一異常的處理相關實踐,比如當提供方異常時,調用方如何進行統一異常處理,或者服務不可用時,進行統一的異常捕獲,告知外圍調用者服務不可用等信息。這些相關實踐部分會在之后的實踐篇系列文章中進行闡述的,也許不是最佳的實踐,僅希望提供一個參考方案吧。這里就不表了,敬請期待~
最后
目前互聯網上大佬都有分享SpringCloud系列教程,內容可能會類似,望多多包涵了。原創不易,碼字不易,還希望大家多多支持。若文中有錯誤之處,還望提出,謝謝。
老生常談
- 個人QQ:499452441
- 微信公眾號:lqdevOps
個人博客:http://blog.lqdev.cn
源碼示例:https://github.com/xie19900123/spring-cloud-learning
原文地址:http://blog.lqdev.cn/2018/09/23/SpringCloud/chapter-five/
轉載于:https://www.cnblogs.com/okong/p/springcloud-five.html
總結
以上是生活随笔為你收集整理的白话SpringCloud | 第五章:服务容错保护(Hystrix)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P2184 【贪婪大陆】
- 下一篇: C语言 —— 贪吃蛇