监控界的最强王者,没有之一!(3)

简介: 监控界的最强王者,没有之一!(3)

Dog server 设计


下图示例了 server 的整体设计,值得注意的是,我们这里对线程的使用非常地克制,图中只有 3 个工作线程。


22.png


首先是 Kafka Consumer 线程,它负责批量消费消息,从 kafka 集群中消费到的是一个个 Tree 的实例,接下来考虑怎么处理它。


在这里,我们需要将树状结构的 message 铺平,我们把这一步叫做 deflate,并且做一些预处理,形成下面的结构:


23.png


接下来,我们就将 DeflateTree 分别投递到两个 Disruptor 实例中,我们把 Disruptor 设计成单线程生产和单线程消费,主要是性能上的考虑。消费线程根据 DeflateTree 的属性使用绑定好的 Processor 进行处理,比如 DeflateTree 中 List<Message> problmes 不为空,同时自己绑定了 ProblemProcessor,那么就需要调用 ProblemProcessor 来处理。


科普时间:Disruptor 是一个高性能的队列,性能比 JDK 中的 BlockingQueue 要好


这里我们使用了 2 个 Disruptor 实例,当然也可以考虑使用更多的实例,这样每个消费线程绑定的 processor 就更少。我们这里把 Processor 绑定到了 Disruptor 实例上,其实原因也很简单,为了性能考虑,我们想让每个 processor 只有单线程使用它,单线程操作可以减少线程切换带来的开销,可以充分利用到系统缓存,以及在设计 processor 的时候,不用考虑并发读写的问题。


这里要考虑负载均衡的情况,有些 processor 是比较耗费 CPU 和内存资源的,一定要合理分配,不能把压力最大的几个任务分到同一个线程中去了。


核心的处理逻辑都在各个 processor 中,它们负责数据计算。接下来,我把各个 processor 需要做的主要内容介绍一下,毕竟能看到这里的开发者,应该真的是对 APM 的数据处理比较感兴趣的。


Transaction processor


transaction processor 是系统压力最大的地方,它负责报表统计,虽然 Message 有 Transaction 和 Event 两个主要的子类,但是在实际的一颗树中,绝大部分的节点都是 transaction 类型的数据。


24.png


下图是 transaction processor 内部的一个主要的数据结构,最外层是一个时间,我们用分钟时间来组织,我们最后在持久化的时候,也是按照分钟来存的。第二层的 HostKey 代表哪个应用以及哪个 ip 来的数据,第三层是 type、name、status 的组合。最内层的 Statistics 是我们的数据统计模块。


25.png


另外我们也可以看到,这个结构到底会消耗多少内存,其实主要取决于我们的 type、name、status 的组合也就是 ReportKey 会不会很多,也就是我们前面在说客户端打点的时候,要避免维度爆炸。


最外层结构代表的是时间的分钟表示,我们的报表是基于每分钟来进行统计的,之后持久化到 ClickHouse 中,但是我们的使用者在看数据的时候,可不是一分钟一分钟看的,所以需要做数据聚合,下面展示两条数据是如何做聚合的,在很多数据的时候,都是按照同样的方法进行合并。


26.png


你仔细想想就会发现,前面几个数据的计算都没毛病,但是 P90, P95 和 P99 的计算是不是有点欺骗人啊?其实这个问题是真的无解的,我们只能想一个合适的数据计算规则,然后我们再想想这种计算规则,可能算出来的值也是差不多可用的就好了。


另外有一个细节问题,我们需要让内存中的数据提供最近 30 分钟的统计信息,30 分钟以上的才从 DB 读取。然后做上面介绍的 merge 操作。


讨论:我们是否可以丢弃一部分实时性,我们每分钟持久化一次,我们读取的数据都是从 DB 来的,这样可行吗?


不行,因为我们的数据是从 kafka 消费来的,本身就有一定的滞后性,我们如果在开始一分钟的时候就持久化上一分钟的数据,可能之后还会收到前面时间的消息,这种情况处理不了。


比如我们要统计最近一小时的情况,那么就会有 30 分钟的数据从各个机器中获得,有 30 分钟的数据从 DB 获得,然后做合并。


这里值得一提的是,在 transaction 报表中,count、failCount、min、max、avg 是比较好算的,但是 P90、P95、P99 其实不太好算,我们需要一个数组结构,来记录这一分钟内所有的事件的时间,然后进行计算,我们这里讨巧使用了 Apache DataSketches,它非常好用,这里我就不展开了,感兴趣的同学可以自己去看一下。


到这里,大家可以去想一想储存到 ClickHouse 的数据量的问题。app_name、ip、type、name、status 的不同组合,每分钟一条数据。


Sample Processor


sample processor 消费 deflate tree 中的 List<Transaction> transactions 和 List<Event> events 的数据。


我们也是按照分钟来采样,最终每分钟,对每个 type、name、status 的不同组合,采集最多 5 个成功、5 个失败、5 个慢处理。


相对来说,这个还是非常简单的,它的核心结构如下图:


27.png


结合 Sample 的功能来看比较容易理解:


28.png


Problem Processor


在做 deflate 的时候,所有 success=false 的 Message,都会被放入 List<Message> problmes 中,用来做错误统计。


Problem 内部的数据结构如下图:


29.png


大家看下这个图,其实也就知道要做什么了,我就不啰嗦了。其中 samples 我们每分钟保存 5 个 treeId。


顺便也再展示下 Problem 的视图:


30.png


关于持久化,我们是存到了 ClickHouse 中,其中 sample 用逗号连接成一个字符串,problem_data 的列如下:


event_date, event_time, app_name, ip, type, name, status, count, sample
Heartbeat processor


Heartbeat 处理 List<Heartbeat> heartbeats 的数据,题外话,正常情况下,一颗树里面只有一个 Heartbeat 实例。


前面我也简单提到了一下,我们 Heartbeat 中用来展示图表的核心数据结构是一个 Map<String, Double> 。


收集到的 key-value 数据如下所示:


{
  "os.systemLoadAverage": 1.5,
  "os.committedVirtualMemory": 1234562342,
  "os.openFileDescriptorCount": 800,
  "thread.count": 600,
  "thread.httpThreadsCount": 250,
  "gc.ZGC Count": 234,
  "gc.ZGC Time(ms)": 123435,
  "heap.ZHeap": 4051233219,
  "heap.Metaspace": 280123212
}


前缀是分类,后缀是图的名称。客户端每分钟收集一次数据进行上报,然后就可以做很多的图了,比如下图展示了在 heap 分类下的各种图:


31.png


Heartbeat processor 要做的事情很简单,就是数据存储,Dog UI 上的数据是直接从 ClickHouse 中读取的。


heartbeat_data 的列如下:


event_date, event_time, timestamp, app_name, ip, name, value
MessageTree Processor


前面我们多次提到了 Sample 的功能,这些采样的数据帮助我们恢复现场,这样我们可以通过 trace 视图来跟踪调用链。


32.png


要做上面的这个 trace 视图,我们需要上下游的所有的 tree 的数据,比如上图是 3 个 tree 实例的数据。


之前我们在客户端介绍的时候说过,这几个 tree 通过 parent treeId 和 root treeId 来组织。


要做这个视图,给我们提出的挑战就是,我们需要保存全量的数据。


大家可以想一想这个问题,为啥要保存全量数据,我们直接保存被 sample 到的数据不就好了吗?


这里我们用到了 Cassandra 的能力,Cassandra 在这种 kv 的场景中,有非常不错的性能,而且它的运维成本很低。


我们以 treeId 作为主键,另外再加 data 一个列即可,它是整个 tree 的实例数据,数据类型是 blob,我们会先做一次 gzip 压缩,然后再扔给 Cassandra。


Business Processor


我们在介绍客户端的时候说过,每个 Message 都可以携带 Business Data,不过只有应用开发者自己手动埋点的时候才会有,当我们发现有业务数据的时候,我们会做另一个事情,就是把这个数据存储到 ClickHouse 中,用来做业务分析。


我们其实不知道应用开发者到底会把它用在什么场景中,因为每个人负责的项目都不一样,所以我们只能做一个通用的数据模型。


33.png


回过头来看这个图,BusinessData 中我们定义了比较通用的 userId 和 bizId,我们认为它们可能是每个业务场景会用到的东西。userId 就不用说了,bizId 大家可以做来记录订单 id,支付单 id 等。


然后我们提供了 3 个 String 类型的列 ext1、ext2、ext3 和两个数值类型的列 extVal1 和 extVal2,它们可以用来表达你的业务相关的参数。


我们的处理当然也非常简单,将这些数据存到 ClickHouse 中就可以了,表中主要有这些列:


event_data, event_time, user, biz_id, timestamp, type, name, status, app_name、ip、success、ext1、ext2、ext3、ext_val1、ext_val2

这些数据对我们 Dog 系统来说肯定不认识,因为我们也不知道你表达的是什么业务,type、name、status 是开发者自己定义的,ext1, ext2, ext3 分别代表什么意思,我们都不知道,我们只负责存储和查询。


这些业务数据非常有用,基于这些数据,我们可以做很多的数据报表出来。因为本文是讨论 APM 的,所以该部分内容就不再赘述了。


其他


ClickHouse 需要批量写入,不然肯定是撑不住的,一般一个 batch 至少 10000 行数据。


我们在 Kafka 这层控制了,一个 app_name + ip 的数据,只会被同一个 dog-server 消费,当然也不是说被多个 dog-server 消费会有问题,但是这样写入 ClickHouse 的数据就会更多。


还有个关键的点,前面我们说了每个 processor 是由单线程进行访问的,但是有一个问题,那就是来自 Dog UI 上的请求可怎么办?这里我想了个办法,那就是将请求放到一个 Queue 中,由 Kafka Consumer 那个线程来消费,它会将任务扔到两个 Disruptor 中。比如这个请求是 transaction 报表请求,其中一个 Disruptor 的消费者会发现这个是自己要干的,就会去执行这个任务。


小结


如果你了解 Cat 的话,可以看到 Dog 在很多地方和 Cat 有相似之处,或者直接说”抄“也行,之前我们也考虑过直接使用 Cat 或者在 Cat 的基础上做二次开发。但是我看完 Cat 的源码后,就放弃了这个想法,仔细想想,只是借鉴 Cat 的数据模型,然后我们自己写一套 APM 其实不是很难,所以有了我们这个项目。




相关文章
|
SQL 关系型数据库 MySQL
解决sql插入字符串中包含‘单引号问题
解决sql插入字符串中包含‘单引号问题
1757 2
解决sql插入字符串中包含‘单引号问题
|
算法 Java Docker
YODA
YODA
599 2
|
人工智能 运维 安全
重塑高校计算机实验室:从硬件到开源应用聚合与托管平台的转型
高校计算机实验室面临环境碎片化、资源分配失衡及安全管控难题。WebSoft9提出四维重构框架,从硬件层融合异构资源、应用层聚合开源工具链、运维层实现智能管理到教学科研协同优化,助力实验室转型。通过AI教学与跨校区协作等实战案例,展示其高效解决方案。建议分阶段实施,先搭建基础平台再逐步扩展功能,同时注重权限分级与混合云备份以规避风险。
491 0
重塑高校计算机实验室:从硬件到开源应用聚合与托管平台的转型
|
10月前
|
人工智能 运维 自然语言处理
技术思辨|AI Coding:经验壁垒正在失效,工具进化重塑编程
本文探讨AI Coding对传统研发模式的影响,总结5大变化趋势。AI虽降低技术门槛,但专业性并未消失,而是向更高维度转移,如问题定义与批判性思维。高效专注、可复用性及架构设计仍为核心,全栈开发与领域专家角色并存。测试与研发左移减少信息损耗,提升效率。那10%的核心技能包括长程规划、决策制定、创造性解决问题、协作沟通及持续学习能力,是AI时代开发者的关键竞争力。最后强调“老师傅”的经验依然重要,需转变价值体现方式以适应新时代需求。
技术思辨|AI Coding:经验壁垒正在失效,工具进化重塑编程
|
JavaScript API PHP
一言API搭建教程:搭建属于自己的文言API接口
这篇文章介绍了如何搭建一个属于自己的文言API接口。文章首先介绍了准备工作,包括代码编辑器和两个文件的创建。然后详细说明了如何将代码复制到php文件中并上传至网站根目录。最后给出了一个示例代码来调用文言API接口。整个过程非常简单。
388 2
|
XML 监控 Java
异步日志:性能优化的金钥匙
本文主要介绍了Log4j2框架的核心原理、实践应用以及一些实用的小Tips,力图揭示Log4j2这一强大日志记录工具在现代分布式服务架构运维中的关键作用。
|
设计模式 缓存 Dubbo
Apache ShenYu 网关正式支持 Dubbo3 服务代理
本文介绍了如何通过 Apache ShenYu 网关访问 Dubbo 服务,主要内容包括从简单示例到核心调用流程分析,并对设计原理进行了总结。
1267 87
Apache ShenYu 网关正式支持 Dubbo3 服务代理
|
Java API Apache
阿里巴巴开源框架JarsLink
JarsLink是一个基于JAVA的模块化开发框架,它提供在运行时动态加载模块(JAR包)、卸载模块和模块间调用的API,它能够帮助你进行模块化开发,也能帮助你的系统在运行时动态添加新功能,减少编译、打包和部署带来的发布耗时,同时它也是阿里巴巴的开源项目之一 https://github.com/alibaba/jarslink,目前在微贷事业群各团队广泛使用。
15006 0
|
Windows
(查看,和保存)windows下通过cmd命令符窗口查看、保存文件目录结构
(查看,和保存)windows下通过cmd命令符窗口查看、保存文件目录结构
741 0
|
Linux 编译器 开发者
C/C++动态库与静态库 的详细解析
C/C++动态库与静态库 的详细解析
1847 0