分布式监控的重要设计就是数据存储模型,而 SkyWalking 的分布式追踪数据模型就是一个经典代表,这也是它会在 APM 领域脱颖而出的原因。

所以今天我就以 SkyWalking 为例,结合明细模型中的分布式追踪模型、指标明细中的稳定性模型、采样数据模型中的数据慢查采样模型,通过对这三个典型模型的横向对比学习,纵向了解收集端计算存储模型的详细过程。

四大存储模型

SkyWalking 的数据存储也是通过微内核和插件形式实现的:数据存储模型是在收集端经过各个插件计算而出,所有插件存放在 oap-server/server-receiver-plugin。

目前收集端的插件主要会构建以下四个存储模型。

为了优化传输效率和存储能力,SkyWalking 会使用注册发现模式去构建注册模型,但注册模型天生会在异步收集场景和客户端内存空间上存在劣势。所以 8.x 版本 SkyWalking 去掉了注册模型,取而代之的是通过 Base64 编码计算注册的唯一值。

虽然这在网络传输上带来了性能损失,但内存优化和异步场景带来的体验上却有了极大提升。显然在当今的内部集群都是万兆网卡的硬件资源下,这样的利是大于弊的,所以注册存储模型我就略讲了。

存储模型中数据量最大的就是明细模型,在存储优化上,收集端会在构建数据索引时,忽略部分不需要索引的数据,以优化存储性能。

对于指标数据,多数的指标数据都是通过脚本语言构建出来了,SkyWalking 通过 OAL 脚本进行指标明细构建。

采样模型通过自定义排序,在一定的时间窗口内采样数据,计算 TOP 指标来完成采样数据的记录,典型的场景是对 DB 执行延迟进行采样,监控出对数据库造成慢查的 SQL。

所以接下来,我会以分布式链路追踪的明细数据、稳定性的指标数据、数据库采样的采样模型为重点逐一进行讲解。

分布式追踪的明细数据

SkyWalking 有多种明细数据(Record)模型,如报警明细数据模型,通过定义报警规则的配置来完成报警;又如 JaegerSpan 或 ZipkinSpan 明细模型,通过收集其他 APM 数据来完成全局的 Span 数据追踪。

但在明细模型数据中,最通用的就是分布式链路追踪(SegmentRecord)的明细追踪模型,它是计算其他各个存储模型的基础数据,其重要属性有以下五点。

1.原始数据流(data_binary)

任务线程监控数据,通过 Base 64 对数据对象进行编码,并存储到 Elasticsearch 索引中。由于原始数据流字段中包含所有以任务线程为监控维度的数据,所以该字段的容量明显高于其他字段好几个维度(而其他字段是从任务线程监控数据中,根据指定属性取出),从而原始数据流的数据也就被设计为不需要查询的资源(对应存储中就是不需要索引)。

在 Elasticsearch 的索引中,索引的名称为 {cluster}segment{time_bucket},可以看出索引的名称包括了三个部分。

cluster 为 SkyWalking 收集端的集群标识。我们真实的线上应用集群非常复杂,在网络或跨机房等情况下,能难尽搭建一套 SkyWalking 集群就面面俱到,因此真实场景是往往需要多个集群才能适配应用服务集群的复杂架构。但如果需要跨网段定位问题时,我们就可以通过 Elasticsearch 的跨集群查询配置,通过 SkyWalking 收集端的集群标识,打破隔离带来的束缚。

segment 标识了此索引为分布式追踪数据的存储模型。

time_bucket 为以时间切分存储模型的标识。因为 APM 数据是海量级别的,通过一定的时间窗口规则,比如以“天”来划分表,这样存储模型就有了时序。通过时序查询,可以实现海量数据的快速插入和检索;通过时序删除指定的索引,可以避免索引碎片带来的性能问题。

2.时间

分布式追踪数据中,一共有 3 个时间相关的属性:开始时间(start_time)、结束时间(end_time)、延迟。时间使用 LongTime 类型记录,避免了时区和空间占用的问题。

在同步模式,开始时间是任务线程被监控的起始,结束时间是退出任务线程监控时间的时刻,延迟为两个时间的差值。

但在异步模式下,分布式监控数据会由多个任务线程的监控数据组成。在发生异步时,当前任务线程的开始,监控时间会传递到接下来的任务线程;而当前任务线程的监控数据,为了防止内存泄漏会被回收掉,并且不会发送到收集端。所以开始时间和结束时间会在异步模式相互关联的任务线程中被持续覆盖,直到真正的发送监控数据任务线程完成数据汇总后,才发送给收集端。

3.端点(endpoint)

在存储模型中,端点信息包括以下两个属性。

入口服务的端点名称

规则的实现逻辑是:第一个 Span 的操作名称就是入口服务的端点名称。那为什么会用这一规则呢?

在我看来,APM 的分布式链路追踪的记录粒度,是记录对端调用的 Span 粒度,也就是支持记录调用过程中内部 Span 粒度。所以记录入口服务的端点名称是最合理的。

端点 ID

在 8.x 版本前,SkyWalking 通过注册模式记录,并生成入口服务的端点名称对应的端点 ID。但我们发现 APM 注册的端点名称是海量级的,并在未归类的 RESTful API 场景下更为突出。

这不仅会给收集端存储注册模型带来性能压力,更会由于需要缓存端点注册信息,给客户端也带来较大的空间压力。这个问题是 APM 注册发现模式的通病,它不仅在端点模型中存在,更在网络地址模型、服务实例模型中存在。

所以在 8.x 后的版本中 SkyWalking 摒弃了注册发现模型,全部通过 Base 64 编码对端点名称进行压缩:在服务端,为各个组件提供归类端点名称支持;在客户端,取消缓存端点的空间。

关于具体的实现设计,你可以查看“在探针侧配置支持操作名称分组的规则”,去了解 SkyWalking 是如何实现端点名称归类的。

4.监控数据标识

存储模型有两个关于监控标识的属性。

SegmentID:监控数据模型的唯一 ID,在任务线程的第一个监控点,使用雪花算法实现。

TraceID:全局分布式追踪 ID,消息队列、分布式事务等批处理框架存在多个 TraceID。

这两个重要属性在前文中已有很多介绍,这里就不过多赘述。

5.标记数据

为描述当前追踪数据的特征,SkyWalking 的追踪存储模型提供了很多标记属性,按照粗、细进行分类。

细分类:我们想更精细地描述一个 Span 时,可以通过数组类型 Tags 的字段,来存储个性化的标记数据,从而实现精细描述。如在数据组件中,tags 会存储 db.type 和 db.instance,来分别标识数据库类型和数据库实例标识。这只是数据库组件的 Tags 细分类。

粗分类:每个分布式链路存储数据都有 statement 和 is_error 字段,前者 statement 用于标记当前组件的执行语句,后者标记当前组件执行正常与否。

稳定性指标数据

指标存储(Metric)模型的计算是通过 OAL 脚本聚合分析得出,如稳定性指标语句:

service_instance_sla = from(ServiceInstance.*).percent(status == true)。

这个语句的释义:服务的稳定性,通过服务实例状态的健康百分比程度进行计算,从而得到衡量和表达。

from 代表数据的挖掘来源,ServiceInstance.* 代表挖掘数据为服务实例的全部数据;

使用百分比运算(percent)规则,根据服务实例健康度(也就是 status 属性),为 true 计算全部服务实例的稳定程度。

百分比指标数据模型(PercentMetrics)的重要属性有如下四点。

总量(total):计算时间窗口中流式数据的总量。

匹配量(match):计算时间窗口中流式数据匹配到的数据总量。

百分比(percentage):根据匹配量和总量,计算出当前时间窗口的百分比。

时间窗口(timeBucket):当前计算的时间窗口。

数据库延迟采样数据

采样模型(TopN)通过一定的时间窗口,对具有一定规则的数据进行采样收集;并根据分布式追踪明细数据中的延迟字段窗口数据进行排序:耗时长的进行保存,耗时短的进行淘汰;最后经过一定的时间积累,计算出采样数据。

值得考虑的是,由于数据收集的客户端是分布式集群,所以明细数据会打到不同的收集节点上,所以收集节点的采样窗口会存在分布式带来的数据误差。也就是,悲观数据都打到一个节点上的这种情况,造成其他收集节点的采样数据不具备采样的数据意义。采样模型针对 DB 组件进行监控,用于发现慢查并进行优化。

主要的属性有以下四点。

延迟(latency):用于存储采样数据的延迟属性,根据实现的排序算法,在一定的时间窗口内得到延迟较高的采样数据。

访问 DB 的执行语句(statement):用户描述采样数据的访问数据库的语句信息,比如关系型数据库的 SQL 语句、访问内存数据库的操作命令。

链路 ID 属性:用于描述采样数据的分布式链路 ID,通过链路 ID 可以快速关联出分布式追踪的明细属性,从而进行分布式链路的慢查询诊断。

应用服务 ID(serviceId):用于存储采样数据的应用服务 ID,来进行对指标的采样,一旦采样到异常数据时,便可观测出采样对服务的影响。

小结与思考

今天,我带你回顾了 APM 的存储模型设计。以 SkyWalking 为例,收集端有三个重要的存储模型:明细数据、指标数据、采样数据。通过各个存储模型的典型示例,我们展开讲解了各个存储模型的每个字段的细节实现。

那么你在生产环境中,分析过那些数据存储模型的案例呢?欢迎在评论区写下你的思考,期待与你讨论。

-– ### 精选评论