簡介
接上一篇Spring Cloud 學習筆記04----服務消費者(RestTemplate+Ribbon(用戶端負載均衡)),接下來我們來學習另外一個元件 斷路器(Hystrix)。
在微服務架構中,我們将系統拆分成很多個獨立服務單元,服務與服務之間通過RPC的方式調用,在Spring Cloud 中可以通過RestTemplate+Ribbon 或者Feign 的方式調用。為了保證高可用性,單個服務通常會叢集部署。這樣就有可能因為網絡原因或者是依賴服務自身問題出現調用故障或延遲,而這些問題會直接導緻調用方的對外服務也出現延遲,若此時調用方的請求不斷增加,最後等待出現故障的依賴方響應形成任務積壓,最終導緻自身服務的癱瘓。
斷路器(Hystrix)簡介
Netflix的創造了一個調用的庫Hystrix實作了斷路器圖案。在微服務架構中,通常有多層服務調用。
如圖所示,微服務圖
較低級别的服務中的服務故障可能導緻使用者級聯故障。當對特定服務的調用的不可用達到一個閥值時(Hystrix中的預設值為5秒内的20次故障),斷路器打開,向調用方傳回一個錯誤響應,而不是長時間的等待。這樣就不會使得線程因調用故障服務被長時間占用不釋放,避免了故障在分布式系統中的蔓延。
如下圖. Hystrix回退防止級聯故障
快速入門
在使用Spring Cloud Hystrix 實作斷路器之前。首先,我們先建構一個服務調用關系。
我們以上一篇的項目為基礎,首先啟動如下項目:
eureka-server 工程:服務注冊中心,端口1111
order-provider 工程: order-service的服務,兩個執行個體啟動端口分别是8081 和8082
service-ribbon 工程:使用Ribbon實作的服務消費者,端口為8764。
在未加入斷路器之前,關閉8081的執行個體,發送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 //開啟負載均衡
RestTemplate restTemplate() {
return new RestTemplate();
}
}
PS: 這裡可以使用Spring Cloud應用中的@SpringCloudApplication注解來修飾應用主類,該注解的具體定義如下所示。可以看到,該注解中包含了上述我們所引用的三個注解, 這也意味着一個Spring Cloud 标準應用包含服務發現以及斷路器。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
- 改造服務消費方式,在HelloService 類中,在getOrderService方法上增加
注解。代碼如下:@HystrixCommand
@HystrixCommand(fallbackMethod ="helloFallback" )
public String getOrderService() {
return restTemplate.getForObject("http://ORDER-SERVICE/dc",String.class);
}
public String helloFallback() {
return "服務出現故障了";
}
下面,我們來驗證一下斷路器實作的服務回調邏輯,重新啟動之前關閉的8081端口order-provider,確定此時服務注冊中心,兩個order-provider以及service-ribbon均已啟動,通路http://localhost:8764/getOrderService 可以輪詢到兩個order-provider 并傳回一些文字資訊。當輪詢到8081時,輸出内容
服務出現故障了
,不再是之前的錯誤内容,Hystrix的服務回調生效。
除了通過斷開具體的服務執行個體來模拟某個節點無法通路的情況之外,我們還可以模拟一下服務阻塞的情況,我們對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
接口的處理線程不是馬上傳回内容,而是在阻塞幾秒之後才傳回内容。由于Hystrix預設逾時時間為2000毫秒,是以這裡采取0至3000的随機數以讓處理過程有一定機率發生逾時來觸發斷路器。測試如下:
源碼位址
https://github.com/XWxiaowei/SpringCloud-Learning/tree/master/2-Finchley版教程示例/Chapter5-1