在 2018 年,Observability(即可观测性)首次被引入 IT 领域,并逐渐取代只关注系统整体可用性的传统监控。随着云原生技术的不断发展,企业从单体架构发展到分布式架构,使用容器部署拆分出来的一众微服务、与业务联系紧密,传统的监控仅适合报告系统的整体运行情况无法进行高度细化的分析与关联,于是需要将研发视角融入监控,发展具有比原有监控更广泛、更主动、更细粒度的能力,这种能力就是可观测性。
Dubbo3 的建设规划有上云,可观测性是上云必不可少的能力,集群间根据实例可用性负载均衡、Kubernetes 弹性伸缩、建立实例健康模型等等运用场景都需要可观测性。
目前 Dubbo3 的可观测性正在建设中,本文主要介绍 Metrics 模块基础知识与进度。
零 - APM介绍
APM全称是 application performance management,翻译过来就是应用的性能管理,主要是用来管理和监控软件系统的性能和可用性。可以保障线上服务的质量,是一个重要的服务治理工具。
如果从系统职能上分的话,APM系统的话可以可以分为三个子系统,分别是 Metrics、Tracing 和 Logging。
Metrics 也叫指标监控,主要是负责处理一些结构化的可以聚合的一些指标数据。
Tracing 又叫链路追踪,主要是围绕单次请求进行信息处理,然后所有的数据都被绑定到系统的单个请求或者说单个事务上。
Logging 是日志监控,主要梳理一些非结构化的事件。
一、Metrics结构与类型
一个 Metrics 由四部分组成,第一个是指标名称;第二个是 labels 或者说tags也就是标签,是一些维度数据,这些维度数据可以用来做一些过滤或者聚合查询;第三个是时间戳,就是它的时间字段;第四个就是具体的指标的一个值。
除了上述四个部分之外,还有一个非常重要的字段没有体现在数据模型里,就是这条数据的指标类型。不同的指标类型的话它是会用在不同的监控场景,同时它的一些查询和可视化的一些方式,也会有一些区别。
下面简单介绍一些常用的指标类型。
第一个是 Gague,这个类型的特点就是他是可增可减的。比如说 CPU 负载、活跃线程数、内存使用率、磁盘使用率,这些数它都是会随着时间进行波动的。它存储和展示的都是一个瞬时值。
第二个指标类型 Counter,这个类型的特点是只增不减,比如说接口请求总量,对于这个类型,一般会有几个衍生的处理,一个是可以比较两个时间点前后的一个差值,这样可以计算出这个单位时间内的请求的一个波动量。第二个就是对时间进行求导之后,就得到 QPS 这种类型的一个字段。
第三个指标类型是 Summary,主要做的是一个汇总统计,比如说平均值,分位数这样的一些指标。然后这个指标类型的话主要用于接口响应延迟这样的一个场景。因为我们平时在看接口响应延迟这个指标的时候,一般除了看它的平均值,可能还会看一些那种分位数指标。
第四个指标类型是 Historgram,它是一个柱状统计,一般是会先对指标进行一个分桶,分桶之后再去统计它的一些值。比如说我们的还是以那个接口响应延迟为例的话,它会比如说有一些那种可视化展示的话,展示它的那个柱状图。
二、指标收集
Dubbo 的指标体系,总共涉及三个模块,分别是指标收集、本地聚合、指标推送。
- 指标收集:将Dubbo内部需要监控的指标推送至统一的collector中进行存储。
- 本地聚合:指标收集获取的均为基础指标,而一些分位数指标则需通过本地聚合计算得出。
- 指标推送:而获取指标的话有两种方式,第一种是直接访问dubbo暴露的接口就可以获得dubbo内部统计的指标,第二种是接入第三方服务器进行指标推送,dubbo会将收集和聚合后的指标通过pull或者push的方式推送至第三方服务器,目前只涉及Prometheus,其中pull或者push由用户选择。
1. 指标收集
指标收集的目的是为了存储微服务的运行状态,相当于给微服务拍了一个快照,以及为进一步的分析(比如指标聚合)提供基础数据。
上图为 Dubbo 的架构图,本方案中指标收集的埋点位置或者说切入位置是在 provider 中通过 SPI 的方式添加一个Filter。
这里贴了部分代码,展示了其中一部分指标收集的逻辑。
我们是通过 interfaceName、methodName、group、version 四个维度的信息作为 map 存储结构的 key ,当然这四个维度的信息最后在指标导出的时候都会转换成前面 metrics 存储结构的 labels 或者说 tags。
接下来给大家展示一个的是我们一个默认存储器的成员变量。
运用分段锁结构的 ConcurrentHashMap 来保证并发度,其中的 MethodMetric 就是前文说的四个维度信息组成的一个 class。
有一个比较重要的结构是一个 MetricsListener 的 list ,这里其实是一种生产者消费者的模式,因为默认收集器是我们默认接入的,但是如果需要收集其他指标则需要继续在此添加监听,让其他收集器监听默认收集器的状态,当默认收集器收集到了值就向监听列表推送一个事件,这样其他收集器就能收集到元信息再进一步加工处理。这里也是本地聚合实现的一个逻辑,具体细节不展示了,有兴趣的同学可以去看看 Dubbo 3.1 的代码。
2. 本地聚合-滑动窗口与 TDigest
本地聚合主要使用滑动窗口与 TDigest,滑动窗口原理如图,假设我们初始有 6 个 bucket,每个窗口时间(即一个 bucket 在 current 指针下的停留时间)设置为2分钟,每次写入指标数据时,会将数据分别写入 6 个 bucket 内,也就是一条数据写六遍,我们会每隔两分钟移动一个 bucket 并且清除原来 bucket 内的数据,读取指标时,会读取当前 current 指向的 bucket 内的指标数据,以达到滑动窗口的效果。
滑动窗口的作用是为了能够对近期的数据做一个聚合,使得我们每次指向的 bucket 里面存储的都是从当前时间到过去一个 bucket 生命周期(即 [ now - bucketLiveTime * bucketNum, now ] 这样一个时间区间)的指标数据。其中 bucket 的生命周期受窗口时间和 bucket 数量控制,这个支持用户自定义配置。
接下来是介绍 Dubbo 分位数指标的处理,我们常说的 p99,p95 这样的指标就是分位数指标,p99是指在100个请求里面,响应时延排名第99位的值,可以较好的反应一个服务的可用性,被称为黄金指标。
Dubbo 在计算分位数指标的时候使用了 TDigest 算法,TDigest 是一个简单,快速,精确度高,可并行化的近似百分位算法。
TDigest 使用的思想是近似算法常用的 Sketch,也就是素描,用一部分数据来刻画整体数据集的特征,就像我们日常的素描画一样,虽然和实物有差距,但是却看着和实物很像,能够展现实物的特征。
下面是TDigest 的原理。假如有 500 个 -30 ~ 30 间的数字,可以使用概率密度函数也就是PDF函数表示这一数据集
该函数上的某一点的 y 值就是其 x 值在整体数据集中的出现概率,整个函数的面积相加就正好为 1 ,可以说它刻画了数据在数据集中的分布态势,也就是大家熟悉的正态分布。
有了数据集对应的 PDF 函数,数据集的百分位数也能用 PDF 函数的面积表示。如下图所示,百分位数P75就是面积占了 75% 时对应的 x 坐标。
PDF 函数曲线中的点都对应着数据集中的数据,当数据量较少时,我们可以使用数据集的所有点来计算该函数,但是当数据量较大时,只有通过少量数据来代替数据集的所有数据。
这里,需要将数据集进行分组,相邻的数据分为一组,用平均数和来代替这一组数。这两个数合称为质心数,然后用这个质心数来计算PDF,这就是TDigest算法的核心思想。
如下图所示,质心数的平均值作为x值,个数作为y值,可以通过这组质心数大致绘制出这个数据集的PDF函数:
对应的,计算百分位数也只需要从这些质心数中找到对应的位置的质心数,它的平均值就是百分位数值。
很明显,质心数的个数值越大,表达它代表的数据越多,丢失的信息越大,也就越不精准。如这张图所示,太大的质心数丢失精准度太多,太小的质心数则有消耗内存等资源较大,达不到近似算法实时性高的效果。
所以,TDigest 在压缩比率的基础上,按照百分位数来控制各个质心数代表的数据的多少,在两侧的质心数较小,精准度更高,而在中间的质心数则较大,以此达到P1 或 P99 的值要比P20更准确的效果。
3. 指标推送之 Prometheus
指标推送的作用是为了将目前 Dubbo 提供的指标进行进一步的存储、运算和可视化,目前第三方服务器只支持 Prometheus。Prometheus 是 CNCF 开源的一个应用于应用监控的系统。主要有三个模块组成,分别是获取数据,存储数据,数据查询。
获取数据有 Pull 和 Push 两种方式,也是 Dubbo 接入的方式;存储数据 Prometheus 是用的时序数据库这里就不展开讲了;数据查询是其自定义的一套查询 IDL,可以接入 Grafana 这一类报警系统,当监控指标异常时候可以使用邮件报警或者电话报警。
目前的设计:
指标推送只有用户在设置了<dubbo:metrics />配置且配置protocol参数后才开启,若只开启指标聚合,则默认不推送指标。
- Promehteus Pull ServiceDiscovery:启动时根据配置将本机 IP、Port、MetricsURL 推送地址信息至中间层,暴露 HTTP ServiceDiscovery 供 Prometheus 读取,配置方式如 <dubbo:metrics protocol="prometheus" mode="pull" address="${dubbo-admin.address}" port="20888" url="/metrics"/>,其中在 Pull 模式下 address 为可选参数,若不填则需用户手动在 Prometheus 配置文件中配置地址。
- Prometheus Push Pushgateway:用户直接在 Dubbo 配置文件中配置 Prometheus Pushgateway 的地址即可,如 <dubbo:metrics protocol="prometheus" mode="push" address="${prometheus.pushgateway-url}" interval="5" />,其中 interval 代表推送间隔
相关 Dubbo Metrics 功能我们预计会在 3.1.2 / 3.1.3 版本中正式 release 发布。
三、服务治理与商业化
Dubbo3 的可观测性建设是 Dubbo3 上云必不可少的一个环节。在 Dubbo3 对标的商业化产品微服务引擎 MSE 中,针对 Dubbo3 做了全方面的增强,以一种无侵入的方式增强 Dubbo3 服务,使其具备完整的微服务治理能力。
在建设Dubbo可观测性的同时,我们也在结合 OpenSergo 标准构建 Dubbo3 的完整的服务治理体系。
OpenSergo 在联合各个社区进行进一步的合作,希望通过社区来一起讨论与定义统一的服务治理标准。当前社区也在联合 bilibili、CloudWeGo等企业、社区一起共建标准,也欢迎感兴趣的开发者、社区与企业一起加入到 OpenSergo 服务治理标准共建中。欢迎大家加入 OpenSergo 社区交流群(钉钉群)进行讨论:34826335