Spring Cloud(五)《Turbine 监控信息聚合展示 Hystrix》

前言介绍

Hystrix Dashboard 可以定时收集接口调用信息;时长、次数、性能、熔断等各项指标来进行监控展示,但是我们每次监控都需要输入一个Hystrix 的链接例如:http://localhost:9001/actuator/hystrix.stream,但是这样并不利于我们去做整体服务的监控,并且在实际使用的过程中如果是几十到几百个接口那么这样的监控几乎达不到监控效果,就累死在监控路上了。因此我们需要使用到 Turbine 来进行监控信息聚合,可以按业务组定义配置方便监控。

案例说明

案例通过添加itstack-demo-springcloud-turbine工程模块,将单体监控汇总在统一页面进行管理,此时的监控模型,如图;

Spring Cloud(五)《Turbine 监控信息聚合展示 Hystrix》

环境准备

  1. jdk 1.8、idea2018、Maven3
  2. Spring Boot 2.0.6.RELEASE
  3. Spring Cloud Finchley.SR2

代码示例

1itstack-demo-springcloud-05
 2├── itstack-demo-springcloud-eureka-client
 3│   └── src
 4│       └── main
 5│           ├── java
 6│           │   └── org.itstack.demo
 7│           │        ├── web
 8│           │        │   └── EurekaClientController.java
 9│           │        └── EurekaClientApplication.java
10│           └── resources   
11│               └── application.yml
12├── itstack-demo-springcloud-eureka-server
13│   └── src
14│       └── main
15│           ├── java
16│           │   └── org.itstack.demo
17│           │        └── EurekaServerApplication.java
18│           └── resources   
19│               └── application.yml
20├── itstack-demo-springcloud-hystrix-dashboard
21│   └── src
22│       └── main
23│           ├── java
24│           │   └── org.itstack.demo
25│           │        └── DashboardApplication.java
26│           └── resources   
27│               └── application.yml
28├── itstack-demo-springcloud-hystrix-feign
29│   └── src
30│       └── main
31│           ├── java
32│           │   └── org.itstack.demo
33│           │        ├── service
34│           │        │   ├── hystrix
35│           │        │   │   └── FeignServiceHystrix.java
36│           │        │   └── FeignService.java
37│           │        ├── web
38│           │        │   └── FeignController.java
39│           │        └── FeignApplication.java
40│           └── resources   
41│               └── application.yml
42├── itstack-demo-springcloud-hystrix-ribbon
43│   └── src
44│       └── main
45│           ├── java
46│           │   └── org.itstack.demo
47│           │        ├── service
48│           │        │   └── RibbonService.java
49│           │        ├── web
50│           │        │   └── RibbonController.java      
51│           │        └── RibbonApplication.java
52│           └── resources   
53│               └── application.yml
54└── itstack-demo-springcloud-turbine
55    └── src
56        └── main
57            ├── java
58            │   └── org.itstack.demo   
59            │        └── TurbineApplication.java
60            └── resources   
61                └── application.yml

完整代码欢迎关注公众号:bugstack虫洞栈 | 回复“SpringCloud专题”进行下载

itstack-demo-springcloud-eureka-client | 服务提供方

提供一个查询用户信息的简单方法,在配置文件中通过修改端口启动2次,模拟双实例应用,为调用方负载做准备。

web/EurekaClientController.java | 注意@EnableEurekaClient用于向注册中心提供服务

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@EnableEurekaClient
 7@RestController
 8public class EurekaClientController {
 9
10    @Value("${server.port}")
11    private int port;
12
13    @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
14    public String queryUserInfo(@RequestParam String userId) {
15        return "Hi 微信公众号:bugstack虫洞栈 | " + userId + " >: from eureka client port: " + port;
16    }
17
18}

EurekaClientApplication.java | 服务启动类

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@SpringBootApplication
 7public class EurekaClientApplication {
 8
 9    public static void main(String[] args) {
10        SpringApplication.run(EurekaClientApplication.class, args);
11    }
12
13}

application.yml | 配置文件链接服务注册中心,8001\8002分别配置启动

1server:
 2  port: 8001 / 8002
 3
 4spring:
 5  application:
 6    name: itstack-demo-springcloud-eureka-client
 7
 8eureka:
 9  client:
10    serviceUrl:
11      defaultZone: http://localhost:7397/eureka/

itstack-demo-springcloud-eureka-server | 单个服务注册中心

服务注册中心用于承载接口提供方向上注册,同时正在调用方链接后可以获取指定应用的服务实例。

EurekaServerApplication.java | 通过注解@EnableEurekaServer启动服务注册与发现中心

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@SpringBootApplication
 7@EnableEurekaServer
 8public class EurekaServerApplication {
 9
10    public static void main(String[] args) {
11        SpringApplication.run( EurekaServerApplication.class, args );
12    }
13
14}

application.yml | 服务注册中心配置文件,端口7397和我们之前写netty的服务的端口一致

1server:
 2  port: 7397
 3
 4eureka:
 5  instance:
 6    hostname: localhost
 7  client:
 8    registerWithEureka: false
 9    fetchRegistry: false
10    serviceUrl:
11      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
12
13spring:
14  application:
15    name: itstack-demo-springcloud-eureka-server

itstack-demo-springcloud-hystrix-dashboard | 服务监控像仪表盘一样透视系统健康度

Spring Cloud Hystrix Dashboard只是spring cloud基于Hystrix Dashboard,将实时监控数据通过页面呈现出来。Spring Cloud Hystrix Dashboard的底层原理是间隔一定时间去“Ping”目标服务,返回的结果是最新的监控数据,最后将数据显示出来。

1Cluster via Turbine (default cluster): http://turbine-hostname:port/turbine.stream 
2Cluster via Turbine (custom cluster): http://turbine-hostname:port/turbine.stream?cluster=[clusterName]
3Single Hystrix App: http://hystrix-app:port/actuator/hystrix.stream 
4

DashboardApplication.java | 配置@EnableHystrixDashboard启动服务

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@EnableHystrixDashboard
 7@SpringBootApplication
 8public class DashboardApplication {
 9
10    public static void main(String[] args) {
11        SpringApplication.run(DashboardApplication.class, args);
12    }
13
14}

application.yml | 通用配置信息

1server:
2  port: 8989
3
4spring:
5  application:
6    name: itstack-demo-springcloud-hystrix-dashboard

itstack-demo-springcloud-feign | Feign服务调用方,添加熔断Hystrix

Feign 是一个声明式的 Web Service 客户端,它的目的就是让 Web Service 调用更加简单。它整合了 Ribbon 和 Hystrix,从而让我们不再需要显式地使用这两个组件。Feign 还提供了 HTTP 请求的模板,通过编写简单的接口和插入注解,我们就可以定义好 HTTP 请求的参数、格式、地址等信息。接下来,Feign 会完全代理 HTTP 的请求,我们只需要像调用方法一样调用它就可以完成服务请求。

Feign 具有如下特性:

可插拔的注解支持,包括 Feign 注解和 JAX-RS 注解

支持可插拔的 HTTP 编码器和解码器

支持 Hystrix 和它的 Fallback

支持 Ribbon 的负载均衡

支持 HTTP 请求和响应的压缩

service/FeignService.java | 注解方式调用,方便易用。@FeignClient会在调用时进行解析服务到具体的http://ip:port/

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@FeignClient(value = "itstack-demo-springcloud-eureka-client", fallback = FeignServiceHystrix.class)
 7public interface FeignService {
 8
 9    @RequestMapping(value = "/api/queryUserInfo", method = RequestMethod.GET)
10    String queryUserInfo(@RequestParam String userId);
11
12}

service/hystrix/FeignServiceHystrix.java | 提供熔断服务,当发生异常时主动返回预定结果

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@Component
 7public class FeignServiceHystrix implements FeignService {
 8
 9    @Override
10    public String queryUserInfo(String userId) {
11        return "queryUserInfo by userId:" + userId + " err!from feign hystrix";
12    }
13
14}

web/FeignController.java | 使用接口提供服务 From Feign

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@RestController
 7public class FeignController {
 8
 9    @Resource
10    private FeignService ribbonService;
11
12    @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
13    public String queryUserInfo(@RequestParam String userId) {
14        return ribbonService.queryUserInfo(userId) + " From Feign";
15    }
16
17}

FeignApplication.java | 注解@EnableEurekaClient、@EnableFeignClients、@EnableDiscoveryClient获取调用注册中心服务

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@SpringBootApplication
 7@EnableEurekaClient
 8@EnableDiscoveryClient
 9@EnableFeignClients
10@EnableHystrix
11public class FeignApplication {
12
13    public static void main(String[] args) {
14        SpringApplication.run(FeignApplication.class, args);
15    }
16
17}

application.yml | eureka服务配置,从注册中心获取可用服务。开启hystrix=true,并设置hystrix.stream

1server:
 2  port: 9001
 3
 4spring:
 5  application:
 6    name: itstack-demo-springcloud-feign
 7
 8eureka:
 9  client:
10    serviceUrl:
11      defaultZone: http://localhost:7397/eureka/
12
13feign.hystrix.enabled: true
14
15management:
16  endpoints:
17    web:
18      exposure:
19        include: hystrix.stream

itstack-demo-springcloud-ribbon | Ribbon服务调用方

Ribbon是一个基于 HTTP 和 TCP 的客户端负载均衡器。它可以通过在客户端中配置 ribbonServerList 来设置服务端列表去轮询访问以达到均衡负载的作用。

当 Ribbon 与 Eureka 联合使用时,ribbonServerList 会被 DiscoveryEnabledNIWSServerList 重写,扩展成从 Eureka 注册中心中获取服务实例列表。同时它也会用 NIWSDiscoveryPing 来取代 IPing,它将职责委托给 Eureka 来确定服务端是否已经启动。

service/RibbonService.java | 接口式硬编码调用不太易于维护,因此也是比较少用的方式。hystrix实际通过getFallback()返回熔断结果

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@Service
 7public class RibbonService {
 8
 9    @Autowired
10    private RestTemplate restTemplate;
11
12    @HystrixCommand(fallbackMethod = "queryUserInfoFallback")
13    public String queryUserInfo(String userId) {
14        return restTemplate.getForObject("http://ITSTACK-DEMO-SPRINGCLOUD-EUREKA-CLIENT/api/queryUserInfo?userId=" + userId, String.class);
15    }
16
17    /**
18     * Specifies a method to process fallback logic.
19     * A fallback method should be defined in the same class where is HystrixCommand.
20     * Also a fallback method should have same signature to a method which was invoked as hystrix command.
21     * for example:
22     * <code>
23     *      @HystrixCommand(fallbackMethod = "getByIdFallback")
24     *      public String getById(String id) {...}
25     *
26     *      private String getByIdFallback(String id) {...}
27     * </code>
28     * Also a fallback method can be annotated with {@link HystrixCommand}
29     * <p/>
30     * default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()}
31     *
32     * @return method name
33     *
34     * getFallback()
35     * 
36     * @Override
37     * protected Object getFallback() {
38     *     final CommandAction commandAction = getFallbackAction();
39     *     if (commandAction != null) {
40     *         try {
41     *             return process(new Action() {
42     *                 @Override
43     *                 Object execute() {
44     *                     MetaHolder metaHolder = commandAction.getMetaHolder();
45     *                     Object[] args = createArgsForFallback(metaHolder, getExecutionException());
46     *                     return commandAction.executeWithArgs(metaHolder.getFallbackExecutionType(), args);
47     *                 }
48     *             });
49     *         } catch (Throwable e) {
50     *             LOGGER.error(FallbackErrorMessageBuilder.create()
51     *                     .append(commandAction, e).build());
52     *             throw new FallbackInvocationException(unwrapCause(e));
53     *         }
54     *     } else {
55     *         return super.getFallback();
56     *     }
57     * }
58     */
59    public String queryUserInfoFallback(String userId) {
60        return "queryUserInfo by userId:" + userId + " err!from ribbon hystrix";
61    }
62
63}

web/RibbonController.java | 使用接口提供服务 From Ribbon

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@RestController
 7public class RibbonController {
 8
 9    @Resource
10    private RibbonService ribbonService;
11
12    @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
13    public String queryUserInfo(@RequestParam String userId) {
14        return ribbonService.queryUserInfo(userId) + " From Ribbon";
15    }
16
17}

RibbonApplication.java | 通过注解@LoadBalanced注册rest模版,用于Ribbon接口调用。并启动@EnableHystrix

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@SpringBootApplication
 7@EnableEurekaClient
 8@EnableDiscoveryClient
 9@EnableHystrix
10public class RibbonApplication {
11
12    public static void main(String[] args) {
13        SpringApplication.run(RibbonApplication.class, args);
14    }
15
16    @Bean
17    @LoadBalanced
18    RestTemplate restTemplate() {
19        return new RestTemplate();
20    }
21
22}

application.yml | eureka服务配置,从注册中心获取可用服务

1server:
 2  port: 9002
 3
 4spring:
 5  application:
 6    name: itstack-demo-springcloud-ribbon
 7
 8eureka:
 9  client:
10    serviceUrl:
11      defaultZone: http://localhost:7397/eureka/

itstack-demo-springcloud-turbine | 监控信息聚合服务

通过配置汇总,将应用itstack-demo-springcloud-feign,itstack-demo-springcloud-ribbon,汇总监控。

TurbineApplication.java | 通过注解@EnableTurbine配置启动Ribbon

1/**
 2 * 微信公众号:bugstack虫洞栈 | 沉淀、分享、成长,专注于原创专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@EnableTurbine
 7@SpringBootApplication
 8public class TurbineApplication {
 9
10    public static void main(String[] args) {
11        SpringApplication.run(TurbineApplication.class, args);
12    }
13
14}

application.yml | eureka服务配置,从注册中心获取可用服务

1spring:
 2  application:
 3    name: itstack-demo-springcloud-turbine
 4
 5server:
 6  port: 8080
 7
 8management:
 9  port: 8081
10
11## 服务注册中心
12eureka:
13  client:
14    service-url:
15      defaultZone: http://localhost:7397/eureka
16
17## 监控汇总配置,这里配置2个应用逗号隔开
18turbine:
19  app-config: itstack-demo-springcloud-feign,itstack-demo-springcloud-ribbon
20  cluster-name-expression: new String("default")
21  combine-host-port: true

测试验证

  1. 启动itstack-demo-springcloud-hystrix-dashboard,访问;http://localhost:8989/hystrix
    Spring Cloud(五)《Turbine 监控信息聚合展示 Hystrix》
  2. 分别启动如下系统模拟;
    1. itstack-demo-springcloud-eureka-server 服务注册发现中心
    2. itstack-demo-springcloud-eureka-client 测试接口提供方
    3. itstack-demo-springcloud-hystrix-feign 接口调用方Feign
    4. itstack-demo-springcloud-hystrix-ribbon 接口调用方Ribbon
    5. itstack-demo-springcloud-turbine 监控信息汇总
  1. 测试监控
  2. 在hystrix-dashboard监控页面{http://localhost:8989/hystrix},输入;http://localhost:8080/turbine.stream
  3. 刷新访问两个调用方接口;http://localhost:9001/api/queryUserInfo?userId=111、http://localhost:9002/api/queryUserInfo?userId=111
  4. 回看刚才的监控页面;http://localhost:8989/hystrix/monitor?stream=http%3A%2F%2Flocalhost%3A8080%2Fturbine.stream,已经可以看到监控信息汇总,如图;
    微信公众号:bugstack虫洞栈 & 监控信息汇总

综上总结

  1. 通过Turbine服务我们可以将监控信息汇总到一起进行查看,这样更加方便实际应用。
  2. SpringCloud 到现在的案例已经使用到了很多服务模块,它确实是一套有序集合框架,将各家优秀功能服务集成,方便使用。
  3. SpringBoot 、 SpringCloud,在开发一些中小型独立服务非常边界,对于一些超大型以外的公司非常合适。当然并不是一线互联网就不使用,因为这里面还牵扯到很多对应的替代产品,比如Dubbo、网关、全链路监控、路由等等,所以需要根据不同业务进行技术选型,不要被技术限制。


上一篇:Spring Cloud(九)《服务网关Zuul 动态路由与权限过滤器》


下一篇:用Java实现JVM第四章《运行时数据区》