上一篇我们介绍了使用 Hystrix Dashboard 来展示 Hystrix 用于熔断的各项度量指标。通过 Hystrix Dashboard,我们可以方便的查看服务实例的综合情况,比如:服务调用次数、服务调用延迟等。但是仅通过 Hystrix Dashboard 我们只能实现对服务当个实例的数据展现,在生产环境我们的服务是肯定需要做高可用的,那么对于多实例的情况,我们就需要将这些度量指标数据进行聚合。下面,在本篇中,我们就来介绍一下另外一个工具:Turbine。

准备工作

在开始使用 Turbine 之前,我们先回顾一下上一篇中实现的架构,如下图所示:

java 登陆监控浏览器清除缓存退出登陆状态_数据


其中,我们构建的内容包括:

eureka-server:服务注册中心
eureka-producer:服务提供者
eureka-consumer-hystrix:使用 Feign 和 Hystrix 实现的服务消费者
hystrix-dashboard:用于展示 eureka-consumer-hystrix 服务的 Hystrix 数据
创建 Turbine
下面,我们将在上述架构基础上,引入 Turbine 来对服务的 Hystrix 数据进行聚合展示。 这里我们将分别介绍两种聚合方式。

通过 HTTP 收集聚合
创建一个标准的 Spring Boot 工程,命名为:turbine。

POM 配置
在 pom.xml 中添加以下依赖

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

启动类
在启动类上使用 @EnableTurbine 注解开启 Turbine

@EnableTurbine
@SpringBootApplication
public class TurbineApplication {

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

配置文件
在 application.yml 加入 Eureka 和 Turbine 的相关配置

spring:
  application:
    name: turbine
server:
  port: 8080
management:
  port: 8081
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7000/eureka/
turbine:
  app-config: eureka-consumer-hystrix
  cluster-name-expression: new String("default")
  combine-host-port: true

参数说明

turbine.app-config 参数指定了需要收集监控信息的服务名;
turbine.cluster-name-expression 参数指定了集群名称为 default,当我们服务数量非常多的时候,可以启动多个 Turbine 服务来构建不同的聚合集群,而该参数可以用来区分这些不同的聚合集群,同时该参数值可以在 Hystrix 仪表盘中用来定位不同的聚合集群,只需要在 Hystrix Stream 的 URL 中通过 cluster 参数来指定;
turbine.combine-host-port 参数设置为 true,可以让同一主机上的服务通过主机名与端口号的组合来进行区分,默认情况下会以 host 来区分不同的服务,这会使得在本地调试的时候,本机上的不同服务聚合成一个服务来统计。
注意:new String(“default”) 这个一定要用 String 来包一下,否则启动的时候会抛出异常:

org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field ‘default’ cannot be found on object of type ‘com.netflix.appinfo.InstanceInfo’ - maybe not public or not valid?


测试
在完成了上面的内容构建之后,我们来体验一下 Turbine 对集群的监控能力。分别启动

eureka-server
 eureka-producer
 eureka-consumer-hystrix
 turbine
 hystrix-dashboard
 访问 Hystrix Dashboard 并开启对 http://localhost:8080/turbine.stream 的监控,这时候,我们将看到针对服务 eureka-consumer-hystrix 的聚合监控数据。

此时的架构如下图所示:

java 登陆监控浏览器清除缓存退出登陆状态_服务调用_02


通过消息代理收集聚合

Spring Cloud 在封装 Turbine 的时候,还实现了基于消息代理的收集实现。所以,我们可以将所有需要收集的监控信息都输出到消息代理中,然后 Turbine 服务再从消息代理中异步的获取这些监控信息,最后将这些监控信息聚合并输出到 Hystrix Dashboard 中。通过引入消息代理,我们的 Turbine 和 Hystrix Dashoard 实现的监控架构可以改成如下图所示的结构:

java 登陆监控浏览器清除缓存退出登陆状态_服务调用_03


从图中我们可以看到,这里多了一个重要元素:RabbitMQ。对于 RabbitMQ 的安装与基本时候我们可以查看之前的 MQ 系列,这里不做过多的说明。下面,我们可以来构建一个新的应用来实现基于消息代理的 Turbine 聚合服务。关于通过 MQ 的聚合,在 Finchley.RC1 版本下有好多坑,好在最后能正常运行了。

Turbine Stream

UPDATED:2018-06-01

Finchley.RC2 已经出了,下边提到的 bug 都已经被修复了,直接添加 @EnableTurbineStream 就可以正常使用了。

java 登陆监控浏览器清除缓存退出登陆状态_spring_04

需要注意一点的是,Turbine Stream 默认的端口已经从 8989 改为 8080 了。

UPDATED:2018-05-18
以下关于 Turbine Stream 的内容仅适用于 Finchley.RC1 版本。今天尝试一下最新的 Finchley.BUILD-SNAPSHOT 发现 netty 的默认端口已经从 8989 改到 8080,并且需要依赖 spring-cloud-starter-netflix-hystrix,因为目前 BUILD-SNAPSHOT 依旧有 bug 不确定他们会怎么改,我就暂时先不更新了。等到 RC2 release 的时候再来更新一发。

创建一个标准的 Spring Boot 工程,命名为:turbine-stream-rabbitmq

POM

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

配置文件

spring:
  application:
    name: turbine-stream-rabbitmq
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7000/eureka/

启动类

@SpringBootApplication
@EnableTurbinestream
public class TurbineStreamRabbitmqApplication {

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

    @Bean
    public ConfigurableCompositeMessageConverter integrationArgumentResolverMessageConverter(CompositeMessageConverterFactory factory) {
        return new ConfigurableCompositeMessageConverter(factory.getMessageConverterForAllRegistered().getConverters());
    }

}

改造服务调用者
以之前的 eureka-consumer-hystrix 项目为基础,在 pom.xml 里加入以下依赖

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

再在启动类上加上 @EnableHystrix 注解

@EnableHystrix
@EnableFeignClients
@SpringBootApplication
public class EurekaConsumerHystrixApplication {

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

}

测试
分别启动 eureka-consumer-hystrix、turbine-stream-rabbitmq 这两个项目,然后在 RabbitMQ 的管理后台可以看到,自动创建了一个 Exchange 和 Queue

java 登陆监控浏览器清除缓存退出登陆状态_spring_05


看到这还是挺高兴的,但是……

当访问了一下 consumer 中的接口后,就开始了艰辛的爬坑路程……

遇到的坑
依赖
这个 Turbine Stream 之前应该是叫 Turbine AMQP,当时有个 spring-cloud-starter-turbine-amqp 依赖可以用,里边包装了相关的依赖,但是现在它被 deprecated 了,让用 spring-cloud-starter-netflix-turbine-stream 来代替,这就得靠自己来组合了。而坑主要就出在这里,至于哪些是必须的,哪些是添加了后就出问题的,还有依赖冲突的问题,都得靠自己来搞了。