HystrixDashboard数据从何而来:HystrixMetrics指标采集源码解读

前言:这里并不是介绍如何引入并使用HystrixDashboard,而是分析HystrixDashboard中的数据是怎么产生、流转最后展示到界面上的

背景说明:我们的API网关所有请求都是用HstrixCommand封装的,之前只是用到了线程池隔离的功能,现在想要配置使用断路器和服务降级。由于网关比较重要,所以准备先看看所有hystrix请求的各项指标,于是使用hystrix dashboard和turbine来查看hystrix指标数据。
然而,在网关中引入spring-cloud-starter-hystrix依赖后,fullGC的频率大大提升,这边只能先停止采集数据,准备看看哪里会导致这种问题,最终通过查看源码,整体了解了hystrix通过hystrix.stream向外输出数据指标的流程,并记录下源码分析过程:

整体结构

此次源码分析基于此依赖:

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

这个项目只是pom项目,聚合依赖:

  • 此pom的依赖项目:

    • spring-cloud-starter是springcloud的基础库,没什么特别功能
    • spring-cloud-netflix-core依赖了netflix体系的各类基本功能组件(ribbon,feign,hystrix…),并进行了一定的抽象封装,是将netflix组件整合为springcloud的基础依赖。
    • hystrix-core是hystrix的核心功能库,
    • hystrix-javanica是对hystrix的注解支持的库
    • hystrix-metrics-event-stream就是将hystrix指标数据暴露为endpoint的依赖包

这里先给出后面整个逻辑相关类的UML类图:

下面的分析主要分为三块,参照上面类图中的三个主要的包。

一、数据对外输出

在依赖列表中,我们先找看上去与HystrixDashboard最相关的包,首先看看hystrix-metrics-event-stream这个包,这个包的类组成很简单:

看到类名就能知道,这个包主要就是封装了各类servlet,而其中主要被外部引用的是HystrixMetricsStreamServlet.class,后面主要的功能逻辑都由这个类串联起来,是输出HystrixMetrics的核心。
由于此类仅有构造器,并无明显的逻辑代码,我们先来看看它的父类:HystrixSampleSseServlet.class,而对外输出的功能也就在这个父类里。这个类继承了HttpServlet,实现了doGet()方法,并在此方法中调用自身的 handleRequest() 方法,而主要输出功能就在这个方法内:

详细说明:

  1. 这里可以看到,是以text/event-stream的格式返回相应数据的,而这种内容类型可以看做是服务器主动推送事件流,因此我们在访问/hystrix.stream端点时,页面会源源不断刷新展示最新数据。
  2. 这里就是将数据:sampleDataAsString (hystrix指标数据)写给请求方。sampleDataAsString数据源于订阅sampleStream(Observable.class)
  3. 这里每隔一定时间检查是否有后续数据,并打印ping维持连接

二、指标数据流转

对外输出数据的能力就全部在这上面一部分了,下面来看看指标数据是如何产生的,首先上面说到对外输出的数据是订阅sampleStream这个Observable得到的,而sampleStream是在创建HystrixMetricsStreamServlet.class的实例时传入的:

这里构造实例时传入的sampleStream是由HystrixDashboardStream.getInstance().observe()提供的,那我们来看看这个类。
HystrixDashboardStream这个类是hystrix-core包下的,其observe()方法返回的数据singleSource是通过构造器创建的,也就是图中标出的

这里DashboardData就是包装指标数据的对象类,其内部包含了三类数据,分别产生于

  • HystrixCommandMetrics.getInstances()
  • HystrixThreadPoolMetrics.getInstances()
  • HystrixCollapserMetrics.getInstances()

我们一个个来看:

  • HystrixCommandMetrics.getInstances()是获取HystrixCommand的数据,主要包括commandKey,groupKey等单次请求的标示信息。
    • 这些数据存储在类静态变量metrics中,并且将每次初始化的实例数据保存在此:
    • 而这些数据是在创建一个HystrixCommand时设置进去的,这段逻辑在AbstractCommand(HystrixCommand的父类)里:
    • 现在,我们可以知道,每次创建一个HystrixCommand,其属性都会被保存至HystrixCommandMetrics的静态变量中,并在hystrix.stream的请求到来时,返回并展示到dashBoard。
  • HystrixThreadPoolMetrics.getInstances()是获取线程池的数据,其数据流转过程跟上面的类似:HystrixThreadPoolMetrics类的静态变量metrics保存着HystrixThreadPoolDefault初始化时设置进来的相关信息。
  • HystrixCollapserMetrics.getInstances()是请求合并的数据,是HystrixCollapser初始化时设置并保存到HystrixCollapserMetrics.metrics中的。

三、实例初始化

到目前为止,我们就能了解到输出到HystrixDashBoard的数据订阅来源sampleStream是从哪里来的了。但是之前讲到,sampleStream的获取是在HystrixMetricsStreamServlet构造器中实现的,所以我们接下来看看HystrixMetricsStreamServlet对象实例的初始化过程。

我们来看一下spring-cloud-netflix-core包下的HystrixCircuitBreakerConfiguration.class类,这是一个自动配置类,其中包含子类HystrixWebConfiguration.class,会构造一个HystrixStreamEndpoint的bean:

  • 在这里将我们的关键类HystrixMetricsStreamServlet.class传入到父类ServletWrappingEndpoint的构造器中
  • 这里的this.controller是ServletWrappingController对象,而就是在这个ServletWrappingController中,通过spring管理bean的流程将HystrixMetricsStreamServlet.class实例初始化

至此,全部的流程就已经梳理完毕了,可能顺序上有点乱,不过参照最上面的UML类图再跟着源码一个个类点进去看看,应该能够对这一块有更清晰的了解,希望我的文章能对你产生帮助,如果有错误的地方请指正,感谢。

发布了35 篇原创文章 · 获赞 104 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/wk52525/article/details/89392469
今日推荐