Hystrix仪表盘监控集群应用

在前面介绍Hystrix Dashboard的首页时,我们知道Hystrix Dashboard支持三种不同的监控方式,而前面只介绍了第三种单体应用的监控,接下来开始介绍前两种对于集群的监控。由于默认集群和自定义集群仅仅是名字和配置方式不同,其他的都是一样的,因此这里以监控默认集群为例进行介绍。Hystrix Dashboard首页如下所示:

也就是说turbine.stream?cluster=[clusterName]turbine.stream都是针对集群使用的,其实从端点的命名中就可以知道这里需要引入Turbine,然后通过它来汇集监控信息,并将聚合后的信息提供给Hystrix Dashboard来集中展示和监控。

接下来将对前面实现的例子进行一些扩展,通过引入Turbine来聚合ribbon-consumer项目(即服务消费者)的监控信息,并输出给Hystrix Dashboard进行展示,最后完成时的架构图如下所示:

为了完成上述功能,这里新建一个SpringBoot工程,相应的操作如下:

第一步,新建一个普通的SpringBoot工程,名称为turbine,注意使用默认的依赖。

第二步,添加项目依赖。Spring Boot工程创建完成后,修改pom.xml文件,添加如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR7</spring-cloud.version>
</properties>

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

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

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

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

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

当然了也可以采用可视化的方式来创建该项目,创建过程如下所示:

注意上图中的Web、Actuator、Eureka client和Turbine这四个依赖是必须要添加的,而其余的Hystrix和Hystrix Dashboard依赖可以不添加。

第三步,在入口类上添加启动注解。接下来在项目的入口类上添加@EnableDiscoveryClient注解,用于开启客户端发现功能;同时还需要添加@EnableTurbine注解,表示开启Turbine功能,如下所示:

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableDiscoveryClient
@EnableTurbine
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}

第四步,设置一些属性。打开application.yml配置文件,在里面设置Eureka和Turbine相关的一些信息,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
spring:
application:
name: turbine

server:
port: 2002

management:
server:
port: 2003

eureka:
client:
service-url:
defaultZone: http://peer1:1111/eureka/
turbine:
app-config: ribbon-consumer
cluster-name-expression: new String("default")
combine-host-port: true

简单介绍一下上述参数的含义:

  • turbine.app-config参数指定了需要收集监控信息的服务名;
  • turbine.cluster-name-expression参数指定了集群名称为default,当服务数量非常多的时候,可以启动多个Turbine服务来构建不同的聚合集群,而该参数可以用来区分这些不同的聚合集群,同时该参数值可以在Hystrix仪表盘中用来定位不同的聚合集群,只需在Hystrix Stream的URL中通过cluster参数来指定。请注意这里必须写成new String("default")的形式,而不能直接使用"default"的形式,那样会导致后续在访问数据聚合链接时的reportingHostsLast10Seconds值一直为0,这一点需要格外注意。
  • turbine.combine-host-port参数设置为true,可以让同一主机上的服务通过主机名与端口号的组合来进行区分,默认情况下会以host来区分不同的服务,这会使得在本地调试的时候,本机上的不同服务聚合成一个服务来统计。

第五步,由于架构图中存在两个RIBBON-CONSUMER服务实例,因此需要提供不同的服务实例,修改ribbon-consumer项目的application.yml配置文件为如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
spring:
application:
name: ribbon-consumer
main:
allow-bean-definition-overriding: true

management:
endpoints:
web:
exposure:
include: ["info","health","hystrix.stream"]
## 修改默认的监控端点地址,添加上下文路径actuator,注意默认也是actuator
base-path: "/actuator"
---
# consumer1向服务注册中心peer1注册
eureka:
client:
service-url:
defaultZone: http://peer1:1111/eureka/
# availability-zones:
# region: us-east-1
spring:
profiles: consumer1
server:
port: 9000

---
# consumer2也向服务注册中心peer1注册
eureka:
client:
service-url:
defaultZone: http://peer1:1111/eureka/
spring:
profiles: consumer2
server:
port: 9001

第六步,分别按照以下顺序来启动相应的服务,启动顺序如下(注意不能颠倒):
(1)服务名为eureka-server的工程,这是服务注册中心,注意端口为1111,即启动实例名为peer1的服务实例。
(2)服务名为hello-service的工程,这是服务提供者,注意需要启动两个实例,启动的端口分别为8081和8082,即启动实例名为p1和p2的服务实例(注意两个服务提供者均需往服务注册中心注册)。
(3)服务名为ribbon-consumer的工程,这是服务消费者,注意需要启动两个实例,启动的端口分别为9000和9001,即启动实例名为consumer1和consumer12的服务实例(注意两个服务消费者均需往服务注册中心注册)。
(4)服务名为hystrix-dashboard的工程,这是Hystrix Dashboard监控盘项目,启动端口为2001,即启动实例名为hystrix-dashboard的服务实例。
(5)服务名为turbine的工程,这是集群监控项目,启动端口为2002,即启动实例名为turbine的服务实例(注意这个服务需往服务注册中心注册)。

接着先去浏览器地址栏中访问http://localhost:9000/get6链接(或者访问RIBBON-CONSUMER服务(即服务消费者)中任意一个带有熔断器的接口),然后访问http://localhost:9000/actuator/hystrix.stream链接(顺便换成9001端口)可以发现页面显示如下信息:

这说明单个应用监控都是正常的,那么接下来访问http://localhost:2002/hystrix.stream链接来查看聚合数据信息如下:

上图也说明聚合数据也是有的,接下来就是通过使用Hystrix Dashboard来查看它。打开http://localhost:2001/hystrix链接,页面按照图示进行操作:

聪明的你也注意到了,监控单体应用的时候多了一层/actuator,而监控集群的时候并没有该层,这一点需要注意。

之后点击Monitor Stream按钮,发现页面变成如下所示的界面:

从图中可以知道,虽然我们启动了两个ribbon-consumer服务实例,但是在监控页面中依然只是展示了一个监控图。但是图中集群报告区域中的Hosts属性已经显示2个了,也就是说由于这两个实例是同一个服务,而对于集群来说我们更加关注的是服务集群的高可用性,所以Turbine会将相同服务作为一个整体来对待,并汇总为一个监控图,因此只会展现一个监控图。

当然了,开发者也可以为每个ribbon-consumer实例设置一个新的spring.application.name属性,如下所示application.yml配置文件信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
spring:
main:
allow-bean-definition-overriding: true

management:
endpoints:
web:
exposure:
include: ["info","health","hystrix.stream"]
## 修改默认的监控端点地址,添加上下文路径actuator,注意默认也是actuator
base-path: "/actuator"
---
# consumer1向服务注册中心peer1注册
spring:
application:
name: ribbon-consumer1
profiles: consumer1

eureka:
client:
service-url:
defaultZone: http://peer1:1111/eureka/
# availability-zones:
# region: us-east-1
server:
port: 9000

---
# consumer2也向服务注册中心peer1注册
spring:
application:
name: ribbon-consumer2
profiles: consumer2

eureka:
client:
service-url:
defaultZone: http://peer1:1111/eureka/

server:
port: 9001

注意还需要修改turbine项目的application.yml配置文件中的turbine.app-config信息,新增ribbon-consumer2这个服务,注意这里不再是服务实例名称,而是单独的服务名称,因为前面通过spring.application.name属性进行了设置,如下所示:

1
2
turbine:
app-config: ribbon-consumer1,ribbon-consumer2

然后按照之前的顺序来启动它,此时查看Turbine的监控首页,如下所示:

注意如果此时依然还是一个监控图,那么需要访问服务消费者中定义的多个方法,因为它是监控某个方法的信息,方法如果不被访问是无法产生数据的。

与消息代理结合

Spring Cloud在封装Turbine的时候,还封装了基于消息代理的收集实现,所以我们可以将所有需要收集的监控信息都输出到消息代理中,然后Turbine服务再从消息代理中异步获取这些监控信息,最后将这些监控信息聚合并输出到Hystrix Dashboard中。

也就是说如果我们引入消息代理,那么之前我们使用Turbine和Hystrix Dashboard实现的监控架构可以修改为如下所示的架构图: