Spring Cloud 入門 之 Hystrix 篇(四)

原文地址:Spring Cloud 入門 之 Hystrix 篇(四)
博客地址:http://www.extlight.comhtml

1、前言

在微服務應用中,服務存在必定的依賴關係,若是某個目標服務調用慢或者有大量超時形成服務不可用,間接致使其餘的依賴服務不可用,最嚴重的可能會阻塞整條依賴鏈,最終致使業務系統崩潰(又稱雪崩效應)。java

上述的問題將是本篇須要解決的問題。git

2、簡單介紹

2.1 請求熔斷

斷路器是一種開關設置,當某個服務單元發生故障以後,經過斷路器的故障監控,向調用方返回一個符合預期的服務降級處理(fallback),而不是長時間的等待或者拋出調用方沒法處理的異常,這樣保證了服務調用方的線程不會長時間被佔用,從而避免了故障在分佈式系統的蔓延乃至崩潰。github

2.2 服務降級

fallback 至關因而降級操做。對於查詢操做, 咱們能夠實現一個 fallback 方法, 當請求後端服務出現異常的時候, 可使用 fallback 方法返回的值。 fallback 方法的返回值通常是設置的默認值或者來自緩存,告知後面的請求服務不可用了,不要再請求了。web

2.3 請求熔斷和服務降級區別

相同:spring

目標一致:爲了防止系統崩潰而實施的一種防護手段

表現形式一致:當請求目標在必定時間內無響應時,返回或執行默認響應內容

不一樣:後端

觸發條件不一樣:下游服務出現故障觸發請求熔斷。系統負荷超過閾值觸發服務降級。

管理目標層次不一樣:請求熔斷針對全部微服務。服務降級針對整個系統中的外圍服務。

2.4 實現方案

Spring Cloud Hystrix 實現了斷路器、線程隔離等一系列服務保護功能。它是基於 Netflix 的開源框架 Hystrix 實現的,該框架的目的在於經過控制訪問遠程系統、服務和第三方庫節點,從而對延遲和故障提供更強大的容錯能力。api

Hystrix 具有服務熔斷、服務降級、線程和信號隔離、請求緩存、請求合併以及服務監控的能力。瀏覽器

3、請求熔斷實戰

本次測試案例基於以前發表的文章中介紹的案例進行演示,不清楚的讀者請先轉移至 《Spring Cloud 入門 之 Feign 篇(三)》 進行瀏覽。緩存

如今的項目列表以下:

服務實例 端口 描述
common-api - 公用的 api,如:實體類
eureka-server 9000 註冊中心(Eureka 服務端)
goods-server 8081 商品服務(Eureka 客戶端)
goods-server-02 8082 商品服務(Eureka 客戶端)
goods-server-03 8083 商品服務(Eureka 客戶端)
order-server 8100 訂單服務(Eureka 客戶端)

在 order-server 項目中:

3.1 添加依賴

<!-- hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

3.2 設置熔斷策略

咱們來修改獲取下訂單的方法,在 placeOrder 方法上加 @HystrixCommand 註解:

@Service
public class OrderServiceImpl implements OrderService{
    
    @Autowired
    private RestTemplate restTemplate;
    
//  @Autowired
//  private GoodsServiceClient goodsServiceClient;

    @HystrixCommand(fallbackMethod = "defaultByPlaceOrder")
    @Override
    public void placeOrder(Order order) throws Exception{
        
        Result result = this.restTemplate.getForObject("http://GOODS/goods/goodsInfo/" + order.getGoodsId(), Result.class);
        
//      Result result = this.goodsServiceClient.goodsInfo(order.getGoodsId());
        
        if (result != null && result.getCode() == 200) {
            System.out.println("=====下訂單====");
            System.out.println(result.getData());
        } else {
            System.out.println(result.getMsg());
        }
    }
    

    public void defaultByPlaceOrder(Order order) {
        System.out.println("商品服務系統異常");
    }
}

當調用商品服務超時或出現異常時,Hystrix 會調用 @HystrixCommand 中指定的 fallbackMethod 方法獲取返回值或執行異常處理。

注意:fallbackMethod 方法要求與正常方法有相同的入參和回參。

3.3 啓動熔斷功能

在啓動類上添加 @EnableCircuitBreaker 註解:

@EnableCircuitBreaker
@EnableEurekaClient
@SpringBootApplication
public class OrderServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class, args);
    }
}

3.4 熔斷測試

  1. 咱們首先演示沒有開啓熔斷的功能,即先把上邊的 @EnableCircuitBreaker 註解進行註釋。

啓動好全部項目,使用 Postman 請求 order-server 進行下單操做,運行結果以下:

當咱們請求發送的 goodsId 的商品不存在,服務提供方拋會異常,調用方沒法處理,所以只能展現圖中的異常信息。

  1. 下面,咱們再將 @EnableCircuitBreaker 註解的註釋放開,運行結果以下:

從圖中可知,雖然請求了一個 goodsId 不存在的商品,可是調用方(order-server)開啓了熔斷機制,執行默認方法,從而使接口能正常通訊而不是拋出調用方不可處理的異常致使整個系統不能正常運行。

看到這裏,或許會有讀者產生一個疑問,若是類中定義 N 個方法,是否是意味着同時也要定義 N 個異常處理的方法呢,答案是否認的。

Hystrix 還提供了 @DefaultProperties 統一處理請求熔斷,在該註解上設置 defaultFallback 屬性值,即熔斷開啓後要執行的方法。

@Service
@DefaultProperties(defaultFallback = "defaultByHystrix")
public class OrderServiceImpl implements OrderService{
    
//  @Autowired
//  private RestTemplate restTemplate;
    
    @Autowired
    private GoodsServiceClient goodsServiceClient;

    @HystrixCommand
    @Override
    public void placeOrder(Order order) throws Exception{
        
//      Result result = this.restTemplate.getForObject("http://GOODS/goods/goodsInfo/" + order.getGoodsId(), Result.class);
        
        Result result = this.goodsServiceClient.goodsInfo(order.getGoodsId());
        
        if (result != null && result.getCode() == 200) {
            System.out.println("=====下訂單====");
            System.out.println(result.getData());
        } else {
            System.out.println(result.getMsg());
        }
    }
    
    public void defaultByHystrix() {
        System.out.println("商品服務系統異常");
    }
}

注意:defaultFallback 定義的方法必須是無參的。

4、服務降級實戰

在 common-api 項目中:

4.1 定義 Fallback

@Component
public class GoodsServiceClientFallbackFactory implements FallbackFactory<GoodsServiceClient> {

    @Override
    public GoodsServiceClient create(Throwable cause) {
        return new GoodsServiceClient() {

            @Override
            public Result goodsInfo(String goodsId) {
                return Result.fail(500, "商品服務系統出現異常,請聯繫管理員");
            }
            
        };
    }

}

使用單獨的類處理異常邏輯,當與服務端沒法正常通訊時調用此類中的方法返回結果。

4.2 修改 Feign 客戶端

將上邊定義好的 FallbackFactory 設置到 @FeignClient 註解上:

@FeignClient(value="GOODS", fallbackFactory = GoodsServiceClientFallbackFactory.class)
public interface GoodsServiceClient {

    @RequestMapping("/goods/goodsInfo/{goodsId}")
    public Result goodsInfo(@PathVariable("goodsId") String goodsId);
}

4.3 開啓服務降級功能

在 order-server 項目中:

server:
    port: 8100

spring:
  application:
    name: ORDER
    
eureka:
    instance:
        instance-id: order-api-8100
        prefer-ip-address: true # 訪問路徑能夠顯示 IP
    client:
        service-url:
            defaultZone: http://localhost:9000/eureka/  # 註冊中心訪問地址

feign:
  hystrix:
    enabled: true

4.4 去掉 @HystrixCommand 配置

@Service
//@DefaultProperties(defaultFallback = "defaultByHystrix")
public class OrderServiceImpl implements OrderService{
    
//  @Autowired
//  private RestTemplate restTemplate;
    
    @Autowired
    private GoodsServiceClient goodsServiceClient;

//  @HystrixCommand
    @Override
    public void placeOrder(Order order) throws Exception{
        
//      Result result = this.restTemplate.getForObject("http://GOODS/goods/goodsInfo/" + order.getGoodsId(), Result.class);
        
        Result result = this.goodsServiceClient.goodsInfo(order.getGoodsId());
        
        if (result != null && result.getCode() == 200) {
            System.out.println("=====下訂單====");
            System.out.println(result.getData());
        } else {
            System.out.println(result.getMsg());
        }
    }
    
//  public void defaultByHystrix() {
//      System.out.println("商品服務系統異常");
//  }
}

4.5 測試服務降級

在啓動類上加 FallbackFactory 類的包掃描目錄:

@ComponentScan(basePackages = {"com.extlight.springcloud"}) // 爲了能掃描 common-api 項目中的 GoodsServiceClientFallbackFactory
@EnableFeignClients(basePackages = {"com.extlight.springcloud"})
@EnableEurekaClient
@SpringBootApplication
public class OrderServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class, args);
    }
}

打開 Postman 請求下單接口,結果以下圖:

咱們手動關閉 2 個商品服務,保留一個商品服務並屢次請求商品服務接口,從而出模擬商品服務超過預約荷載情景,最終看到圖中服務降級功能。當有請求再次訪問商品服務時默認返回 GoodsServiceClientFallbackFactory 中定義的內容。

5、儀表盤

除了服務熔斷、降級的功能外,Hystrix 還提供了準及時的調用監控。 Hystrix 會持續地記錄全部經過 Hystrix 發起的請求的執行信息,並以統計報表和圖形方式展現給用戶。

5.1 配置被監控方

order-server 項目中:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

修改 application.yml,開放端口:

management:
  endpoints:
    web:
      exposure:
        include: "*"

5.2 配置監控方

1.新建一個名爲 hystrix-dashboard 項目,添加以下依賴:

<!-- hystrix-dashboard -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

2.新建 application.yml

server:
  port: 9300
  
spring:
  application:
    name: Hystrix-Dashboard

3.開啓監控功能

在啓動類上添加 @EnableHystrixDashboard 註解。

@EnableHystrixDashboard
@SpringBootApplication
public class HystrixdashboardApplication {

    public static void main(String[] args) {
        SpringApplication.run(HystrixdashboardApplication.class, args);
    }
}

啓動,瀏覽器訪問: http://localhost:9300/hystrix

5.3 監控設置

咱們以監控 order-server 爲例,在監控界面添加監控信息:

# 須要監控的服務地址
http://localhost:8100/actuator/hystrix.stream

delay: 請求間隔時間

title: 監控名稱

點擊 monitor stream

批量訪問 order-server 服務的下單接口。

最終效果以下:

經過批量訪問下單接口,發現圖中實心圓和曲線發生了變化。那咱們如何根據這兩個圖形查看監控信息呢?

實心圓:經過顏色的變化表明實例的健康程度,健康度從綠色>黃色>橙色>紅色遞減。其大小也會根據實例的請求流量發生變化,流量越大實心圓越大。

曲線:用來記錄間隔時間內流量的相對變化,一般能夠觀察到流量的上升和降低趨勢。

6、案例源碼

Hystrix demo 源碼

7、參考資料

hystrix-javanica

hystrix configuration

hystrix dashboard

相關文章
相關標籤/搜索