Spring Cloud 學(xué)習(xí)筆記06----斷路器(Hystrix)(Finchley版本)
簡介
接上一篇Spring Cloud 學(xué)習(xí)筆記04----服務(wù)消費者(RestTemplate+Ribbon(客戶端負(fù)載均衡)),接下來我們來學(xué)習(xí)另外一個組件 斷路器(Hystrix)。
在微服務(wù)架構(gòu)中,我們將系統(tǒng)拆分成很多個獨立服務(wù)單元,服務(wù)與服務(wù)之間通過RPC的方式調(diào)用,在Spring Cloud 中可以通過RestTemplate+Ribbon 或者Feign 的方式調(diào)用。為了保證高可用性,單個服務(wù)通常會集群部署。這樣就有可能因為網(wǎng)絡(luò)原因或者是依賴服務(wù)自身問題出現(xiàn)調(diào)用故障或延遲,而這些問題會直接導(dǎo)致調(diào)用方的對外服務(wù)也出現(xiàn)延遲,若此時調(diào)用方的請求不斷增加,最后等待出現(xiàn)故障的依賴方響應(yīng)形成任務(wù)積壓,最終導(dǎo)致自身服務(wù)的癱瘓。
斷路器(Hystrix)簡介
Netflix的創(chuàng)造了一個調(diào)用的庫Hystrix實現(xiàn)了斷路器圖案。在微服務(wù)架構(gòu)中,通常有多層服務(wù)調(diào)用。
如圖所示,微服務(wù)圖
較低級別的服務(wù)中的服務(wù)故障可能導(dǎo)致用戶級聯(lián)故障。當(dāng)對特定服務(wù)的調(diào)用的不可用達到一個閥值時(Hystrix中的默認(rèn)值為5秒內(nèi)的20次故障),斷路器打開,向調(diào)用方返回一個錯誤響應(yīng),而不是長時間的等待。這樣就不會使得線程因調(diào)用故障服務(wù)被長時間占用不釋放,避免了故障在分布式系統(tǒng)中的蔓延。
如下圖. Hystrix回退防止級聯(lián)故障
快速入門
在使用Spring Cloud Hystrix 實現(xiàn)斷路器之前。首先,我們先構(gòu)建一個服務(wù)調(diào)用關(guān)系。
我們以上一篇的項目為基礎(chǔ),首先啟動如下項目:
eureka-server 工程:服務(wù)注冊中心,端口1111
order-provider 工程: order-service的服務(wù),兩個實例啟動端口分別是8081 和8082
service-ribbon 工程:使用Ribbon實現(xiàn)的服務(wù)消費者,端口為8764。
在未加入斷路器之前,關(guān)閉8081的實例,發(fā)送GET請求到http://localhost:8764/getOrderService,可以看到如下輸出
引入Hystrix。
- 在service-ribbon 工程的pom.xml 引入 spring-cloud-starter-hystrix 依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 在service-ribbon 工程的主類ServiceRibbonApplication中使用
@EnableCircuitBreaker
注解開啟斷路器功能:
@SpringBootApplication
@EnableEurekaClient //ribbon
@EnableCircuitBreaker //斷路器
@SpringCloudApplication
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
@Bean
@LoadBalanced //開啟負(fù)載均衡
RestTemplate restTemplate() {
return new RestTemplate();
}
}
PS: 這里可以使用Spring Cloud應(yīng)用中的@SpringCloudApplication注解來修飾應(yīng)用主類,該注解的具體定義如下所示??梢钥吹?,該注解中包含了上述我們所引用的三個注解, 這也意味著一個Spring Cloud 標(biāo)準(zhǔn)應(yīng)用包含服務(wù)發(fā)現(xiàn)以及斷路器。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
- 改造服務(wù)消費方式,在HelloService 類中,在getOrderService方法上增加
@HystrixCommand
注解。代碼如下:
@HystrixCommand(fallbackMethod ="helloFallback" )
public String getOrderService() {
return restTemplate.getForObject("http://ORDER-SERVICE/dc",String.class);
}
public String helloFallback() {
return "服務(wù)出現(xiàn)故障了";
}
下面,我們來驗證一下斷路器實現(xiàn)的服務(wù)回調(diào)邏輯,重新啟動之前關(guān)閉的8081端口order-provider,確保此時服務(wù)注冊中心,兩個order-provider以及service-ribbon均已啟動,訪問http://localhost:8764/getOrderService 可以輪詢到兩個order-provider 并返回一些文字信息。當(dāng)輪詢到8081時,輸出內(nèi)容服務(wù)出現(xiàn)故障了
,不再是之前的錯誤內(nèi)容,Hystrix的服務(wù)回調(diào)生效。
除了通過斷開具體的服務(wù)實例來模擬某個節(jié)點無法訪問的情況之外,我們還可以模擬一下服務(wù)阻塞的情況,我們對order-provider中增加/hello
接口,具體如下:
@GetMapping("/hello")
public String hello(HttpServletRequest request) throws InterruptedException {
// 讓處理線程等待幾分鐘
int sleepTime = new Random().nextInt(3000);
Thread.sleep(sleepTime);
String services = "Services: " + discoveryClient.getServices() + ";port=" + request.getServerPort();
System.out.println(services);
return "hello world";
}
通過Thread.sleep()方法可以讓/hello
接口的處理線程不是馬上返回內(nèi)容,而是在阻塞幾秒之后才返回內(nèi)容。由于Hystrix默認(rèn)超時時間為2000毫秒,所以這里采取0至3000的隨機數(shù)以讓處理過程有一定概率發(fā)生超時來觸發(fā)斷路器。測試如下:
源碼地址
https://github.com/XWxiaowei/SpringCloud-Learning/tree/master/2-Finchley版教程示例/Chapter5-1
參考
【Spring Cloud 微服務(wù)實戰(zhàn) 第5章】
作者:碼農(nóng)飛哥
微信公眾號:碼農(nóng)飛哥