eBay邓明:dubbo-go 中 metrics 的设计

最近因为要在 Apache/dubbo-go(以下简称 dubbo-go )里面实现类似的这个 metrics 功能,于是花了很多时间去了解现在 Dubbo 里面的 metrics 是怎么实现的。该部分,实际上是被放在一个独立的项目里面,即 metrics 。

总体上来说,Dubbo 的 metrics 是一个从设计到实现都非常优秀的模块,理论上来说,大部分的 Java 项目是可以直接使用 metrics 的。但也因为兼顾性能、扩展性等各种非功能特性,所以初看代码会有种无从下手的感觉。

今天这篇文章将会从比较大的概念和抽象上讨论一下 dubbo-go 中的 metrics 模块的设计——实际上也就是 Dubbo 中的 metrics 的设计。因为我仅仅是将 Dubbo 里面的相关内容在 dubbo-go 中复制一份。

目前 dubbo-go 的 metrics 刚刚开始起步,第一个 PR ,点击这里

总体设计

Metric

要想理解 metrics 的设计,首先要理解,我们需要收集一些什么数据。我们可以轻易列举出来在 RPC 领域里面我们所关心的各种指标,诸如每个服务的调用次数,响应时间;如果更加细致一点,还有各种响应时间的分布,平均响应时间,999线……

但是上面列举的是从数据的内容上划分的。 metrics 在抽象上,则是摒弃了这种划分方式,而是结合了数据的特性和表现形式综合划分的。

从源码里面很容易找到这种划分的抽象。

metrics 设计了 Metric 接口作为所有数据的顶级抽象:

在 Dubbo 里面,其比较关键的子接口是:

为了大家理解,这里我抄一下这些接口的用途:

  • Gauge: 一种实时数据的度量,反映的是瞬态的数据,不具有累加性,例如当前 JVM 的线程数;
  • Counter: 计数器型指标,适用于记录调用总量等类型的数据;
  • Histogram : 直方分布指标,例如,可以用于统计某个接口的响应时间,可以展示 50%, 70%, 90% 的请求响应时间落在哪个区间内;
  • Meter: 一种用于度量一段时间内吞吐率的计量器。例如,一分钟内,五分钟内,十五分钟内的qps指标;
  • Timer: Timer相当于Meter+Histogram的组合,同时统计一段代码,一个方法的qps,以及执行时间的分布情况;

目前 dubbo-go 只实现了 FastCompass ,它也是 Metric 的子类:

这个接口功能很简单,就是用于收集一段时间之内的 subCategory 执行的次数和响应时间。 subCategory 是一个比较宽泛的概念,无论是在 Dubbo 还是在 dubbo-go 里面,一个典型的 subCategory 就会是某个服务。

这里的设计要点在于,它是从什么角度上去做这些数据的抽象的。

很多人在开发这种采集数据的相关系统或者功能的时候,最容易陷入的就是从数据内容上做抽象,例如抽象一个接口,里面的方法就是获得服务的调用次数或者平均响应时间等。

这种抽象并非不可以,尤其是在简单系统里面,还非常好用。唯独在通用性和扩展性上要差很多。

MetricManager

在我们定义了 Metric 之后,很容易就想到,我要有一个东西来管理这些 Metric 。这就是 MetricManager ——对应到 Dubbo 里面的 IMetricManager 接口。

MetricManager 接口目前在 dubbo-go 里面还很简单:

本质上来说,我在前面提到的那些 Metric 的子类,都可以从这个 MetricManager 里面拿到。它是对外的唯一入口。

因此无论是上报采集的数据,还是某些功能要用这些采集的数据,最重要的就是获得一个 MetricManager 的实例。例如我们最近正在开发的接入 Prometheus 就是拿到这个 MetriManger 实例,而后从里面拿到 FastCompass 的实例,而后采集这些数据:

MetricRegistry

MetricRegistry 是一个对 Metric 集合的抽象。 MetricManager 的默认实现里面,就是使用 MetricRegistry 来管理 Metric 的:

所以,本质上它就是提供了一些注册 Metric 然后再从里面捞出来的方法。

于是,这就有一个问题了:为什么我在有了 MetricManager 之后,还有有一个MetricRegistry?似乎这两个功能有些重叠?

答案大概是两个方面:

1、除了管理所有的 Metric 之外,还承担着额外的功能,这些功能典型的就是 IsEnabled 。而实际上,在未来我们会赋予它管理生命周期的责任,比如说在 Dubbo 里面,该接口就还有一个 clear 方法;
2、 metrics 里面还有一个 group 的概念,而这只能由 MetricManager 来进行管理,至少交给 MetricRegistry 是不合适的。

metrics 的 group 说起来也很简单。比如在 Dubbo 框架里面采集的数据,都会归属于 Dubbo 这个 group 。也就是说,如果我想将非框架层面采集的数据——比如纯粹的业务数据——分隔出来,就可以借用一个 business group 。又或者我采集到的机器自身的数据,可以将其归类到 system 这个 group 下。

所以 MetricManger 和 MetricRegistry 的关系是:

Clock

Clock 抽象是一个初看没什么用,再看会觉得其抽象的很好。Clock 里面就两个方法:

一个是获得时间戳,另外一个则是获得时间周期(Tick)。比如通常采集数据可能是每一分钟采集一次,所以你得知道现在处在哪个时间周期里面。Clock 就提供了这种抽象。

很多人在实现自己的这种 metrics 的框架的时候,大多数都是直接使用系统的时钟,也就是系统的时间戳。于是所有的 Metic 在采集数据或者上报数据的时候,不得不自己去处理这种时钟方面的问题。

这样不同的 Metric 之间就很难做到时钟的同步。比如说可能在某个 Metric1 里面,采集周期是当前这一分钟,而 Metric2 是当前这一分钟的第三十秒到下一分钟的第三十秒。虽然它们都是一分钟采集一次,但是这个周期就对不上了。

另外一个有意思的地方在于,Clock 提供的这种抽象,允许我们不必真的按照现实时间的时间戳来处理。比如说,可以考虑按照 CPU 的运行时间来设计 Clock 的实现。

例子

就用这一次 PR 的内容来展示一下这个设计。

在 dubbo-go 里面这次实现了 metricsFilter ,它主要就是收集调用次数和响应时间,其核心是:

report 其实就是把 metrics reports 给 MetricManager :

所以,这里面可以看出来,如果我们要收集什么数据,也是要先获得 MetricManager 的实例。

FastCompass 的实现里面会将这一次调用的服务及其响应时间保存下来。而后在需要的时候再取出来。

所谓的需要的时候,通常就是上报给监控系统的时候。比如前面的提到的上报给 Prometheus。

所以这个流程可以抽象表达为:

这是一个更加宽泛的抽象。也就是意味着,我们除了可以从这个 metricFilter 里面收集数据,也可以从自身的业务里面去收集数据。比如说统计某段代码的执行时间,一样可以使用 FastCompass 。

而除了 Prometheus ,如果用户自己的公司里面有监控框架,那么他们可以自己实现自己的上报逻辑。而上报的数据则只需要拿到 MetricManager 实例就能拿到。

总结

本质上来说,整个 metrics 可以看做是一个巨大无比的 provider-conumer 模型。

不同的数据会在不同的地方和不同时间点上被采集。有些人在读这些源码的时候会有点困惑,就是这些数据什么时间点会被采集呢?

它们只会在两类时间点采集:

1、实时采集。如我上面举例的 metricsFilter ,一次调用过来,它的数据就被采集了;
2、另外一个则是如同 Prometheus 。每次 Prometheus 触发了 collect 方法,那么它就会把每种(如 Meter, Gauge )里面的数据收集过来,然后上报,可以称为是定时采集;

Dubbo 里面采集了非常多的数据:

这些具体的实现,我就不一一讨论了,大家有兴趣可以去看看源码。这些数据,也是我们 dubbo-go 后面要陆续实现的东西,欢迎大家持续关注,或者来贡献代码。

作者信息:邓明,毕业于南京大学,就职于 eBay Payment 部门,负责退款业务开发。


本文作者:邓明

阅读原文

本文为阿里云内容,未经允许不得转载。

Image placeholder
alexlis
未设置
  69人点赞

没有讨论,发表一下自己的看法吧

推荐文章
SpringBoot 整合 Dubbo

1.整合dubbo 有的人或许会说已经有spring-cloud了,你整合dubbo干什么,其实没啥意图,主要就是想整合一下,毕竟dubbo在国内使用的还是很多的,你会一点点总不至于让你显得那么尴尬。

Dubbo 毕业,成为 Apache 基金会顶级项目

Dubbo发展史一览2011年10月27日,阿里巴巴开源了自己服务化治理方案的核心框架Dubbo,服务治理的设计理念开始逐渐在国内软件行业中落地,并被广泛应用。自开源后,许多非阿里系公司选择使用Dub

Dubbo 在 K8s 下的思考

作者|曹胜利  ApacheDubboPMC导读:Dubbo作为高性能JavaRPC框架的刻板印象早已深入人心,在CloudNative的架构选型上,SpringCloud或许才是业界的优先选择。实际

Dubbo 稳定性案例:Nacos 注册中心可用性问题复盘

问题描述上周四晚刚回到家,就接到了软负载同学的电话,说是客户线上出了故障,我一听”故障“两个字,立马追问是什么情况,经过整理,还原出线上问题的原貌:客户使用了Dubbo,注册中心使用的是Nacos,在

瓜子二手车在 Dubbo 版本升级、多机房方案方面的思考和实践

前言随着瓜子业务的不断发展,系统规模在逐渐扩大,目前在瓜子的私有云上已经运行着数百个Dubbo应用,上千个Dubbo实例。瓜子各部门业务迅速发展,版本没有来得及统一,各个部门都有自己的用法。随着第二机

Spring WebFlux 的设计及工作原理剖析

前言 Spring5发布有两年了,随Spring5一起发布了一个和SpringWebMvc同级的SpringWebFlux。这是一个支持反应式编程模型的新框架体系。反应式模型区别于传统的MVC最大的不

软件架构被高估,清晰简单的设计被低估

软件架构最佳实践、企业架构模式以及系统描述的正式方法都是非常重要且实用的工具,总会有合适的场景让它们发挥作用。但在设计系统时,请从简单始、以简单终,尽可能避免一切会无谓提高复杂度的架构与正式工具。

分布式时序数据库QTSDB的设计与实现

现有的开源时序数据库influxdb只支持单机运行,在面临大量数据写入时,会出现查询慢,机器负载高,单机容量的限制。为了解决这一问题,360基础架构团队在单机influxdb的基础上,开发了集群版——

百亿流量微服务网关的设计与实现

本文从百亿流量交易系统微服务网关(APIGateway)的现状和面临的问题出发,阐述微服务架构与API网关的关系,理顺流量网关与业务网关的脉络,分享API网关知识与经验。API网关概述“计算机科学领域

GoWeb教程_13.0. 如何设计一个 Web 框架

前面十二章介绍了如何通过Go来开发Web应用,介绍了很多基础知识、开发工具和开发技巧,那么我们这一章通过这些知识来实现一个简易的Web框架。通过Go语言来实现一个完整的框架设计,这框架中主要内容有第一

GoWeb教程_13.3. controller 设计

传统的MVC框架大多数是基于Action设计的后缀式映射,然而,现在Web流行REST风格的架构。尽管使用Filter或者rewrite能够通过URL重写实现REST风格的URL,但是为什么不直接设计

基于 Hyperf 实现 RabbitMQ + WebSocket 消息推送

#介绍 基于Hyperf+WebSocket+RabbitMQ实现的一个简单大屏幕的消息推送。 #思路 利用WebSocket协议让客户端和服务器端保持有状态的长链接,保存链接上来的客户端id。订阅发

如何设计 QQ、微信、微博、Github 等等,第三方账号登陆 ?(附表设计)

前言:多账户登陆1.创业初期用户名密码注册登陆手机号注册登陆2.数据库设计3.引入第三方账户方案4.数据库设计5.总结前言:多账户登陆互联网应用当中,我们的应用会使用多个第三方账号进行登录,比如:网易

【Kubernetes系列】第5篇 Ingress controller – traefik组件介绍

1.概述为了能够让Ingress资源能够工作,在Kubernetes集群中必须至少有一个运行中的ingresscontroller组件。也就是说如果在kubernetes集群中没有一个ingressc

Kubernetes 基础信息:什么是 Kubernetes?

简介 Kubernetes(常简称为K8s,在希腊语意为“舵手”或“驾驶员”)是用于自动部署、扩展和管理容器化(containerized)应用程序的开源系统。 由JoeBeda、BrendanBur

GoWeb教程_08.2. WebSocket

WebSocket是HTML5的重要特性,它实现了基于浏览器的远程socket,它使浏览器和服务器可以进行全双工通信,许多浏览器(Firefox、GoogleChrome和Safari)都已对此做了支

SpringBoot整合RabbitMQ

SpringBoot整合RabbitMQSpringBoot框架已经提供了RabbitMQ的使用jar包,开发人员在使用RabbitMQ的时候只需要引用jar包简单的配置一下就可以使用RabbitMQ

SpringBoot连接多RabbitMQ源

在实际开发中,很多场景需要异步处理,这时就需要用到RabbitMQ,而且随着场景的增多程序可能需要连接多个RabbitMQ。SpringBoot本身提供了默认的配置可以快速配置连接RabbitMQ,但

使用dotnet-dump分析dotnet转储文件

课程推荐:web全栈开发就业班--拿到offer再缴学费--融职教育 有很多时候,在生产环境会产生各种各样的问题,但在生成环境计划是不能调试的,所以dotnet-dump这时就启动作用了。 除了dot

GoWeb教程_13.2. 自定义路由器设计

HTTP路由 HTTP路由组件负责将HTTP请求交到对应的函数处理(或者是一个struct的方法),如前面小节所描述的结构图,路由在框架中相当于一个事件处理器,而这个事件包括: 用户请求的路径(pat

GoWeb教程_13.4. 日志和配置设计

日志和配置的重要性 前面已经介绍过日志在我们程序开发中起着很重要的作用,通过日志我们可以记录调试我们的信息,当初介绍过一个日志系统seelog,根据不同的level输出不同的日志,这个对于程序开发和程

SpringBoot 中的 Servlet Web 容器

1.前言 SpringBoot支持一下嵌入式Servlet容器: SpringBoot2.0.3.RELEASE需要Java8或9以及SpringFramework5.0.7.RELEASE或更高版本

重回榜首!Facebook开源加强版BERT,全面超越XLNet

大数据文摘出品作者:宁静刚刚被拉下神坛的BERT又一次称霸了GLUE、SQuAD和RACE三个排行榜。今年六月,谷歌发布XLNet,指出并解决了BERT的缺点,在20多个指标上全面刷爆了BERT之前的

云端的生存之道,第 1 单元:将 Spring Boot 部署到 Kubernetes

初始化Kubernetes集群 第一步是初始化IBMCloud上的Kubernetes集群。IBMCloud可能需要几分钟时间来启动新的Kubernetes集群;因此,通过先执行初始化操作,可以在后台

【CSS全解01】CSS基础-体系化学CSS

大纲 基础部分学习占比:HTML1%`CSS19%Javascript80%`(`基础部分?%框架?%`项目?%) CSS历史 AcidTestforbrowser CSS是艺术(非逻辑,用测试经验来