Spring Cloud 快速入門(四)Hystrix Dashboard 監控儀表盤、Turbine 聚合監控、服務降級報警機制

FixBugIdou1995發表於2020-10-13

1. Dashboard 監控儀表盤

Hystrix Dashboard 儀表盤用於以 GUI 的形式展示消費者的執行情況,包括其處理器方法與 Service 方法的呼叫執行情況,及熔斷器 CircuitBreaker 的狀態等。當然,這些顯示出的資料都是在指定時間窗內的執行情況及狀態資訊。

總步驟

  • 新增 hystrix-dashboard 與 actuator 依賴
  • 配置檔案中開啟 actuator 的 hystrix.stream 監控終端
  • 在啟動類上新增@EnableHystrixDashboard 註解

1.1 定義消費者工程 04-consumer-dashboard-8080

Hystrix-dashboard 用於監控 Hystrix 服務降級情況,所以應新增在消費者工程中。

(1) 建立工程
本例完全可以直接在 04-consumer-fallbackfeign-8080 工程中進行修改,為了便於演示,這裡又新建了一個工程。複製工程 04-consumer-fallbackfeign-8080,並重新命名為04-consumer-dashboard-8080。

(2) 新增依賴
保證如下三個依賴都要有:

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

(3) 修改配置檔案
在這裡插入圖片描述

在配置檔案中新增如下內容,用於開啟 actuator 的相關監控終端,並調整 Hystrix 隔離執行緒執行的超時時限。

spring:
  application:
    name: abcmsc-consumer-depart

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka


feign:
  client:
    config:
      default:
        connectTimeout: 5000   # 指定Feign客戶端連線提供者的超時時限
        readTimeout: 5000      # 指定Feign客戶端連線上提供者後,向提供者進行提交請求,從提交時刻開始,到接收到響應,這個時段的超時時限

  # 開啟Feign對Hystrix的支援
  hystrix:
    enabled: true
# 設定服務熔斷時限
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

# 開啟actuator的hystrix.stream監控終端
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

(4) 修改啟動類
在這裡插入圖片描述

@EnableHystrixDashboard  // 開啟Dashboard功能
@EnableFeignClients  // 開啟Feign客戶端
@SpringCloudApplication
public class ApplicationConsumer8080 {

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

}

1.2 定義提供者工程 04-provider-8081

(1) 建立工程

複製第三章的 03-provider-8081 工程,並重新命名為 04-provider-8081。因為 03-provider-8081 工程的 Service 方法中我們實現了一個執行緒阻塞的功能,當時為了演示feign的呼叫超時,我們拿過來修改一下。

(2) 修改 Service 實現類

這裡僅修改 getDepartById()方法。
為了測試方便,這裡將 id 值設定為 sleep()的時間,這樣設定沒有業務上的意義,但可以方便控制請求的執行時間,達到超時、不超時的效果。
在這裡插入圖片描述

@Service
public class DepartServiceImpl implements DepartService {

    @Autowired
    private DepartRepository repository;
	...
    @Override
    public Depart getDepartById(int id) {
        int time = id;
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if(repository.existsById(id)) {
            // 在DB中指定的id若不存在,該方法會丟擲異常
            return repository.getOne(id);
        }
        Depart depart = new Depart();
        depart.setName("no this depart");
        return depart;
    }
	...
}

啟動測試:
3秒是超時的:
在這裡插入圖片描述
1秒就是OK的:
在這裡插入圖片描述

1.3 儀表盤

原理是基於H5的SSE規範(Server Send Event,伺服器傳送事件)

操作:
在這裡插入圖片描述

通過訪問localhost:8080/actuator/hystrix.stream可以直接獲取到actuator的hystrix.stream監控終端的資料,Hystrix Dashboard實際上就是對這些資料進行解析轉成視覺化介面:

在這裡插入圖片描述

可以看到會動態顯示很多資料,但是不直觀,現在我們用Hystrix Dashboard對這些資料進行解析:

在這裡插入圖片描述

點選以後得到如下頁面:

在這裡插入圖片描述

呼叫幾次超時請求後,介面變化(紅色):
在這裡插入圖片描述

呼叫幾次成功請求後,介面變化(綠色):

在這裡插入圖片描述

GUI 介紹

官網的介紹:
在這裡插入圖片描述

在這裡插入圖片描述

1.4 使用postman進行批量訪問測試

先建立一個集合,將要執行的請求儲存到集合中:
在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述

找到Runner,執行集合中的請求:

在這裡插入圖片描述

選中集合,和集合中要執行的方法:

在這裡插入圖片描述

Iterations引數代表要迴圈執行幾次,點選執行:

在這裡插入圖片描述

執行以後檢視Dashboard監控頁面,看到都是綠色成功的:

在這裡插入圖片描述

向集合中新增超時的請求:

在這裡插入圖片描述

看到集合中既有超時的,也有不超時的請求:
在這裡插入圖片描述

點選執行後直接看效果:
在這裡插入圖片描述

2. Turbine 聚合監控–監控預設組叢集

關於 Turbine:
前面的方式是對單個消費者進行監控,我們也可以對叢集進行整體監控。此時就需要使用 Turbine 技術了。Turbine 能夠彙集監控資訊,並將聚合後的資訊提供給 Hystrix Dashboard來集中展示和監控。

在這裡插入圖片描述

【翻譯】就係統的總體執行狀況而言,檢視單個例項的Hystrix資料並不是很有用。Turbine 是一個應用程式,它將所有相關的/hystrix.stream端點聚合成一個合併的/hystrix.stream,以便在Hystrix儀表板中使用。單個例項通過Eureka定位執行Turbine需要使用@EnableTurbine註釋您的主類(例如,通過使用spring-cloud-starter-netflix-turbine來設定類路徑)。

2.1 整體架構示意圖

在這裡插入圖片描述

2.2 總步驟

(1) Turbine Client

  • 至少要有 actuator 與 neflix-hystrix 依賴
  • 在配置檔案中必須開啟 acturator 的 hystrix.stream 監控終端

(2) Turbine Server

  • 至少要有如下依賴:
    • netflix-turbine 依賴
    • netflix -hystrix-dashboard 依賴
    • netflix -hystrix 依賴
    • actuator 依賴
    • eureka client 依賴
  • 在配置檔案中要配置 turbine:指定要監控的 group 及相應的微服務名稱

2.3 建立消費者工程 04-consumer-turbine-client-8180

(1) 建立工程
複製 04-consumer-dashboard-8080 工程,並重新命名為 04-consumer-turbine-client-8180。

(2) 修改依賴
由於當前應用無需使用 Dashboard,所以可以將 Dashboard 依賴去掉。但必須要保證 Turbine 所監控的應用中具有 actuator 與 hystrix 依賴。
在這裡插入圖片描述

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

(3) 修改配置檔案
在這裡插入圖片描述

在這裡插入圖片描述

server:
  port: 8180

spring:
  application:
    name: abcmsc-consumer-depart

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka


feign:
  client:
    config:
      default:
        connectTimeout: 5000   # 指定Feign客戶端連線提供者的超時時限
        readTimeout: 5000      # 指定Feign客戶端連線上提供者後,向提供者進行提交請求,從提交時刻開始,到接收到響應,這個時段的超時時限

  # 開啟Feign對Hystrix的支援
  hystrix:
    enabled: true

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

# 開啟actuator的hystrix.stream監控終端
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

(4) 修改啟動類
作為被監控客戶端,不需要開啟監控儀表盤了:
在這裡插入圖片描述

//@EnableHystrixDashboard
@EnableFeignClients  // 開啟Feign客戶端
@SpringCloudApplication
public class ApplicationConsumer8180 {//重新命名改成8180

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

}

2.4 建立消費者工程 04-consumer-turbine-client-8280

(1) 建立工程
複製 04-consumer-turbine-client-8180 工程,並重新命名為 04-consumer-turbine-client-8280。
(2) 修改配置檔案
在這裡插入圖片描述

server:
  port: 8280

spring:
  application:
    name: abcmsc-consumer-depart

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

feign:
  client:
    config:
      default:
        connectTimeout: 5000   # 指定Feign客戶端連線提供者的超時時限
        readTimeout: 5000      # 指定Feign客戶端連線上提供者後,向提供者進行提交請求,從提交時刻開始,到接收到響應,這個時段的超時時限

  # 開啟Feign對Hystrix的支援
  hystrix:
    enabled: true

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

# 開啟actuator的hystrix.stream監控終端
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

(3) 修改啟動類

@EnableFeignClients  // 開啟Feign客戶端
@SpringCloudApplication
public class ApplicationConsumer8280 {//啟動類更名,方便區分

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

}

2.5 建立 Turbine 工程 00-hystrix-turbine-8888

(1) 建立工程
複製第二章中的 00-eurekaserver-8000 工程,並重新命名為 00-hystrix-turbine-8888。

(2) 修改依賴
由於這是一個 Eureka Client,所以將原來的 Eureka Server 依賴刪除,新增 Eureka Client 依賴。

  • netflix-turbine 依賴
  • netflix -hystrix-dashboard 依賴
  • netflix -hystrix 依賴
  • actuator 依賴
  • eureka client 依賴
<!-- hystrix-turbine依賴 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<!-- hystrix-dashboard依賴 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!--hystrix依賴-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--actuator依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--eureka客戶端依賴-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

(3) 修改啟動類
在這裡插入圖片描述

@EnableTurbine // 開啟Turbine聚合功能
@EnableHystrixDashboard // 開啟Hystrix儀表盤功能
@SpringCloudApplication
public class ApplicationTurbine8888 { //重新命名

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

}

(4) 修改配置檔案
在這裡插入圖片描述

server:
  port: 8888

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
spring:
  application:
    name: hystrix-turbine

# 配置turbine
turbine:
  # 指定要監控的微服務名稱
  app-config: abcmsc-consumer-depart
  aggregator:
    # 指定要監控的微服務組,default指定要監控預設組
    # 目前我們不需要給叢集中的例項進行分組,所以這裡配置default,代表監控預設組即可。
    cluster-config: default
  # 叢集名稱表示式,用來配置如何獲取和判斷叢集中各個例項所屬叢集組的名稱
  # 目前我們不需要給叢集中的例項進行分組
  # 所以這裡直接配置為簡單字串'default'即可,所有例項都屬於預設組。
  cluster-name-expression: "'default'"

2.6 效果

在這裡插入圖片描述
先直接通過路徑訪問:
在這裡插入圖片描述

在通過Dashboard 監控儀表盤監控 聚合後的資料:
在這裡插入圖片描述
看到該叢集中有兩臺主機。

2.7 監控預設組兩個叢集(不同的微服務)

上面案例兩個消費者是同一個微服務名稱,現在我們改成不同的兩個微服務:

(1) 分別將兩個應用微服務名稱改成不同的,對應兩個微服務

04-consumer-turbine-client-8180:
在這裡插入圖片描述

04-consumer-turbine-client-8280:
在這裡插入圖片描述

(2) 修改Turbine 工程監控兩個微服務
在這裡插入圖片描述

(3) 效果
在這裡插入圖片描述
看到雖然還是2,但是現在是兩個微服務了,代表各自兩個叢集,將兩個叢集中的所有主機資訊進行統計顯示。

3. Turbine 聚合監控–監控多個組叢集

為了更加方便對叢集的執行狀態的監控,Turbine 將叢集進行了分組。前面我們監控了兩個叢集,這兩個叢集預設被分為了一個組,是預設組。我們也可以將叢集劃分到多個組中使用同一個 Turbine 進行分別監控。

3.1 整體架構

在這裡插入圖片描述

3.2 分組監控原理

Turbine 對於叢集分組進行監控的原理是,在叢集之上再新增一種分類:組。為每個叢集中的 Sever 都新增一個 groupId,而 Turbine 是基於 groupId 進行監控的。

這個 groupId 是基於自定義的 Eureka 後設資料實現的。

Eureka 後設資料是指,Eureka Client 向 Eureka Server 註冊時的描述資訊,註冊資料。其有兩種型別:

  • 標準後設資料:Eureka 中已經定義好的客戶端描述資訊。
  • 自定義後設資料:在客戶端配置檔案中自己指定的 key-value 資料。

3.3 建立消費者工程 04-consumer-turbine-client-8380

(1) 建立工程
複製 04-consumer-turbine-client-8180 工程,並重新命名為 04-consumer-turbine-client-8380。

啟動類重新命名,方便區分:ApplicationConsumer8380

(2) 修改配置檔案
在這裡插入圖片描述

在instance配置資訊裡面新增自定義的後設資料,key必須為cluster(Turbine要求的):
在這裡插入圖片描述

server:
  port: 8380

spring:
  application:
    name: consumer-8380

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

  instance:
    metadata-map:
      cluster: group1   # 自定義Eureka後設資料

feign:
  client:
    config:
      default:
        connectTimeout: 5000   # 指定Feign客戶端連線提供者的超時時限
        readTimeout: 5000      # 指定Feign客戶端連線上提供者後,向提供者進行提交請求,從提交時刻開始,到接收到響應,這個時段的超時時限

  # 開啟Feign對Hystrix的支援
  hystrix:
    enabled: true

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

# 開啟actuator的hystrix.stream監控終端
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

3.4 建立消費者工程 04-consumer-turbine-client-8480

(1) 建立工程
複製 04-consumer-turbine-client-8380 工程,並重新命名為 04-consumer-turbine-client-8480。

啟動類重新命名,方便區分:ApplicationConsumer8480

(2) 修改配置檔案

server:
  port: 8480

spring:
  application:
    name: consumer-8480

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
      
  instance:
    metadata-map:
      cluster: group1   # 自定義Eureka後設資料
...

3.5 建立消費者工程 04-consumer-turbine-client-8580

(1) 建立工程
複製 04-consumer-turbine-client-8480 工程,並重新命名為 04-consumer-turbine-client-8580。

啟動類重新命名,方便區分:ApplicationConsumer8580

(2) 修改配置檔案

server:
  port: 8580

spring:
  application:
    name: consumer-8580

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
      
  instance:
    metadata-map:
      cluster: group2   # 自定義Eureka後設資料
...

3.6 建立消費者工程 04-consumer-turbine-client-8680

(1) 建立工程
複製 04-consumer-turbine-client-8580 工程,並重新命名為 04-consumer-turbine-client-8680。

啟動類重新命名,方便區分:ApplicationConsumer8680

(2) 修改配置檔案

server:
  port: 8680

spring:
  application:
    name: consumer-8680

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
      
  instance:
    metadata-map:
      cluster: group2   # 自定義Eureka後設資料
...

3.7 建立 Turbine 工程 00-hystrix-turbine-7777

(1) 建立工程
複製 00-hystrix-turbine-8888 工程,並重新命名為 00-hystrix-turbine-7777。

(2) 修改配置檔案
在這裡插入圖片描述

指定監控四個微服務名稱,同時代表了4個叢集,並對所有叢集中的例項進行了分組:

在這裡插入圖片描述

server:
  port: 7777

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
spring:
  application:
    name: hystrix-turbine

# 配置turbine
turbine:
  # 指定要監控的微服務名稱
  app-config: consumer-8380,consumer-8480,consumer-8580,consumer-8680
  aggregator:
    # 指定要監控的微服務組
    cluster-config: group1,group2
  # 指定要監控微服務組名稱來自於Eureka後設資料cluster
  cluster-name-expression: metadata['cluster']

3.8 演示

之前的配置:
consumer-8380、consumer-8480 屬於 group1
consumer-8580、consumer-8680 屬於 group2

監控group1:
在這裡插入圖片描述

在這裡插入圖片描述

監控group2:
在這裡插入圖片描述

在這裡插入圖片描述

4. 服務降級報警機制

無論哪種原因(系統異常、超時、隔離、熔斷)啟用了服務降級,系統都應該向管理員發出警報通知管理員,例如向管理員傳送簡訊。這種發生服務降級後向管理員發出警報的機制稱為服務降級報警機制。

1.高併發情況下,避免同一個服務因為服務降級,導致該服務的每個請求都發告警資訊,所以我們需要給報警新增一個報警標示,沒報過警的才報警
2.同時避免發過一次報警以後忘記處理了,之後又不在報警,導致一直沒人處理,所以需要給報警標示設定一個有效期時間
3.報警處理希望非同步處理,不影響請求的響應。

針對以上情況,考慮將報警標識放Redis最為合適。

當然還需要考慮高併發情況下 Redis 存在的問題:

  • 快取穿透
  • 快取雪崩
  • 熱點快取:雙重檢測鎖(存線上程安全問題)

4.1 建立工程 04-consumer-alarm-8080

複製前面任意的服務熔斷消費者工程,這裡複製 04-consumer-fallbackmethod-8080工程,並重新命名為 04-consumer-alarm-8080。

4.2 新增依賴

<!--Spring Boot與Redis整合依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

4.3 修改配置檔案

spring:
  application:
    name: abcmsc-consumer-depart

  # 連線Redis伺服器
  redis:
    host: redis5OS
    port: 6379
    password: 111

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

4.4 修改處理器

修改處理器,首先建立一個執行緒池,包含 5 個執行緒,然後再修改服務降級方法。
在這裡插入圖片描述

修改服務降級方法,以當前主機ip和方法名作為key:
在這裡插入圖片描述
報警前先從redis快取中查詢報警暴擊,判斷在一定時間內是否已經報過警了:
在這裡插入圖片描述
報警,非同步處理:
在這裡插入圖片描述

@RestController
@RequestMapping("/consumer/depart")
public class SomeController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    // 建立一個執行緒池,包含5個執行緒
    private ForkJoinPool pool = new ForkJoinPool(5);
	...
    @HystrixCommand(fallbackMethod = "getHystrixHandler")
    @GetMapping("/get/{id}")
    public Depart getByIdHandler(@PathVariable("id") int id, HttpServletRequest request) {
        String url = SERVICE_PROVIDER + "/provider/depart/get/" + id;
        return restTemplate.getForObject(url, Depart.class);
    }

    // 定義服務降級方法,即響應給客戶端的備選方案
    public Depart getHystrixHandler(@PathVariable("id") int id, HttpServletRequest request) {
        // 向管理員發出警報
        String ip = request.getLocalAddr();
        String key = ip + "_getHystrixHandler";
        // 指定存放到Redis中的key為“ip_發生降級的方法名”
        alarm(key);

        Depart depart = new Depart();
        depart.setId(id);
        depart.setName("no this depart");
        return depart;
    }

    // 降級發生後的報警
    private void alarm(String key) {
        BoundValueOperations<String, String> ops = redisTemplate.boundValueOps(key);
        String value = ops.get();
        if (value == null) {
            synchronized (this) {
                value = ops.get();
                if (value == null) {
                    // 傳送簡訊
                    sendMsg(key);
                    value="已發生服務降級";
                    ops.set(value, 10, TimeUnit.SECONDS);
                }
            }
        }
    }

    // 使用執行緒池實現非同步簡訊傳送
    private void sendMsg(String key) {
        pool.submit(() -> {
            System.out.println("傳送服務降級警報:" + key);
        });
    }
}

4.5 演示

在這裡插入圖片描述

相關文章