Spring Cloud構(gòu)建微服務(wù)架構(gòu):服務(wù)容錯保護(Hystrix服務(wù)降級)
前言
在微服務(wù)架構(gòu)中,我們將系統(tǒng)拆分成了一個個的服務(wù)單元,各單元應(yīng)用間通過服務(wù)注冊與訂閱的方式互相依賴。由于每個單元都在不同的進程中運行,依賴通過遠程調(diào)用的方式執(zhí)行,這樣就有可能因為網(wǎng)絡(luò)原因或是依賴服務(wù)自身問題出現(xiàn)調(diào)用故障或延遲,而這些問題會直接導(dǎo)致調(diào)用方的對外服務(wù)也出現(xiàn)延遲,若此時調(diào)用方的請求不斷增加,***就會出現(xiàn)因等待出現(xiàn)故障的依賴方響應(yīng)而形成任務(wù)積壓,線程資源無法釋放,最終導(dǎo)致自身服務(wù)的癱瘓,進一步甚至出現(xiàn)故障的蔓延最終導(dǎo)致整個系統(tǒng)的癱瘓。如果這樣的架構(gòu)存在如此嚴(yán)重的隱患,那么相較傳統(tǒng)架構(gòu)就更加的不穩(wěn)定。為了解決這樣的問題,因此產(chǎn)生了斷路器等一系列的服務(wù)保護機制。
針對上述問題,在Spring Cloud Hystrix中實現(xiàn)了線程隔離、斷路器等一系列的服務(wù)保護功能。它也是基于Netflix的開源框架 Hystrix實現(xiàn)的,該框架目標(biāo)在于通過控制那些訪問遠程系統(tǒng)、服務(wù)和第三方庫的節(jié)點,從而對延遲和故障提供更強大的容錯能力。Hystrix具備了服務(wù)降級、服務(wù)熔斷、線程隔離、請求緩存、請求合并以及服務(wù)監(jiān)控等強大功能。
接下來,我們就從一個簡單示例開始對Spring Cloud Hystrix的學(xué)習(xí)與使用。
動手試一試
在開始使用Spring Cloud Hystrix實現(xiàn)斷路器之前,我們先拿之前實現(xiàn)的一些內(nèi)容作為基礎(chǔ),其中包括:
- eureka-server工程:服務(wù)注冊中心,端口:1001
- eureka-client工程:服務(wù)提供者,兩個實例啟動端口分別為2001
下面我們可以復(fù)制一下之前實現(xiàn)的一個服務(wù)消費者:eureka-consumer-ribbon,命名為eureka-consumer-ribbon-hystrix。下面我們開始對其進行改在:
***步:pom.xml的dependencies節(jié)點中引入spring-cloud-starter-hystrix依賴:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-hystrix</artifactId>
- </dependency>
第二步:在應(yīng)用主類中使用@EnableCircuitBreaker或@EnableHystrix注解開啟Hystrix的使用:
- @EnableCircuitBreaker
- @EnableDiscoveryClient
- @SpringBootApplication
- public class Application {
- @Bean
- @LoadBalanced
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
- public static void main(String[] args) {
- new SpringApplicationBuilder(Application.class).web(true).run(args);
- }
- }
注意:這里我們還可以使用Spring Cloud應(yīng)用中的@SpringCloudApplication注解來修飾應(yīng)用主類,該注解的具體定義如下所示。我們可以看到該注解中包含了上我們所引用的三個注解,這也意味著一個Spring Cloud標(biāo)準(zhǔn)應(yīng)用應(yīng)包含服務(wù)發(fā)現(xiàn)以及斷路器。
- @Target({ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @SpringBootApplication
- @EnableDiscoveryClient
- @EnableCircuitBreaker
- public @interface SpringCloudApplication {
- }
第三步:改造服務(wù)消費方式,新增ConsumerService類,然后將在Controller中的邏輯遷移過去。***,在為具體執(zhí)行邏輯的函數(shù)上增加@HystrixCommand注解來指定服務(wù)降級方法,比如:
- @RestController
- public class DcController {
- @Autowired
- ConsumerService consumerService;
- @GetMapping("/consumer")
- public String dc() {
- return consumerService.consumer();
- }
- class ConsumerService {
- @Autowired
- RestTemplate restTemplate;
- @HystrixCommand(fallbackMethod = "fallback")
- public String consumer() {
- return restTemplate.getForObject("http://eureka-client/dc", String.class);
- }
- public String fallback() {
- return "fallback";
- }
- }
- }
下面我們來驗證一下上面Hystrix帶來的一些基礎(chǔ)功能。我們先把涉及的服務(wù)都啟動起來,然后訪問localhost:2101/consumer,此時可以獲取正常的返回,比如:Services: [eureka-consumer-ribbon-hystrix, eureka-client]。
為了觸發(fā)服務(wù)降級邏輯,我們可以將服務(wù)提供者eureka-client的邏輯加一些延遲,比如:
- @GetMapping("/dc")
- public String dc() throws InterruptedException {
- Thread.sleep(5000L);
- String services = "Services: " + discoveryClient.getServices();
- System.out.println(services);
- return services;
- }
重啟eureka-client之后,再嘗試訪問localhost:2101/consumer,此時我們將獲得的返回結(jié)果為:fallback。我們從eureka-client的控制臺中,可以看到服務(wù)提供方輸出了原本要返回的結(jié)果,但是由于返回前延遲了5秒,而服務(wù)消費方觸發(fā)了服務(wù)請求超時異常,服務(wù)消費者就通過HystrixCommand注解中指定的降級邏輯進行執(zhí)行,因此該請求的結(jié)果返回了fallback。這樣的機制,對自身服務(wù)起到了基礎(chǔ)的保護,同時還為異常情況提供了自動的服務(wù)降級切換機制。
更多Spring Cloud內(nèi)容請持續(xù)關(guān)注我的博客更新或在《Spring Cloud微服務(wù)實戰(zhàn)》中獲取。
代碼示例
樣例工程將沿用之前在碼云和GitHub上創(chuàng)建的SpringCloud-Learning項目,重新做了一下整理。通過不同目錄來區(qū)分Brixton和Dalston的示例。
碼云:點擊查看
GitHub:點擊查看
具體工程說明如下:
- eureka的服務(wù)注冊中心:eureka-server
- eureka的服務(wù)提供方:eureka-client
- eureka的服務(wù)消費者:eureka-consumer-ribbon-hystrix
【本文為51CTO專欄作者“翟永超”的原創(chuàng)稿件,轉(zhuǎn)載請通過51CTO聯(lián)系作者獲取授權(quán)】