前一章節,咱們知道了如何利用
RestTemplate
+Ribbon
和Feign
的方式進行服務的調用。在微服務架構中,一個服務可能會調用不少的其餘微服務應用,雖然作了多集羣部署,但可能還會存在諸如網絡緣由或者服務提供者自身處理的緣由,或多或少都會出現請求失敗或者請求延遲問題,若服務提供者長期未對請求作出迴應,服務消費者又不斷的請求下,可能就會形成服務提供者服務崩潰,進而服務消費者也一塊兒跟着不可用,嚴重的時候就發生了系統雪崩
了。鑑於此,產生了斷路器等一系列的服務保護機制。本章節,就來講下如何利用Hystrix
進行容錯處理。html
按照此係列的慣例,咱們先來了解下一些相關的知識。java
注:如下部份內容轉至大佬純潔的微笑:熔斷器Hystrix。git
容錯處理是指軟件運行時,能對由非正常因素引發的運行錯誤給出適當的處理或信息提示,使軟件運行正常結束——百度百科程序員
從百度百科的解釋中能夠看出,簡單理解,所謂的容錯處理
其實就是捕獲異常了,不讓異常影響系統的正常運行,正如java
中的try catch
同樣。github
而在微服務調用中,自身異常可自行處理外,對於依賴的服務若發生錯誤,或者調用異常,或者調用時間過長等緣由時,避免長時間等待,形成系統資源耗盡。 通常上都會經過設置請求的超時時間
,如http
請求中的ConnectTimeout
和ReadTimeout
;再或者就是使用熔斷器
模式,隔離問題服務,防止級聯錯誤等。spring
在微服務架構中,存在不少的微服務單元,各個微服務之間經過網絡進行通信,不免出現依賴關係,若某一個單元
出現故障
,就很容易因依賴關係而引起故障的蔓延,產生「雪崩效應」
,最終致使整個系統的癱瘓。設計模式
下面這張圖,相比你們都有看過了。瀏覽器
如圖所示:A做爲服務提供者,B爲A的服務消費者,C和D是B的服務消費者。A不可用引發了B的不可用,並將不可用像滾雪球同樣放大到C和D時,雪崩效應就造成了。也就應了那句話:星星之火,能夠燎原!服務器
熔斷器,和現實生活中的空氣開關
做用很像。它能夠實現快速失敗,若是它在一段時間內偵測到許多相似的錯誤,會強迫其之後的多個調用快速失敗,再也不訪問遠程服務器,從而防止應用程序不斷地嘗試執行可能會失敗的操做,使得應用程序繼續執行而不用等待修正錯誤,或者浪費CPU時間去等到長時間的超時產生。熔斷器也可使應用程序可以診斷錯誤是否已經修正,若是已經修正,應用程序會再次嘗試調用操做。微信
熔斷器模式就像是那些容易致使錯誤的操做的一種代理。這種代理可以記錄最近調用發生錯誤的次數,而後決定使用容許操做繼續,或者當即返回錯誤。
能夠看出,熔斷器一共有三種狀態,之間轉換關係以下:
我的以爲,主要仍是快速失敗,避免請求堆積,壓垮服務器。進而起到保護服務高可用的目的。
Hystrix是一個實現了超時機制和斷路器模式的工具類庫。
Hystrix是有Netflix開源的一個延遲和容錯庫,用於隔離訪問遠程系統、服務或第三方庫,防止級聯失敗,從而提高系統的可用性和容錯性。
Hystrix容錯機制:
下圖就是Hystrix
的回退策略,防止級聯故障。
建立個工程spring-cloud-hystrix
工程。 0.引入POM依賴。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
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 @LoadBalanced public RestTemplate restTemplat() { return new RestTemplate(); } }
2.編寫一個測試類,加入@HystrixCommand
,指定fallbackMethod
方法。
RibbonController.java
/** * ribbon 常規方式-示例 * @author oKong * */ @RestController @Slf4j public class RibbonController { @Autowired RestTemplate 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
註解,咱們能夠放在任何一個調用函數裏面,以此實現調用方法發生異常或者錯誤時,能夠快速返回,避免持續請求,形成資源的耗盡。
如上小節說示例的,當咱們方法不少時,要是分別編寫一個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 @LoadBalanced public RestTemplate restTemplat() { return new RestTemplate(); } }
IHelloClient.java
,同時定義fallback
或者fallbackFactory
屬性值。注意:二者 同時設置時,優先調用fallback
,fallbackFactory
不進行調用了。@FeignClient(name="eureka-client",/*fallback=HelloClientFailImpl.class,*/ fallbackFactory = HelloClientFallbackFactory.class) public interface IHelloClient { /** * 定義接口 * @param name * @return */ @RequestMapping(value="/hello", method=RequestMethod.GET) public String hello(@RequestParam("name") String name); }
fallback
和fallbackFactory
屬性對應類。HelloClientFailImpl.java
@Component("fallback") @Slf4j public class HelloClientFailImpl implements IHelloClient{ @Override public 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; @Override public 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:
@Bean public Feign.Builder feignHystrixBuilder() { return HystrixFeign.builder(); }
也是能夠的。
4.編寫一個測試類FeignController
:
/** * feign 熔斷器示例 * @author oKong * */ @RestController @Slf4j public class FeignController { @Autowired IHelloClient 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版的,但原理是差很少的~
本章節主要講解了如何整合
Hystrix
。自己Hystrix
已經包含了服務降級
、依賴隔離
、熔斷器
等功能了,咱們使用時並沒進行特殊設置,默認都是生效的。對於一些關於Hystrix
的高級用法,好比信號量
隔離、線程池的設置等等,還有一些像超時時間
等,因爲此方面瞭解的很少,這裏就不班門弄斧了。你們可去官方網站或者谷歌搜索下相關材料下,對於一些業務場景,可進行一些自定義設置。主要仍是針對@HystrixCommand
註解的相關配置。關於調用統一異常的處理相關實踐,好比當提供方異常時,調用方如何進行統一異常處理,或者服務不可用時,進行統一的異常捕獲,告知外圍調用者服務不可用等信息。這些相關實踐部分會在以後的實踐篇系列文章中進行闡述的,也許不是最佳的實踐,僅但願提供一個參考方案吧。這裏就不表了,敬請期待~
目前互聯網上大佬都有分享
SpringCloud
系列教程,內容可能會相似,望多多包涵了。原創不易,碼字不易,還但願你們多多支持。若文中有錯誤之處,還望提出,謝謝。
499452441
lqdevOps
我的博客:http://blog.lqdev.cn
源碼示例:https://github.com/xie19900123/spring-cloud-learning
原文地址:http://blog.lqdev.cn/2018/09/23/SpringCloud/chapter-five/