1.前言
經過上一篇博客的Ribbon和OpenFeign學習後,接下來我們正式開始熔斷機制的學習,目前常用的服務間調用組件有Hystrix,這裏我們就重點來學習一下這個組件的使用。
2.Hystrix整合Ribbon
我們知道大量請求會阻塞在Tomcat服務器上,影響其它整個服務.在複雜的分佈式架構的應用程序有很多的依賴,都會不可避免地在某些時候失敗.高併發的依賴失敗時如果沒有隔離措施,當前應用服務就有被拖垮的風險。
Spring Cloud Netflix Hystrix就是隔離措施的一種實現,可以設置在某種超時或者失敗情形下斷開依賴調用或者返回指定邏輯,從而提高分佈式系統的穩定性。
生活中舉個例子,如電力過載保護器,當電流過大的的時候,出問題,過載器會自動斷開,從而保護電器不受燒壞。因此Hystrix請求熔斷的機制跟電力過載保護器的原理很類似。
比如:訂單系統請求庫存系統,結果一個請求過去,因爲各種原因,網絡超時,在規定幾秒內沒反應,或者服務本身就掛了,這時候更多的請求來了,不斷的請求庫存服務,不斷的創建線程,因爲沒有返回,也就資源沒有釋放。
Hystrix特性:
- 請求熔斷
當請求後端服務失敗數量超過一定比例(默認50%), 斷路器會切換到開路狀態(Open). 這時所有請求會直接失敗而不會發送到後端服務. 斷路器保持在開路狀態一段時間後(默認5秒), 自動切換到半開路狀態(HALF-OPEN)。 - 服務降級
當請求後端服務出現異常的時候, 服務降級就是用來提供一個基礎服務,以便告訴後面的請求不要再來了。 - 依賴隔離
在Hystrix中, 主要通過線程池來實現資源隔離. 通常在使用的時候我們會根據調用的遠程服務劃分出多個線程池.比如說,一個服務調用兩外兩個服務,你如果調用兩個服務都用一個線程池,那麼如果一個服務卡在哪裏,資源沒被釋放後面的請求又來了,導致後面的請求都卡在哪裏等待,導致你依賴的A服務把你卡在哪裏,耗盡了資源,也導致了你另外一個B服務也不可用了。這時如果依賴隔離,某一個服務調用A B兩個服務,如果這時我有100個線程可用,我給A服務分配50個,給B服務分配50個,這樣就算A服務掛了,我的B服務依然可以用。 - 請求緩存
比如一個請求過來請求我userId=1的數據,你後面的請求也過來請求同樣的數據,這時我不會繼續走原來的那條請求鏈路了,而是把第一次請求緩存過了,把第一次的請求結果返回給後面的請求。 - 請求合併
我依賴於某一個服務,我要調用N次,比如說查數據庫的時候,我發了N條請求發了N條SQL然後拿到一堆結果,這時候我們可以把多個請求合併成一個請求,發送一個查詢多條數據的SQL的請求,這樣我們只需查詢一次數據庫,提升了效率。
事實上,Hystrix一般需要與Ribbon和OpenFeign配合使用,因爲OpenFeign的內部已集成Hystrix,只需要調用相應api即可,所以這裏首先演示Ribbon與OpenFeign的配合使用。
- 像之前一樣建立名爲hystrix-client的模塊,同樣記得在選擇依賴時選擇Spring Web、Eureka Discovery、Ribbon,Hystrix,如圖所示:
- 修改配置文件application.yml,代碼如下:
server:
port: 18766
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:18761/eureka/
spring:
application:
name: service-hystrix
- 修改啓動類,使用註解
@EnableCircuitBreaker
開啓斷路器的支持。代碼如下:
package com.springclouddemo.hystrixclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class HystrixClientApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixClientApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
- 接下來,創建一個HiService類,表示要遠程調用的接口服務,注意這裏的uri名字要和調用的
application-name
相同,即上一篇博客中eureka-client
中配置過的。除此之外,使用註解@HystrixCommand
來提供服務降級,註解參數fallbackMethod
提供降級服務,代碼如下:
package com.springclouddemo.hystrixclient.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @author 莫息濤
* @Description: Ribbon的測試服務類
* @date 2020/2/24 11:54
*/
@Service
public class HiService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiServiceError")
public String hiService() {
return restTemplate.getForObject("http://SERVICE-HI/hi",String.class); //註冊的服務名稱
}
public String hiServiceError(){
return "Error";
}
}
- 創建一個HiController,調用HiService的方法,代碼如下:
package com.springclouddemo.ribbonclient.controller;
import com.springclouddemo.ribbonclient.service.HiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 莫息濤
* @Description: Ribbon的對外測試接口
* @date 2020/2/24 11:54
*/
@RestController
public class HiController {
@Autowired
HiService hiService;
@RequestMapping(value = "/hi")
public String hi(){
return hiService.hiService();
}
}
- 按照順序依次啓動
eureka-server
,eureka-client
,hystrix-client
,訪問註冊中心頁面,可以看到整合了hystrix的ribbon模塊已經啓動,如圖所示:
- 訪問
http://localhost:18766/hi
,可以看到如下顯示結果,說明整合了hystrix的ribbon配置成功,如圖所示:
- 關閉
eureka-client
,然後再次訪問http://localhost:18766/hi
,可以看到如下顯示結果,說明hystrix配置的降級服務成功,如圖所示:
3.Hystrix整合OpenFeign
我們講完了Ribbon與Hystrix的結合,那麼接下來看看Feign中又是怎麼使用Hystrix的。
因爲OpenFeign內置了Hystrix的功能,所以我們不需要引入特殊的包。我們先來創建一個降級的服務。
用這篇博客寫好的OpenFeign樣例在上面進行擴展
- 新建一個fallback包,用於存放降級服務的相應方法,再新建HiFallback,作爲降級服務的HiInterface 實現類,代碼如下:
package com.springclouddemo.openfeignclient.fallback;
import com.springclouddemo.openfeignclient.Interface.HiInterface;
import org.springframework.stereotype.Component;
/**
* @author 莫息濤
* @Description: 測試的降級服務
* @date 2020/2/24 18:28
*/
@Component
public class HiFallback implements HiInterface {
@Override
public String hi() {
return "Error";
}
}
- 修改HiInterface,添加降級服務的
fallback
屬性,代碼如下:
package com.springclouddemo.openfeignclient.Interface;
import com.springclouddemo.openfeignclient.fallback.HiFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author 莫息濤
* @Description: Feign的測試接口
* @date 2020/2/24 10:48
*/
@FeignClient(value = "service-hi",fallback = HiFallback.class)
public interface HiInterface {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String hi();
}
- 修改application.yaml,由於Feign默認的Hystrix是關閉的,我們需要在配置文件中開啓,代碼如下:
server:
port: 18764
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:18761/eureka/
spring:
application:
name: service-openfeign
feign:
hystrix:
enabled: true
- 按照順序依次啓動
eureka-server
,eureka-client
,openfeign-client
,訪問註冊中心頁面,可以看到整合了hystrix的openfeign模塊已經啓動,如圖所示:
- 訪問
http://localhost:18764/hi
,可以看到如下顯示結果,說明整合了hystrix的openfeign配置成功,如圖所示:
- 關閉
eureka-client
,然後再次訪問http://localhost:18764/hi
,可以看到如下顯示結果,說明hystrix配置的降級服務成功,如圖所示: