本文首发自 微盟技术中心 微信公众平台~
一、前言背景
随着公司业务的发展,原有的 APM 系统逐渐显露出一些痛点。这些问题包括性能统计不尽如人意、分析维度单一、频繁的调用链丢失、告警配置不够灵活、告警规则较少等等,痛点+需求多达几十条,新的需求在原 APM 中改造已经无从下手。为了应对这些挑战,我们决定在今年初展开新的 APM 系统重构,启动了 APM-v3 版本的项目。
在本次重构项目中,我主要是负责的是指标与告警相关实现。所以本次分享主要是指标与告警相关的内容,指标分析是整个 APM 系统的两大核心之一 (另一个是调用链),指标对应的时序数据为统计大盘、性能图表、告警计算等提供了关键的数据支撑。
告警部分也是进行了重新实现,原 APM-2.0 告警相关能力是在 consumer 中实时进行计算得出的,程序中无法进行指标聚合,告警规则不能灵活配置,通知形式也较为单一, 并且没有认领和抑制的能力。故在 APM3.0 的设计中,我们希望能够接入Prometheus+AlertManage 的类似方案,来替代原来的告警能力。
经过方案选型的对比,我们最终选用了一个更好的方案组合: VictoriaMetrics + VMAlert。(组件介绍详见官方文档:https://docs.victoriametrics.com/)
二、架构设计
组件选型确定好了之后,梳理出指标服务整体架构实现方案:
1.前端应用打点数据上报到不同的消息队列(比如:WEB,小程序,nodejs,APP),在客户端上报时采用当前流行的 Opentemetry 的 trace 规范进行采集,一方面可以用于记录调用链,另一方面可进行解析统计形成我们的指标数据;
2.需要开发一个指标的 exporter 服务来消费队列数据,根据 APM 系统的配置的参数,计算并生成指标进行透出,另外需接入 VictoraMetrics 服务发现的能力;
3.然后由VictoriaMetrics进行间隔时间拉取, 并进行持久化存储。
4.最下面是告警流程设计。
三、开发设计
整体方案确定之后,就开始落实具体的开发设计了,大致分为以下几个步骤:
3.1 了解指标一些知识
1.我们先来了解一下指标拉取的数据示例, 通常以文本格式进行透出,内容包括指标名称、标签和数值,例如:
# HELP metric1 This is metric 1# TYPE metric1 countermetric1{label1="value1", label2="value2"} 123metric1{label1="value1", label2="value3"} 456
实际举例:
2.我们采用的是 HTTP 接口拉模式采集,可以看出对于指标透出的的内容不可以无限的大,否则会有超时等性能问题,所以要考虑对每批拉取的内容需要做一些约束条件,总结设计原则主要有以下几个思路:
- Label 值不允许使用无限量的字段, 如:用户的访问 IP 或用户的 OpenId,仅我国的 IP 数就多达3千多万,如果都作为了个 Label 值的话 ,这个拉取的数据包 就太大了;当然对于最终的使用者来说,查看统计时,一般都是看汇总后的结果,比如:我们可以将IP转换成城市进行透出指标,这样一来,数据量就会很小了
- 指标定义时可以指定多个 Label,这时多个 Label 值的组合数,也需要是一个比较可控的数量级。
- 控制指标数据拉取频率,由于每一次指标拉取都是完整的一组数据,所以数据采集的间隔也不能太频繁,否则会给指标存储带来非常大的压力;
- 最终我们采用每30s拉取1次,每次拉取的 metric 数据行数保持在20W以内。
3.上面理解了指标的使用要求,就需要梳理适合/不适合的场景。
- 由于存储的数据是汇总后的时序数据,不能进行太细的数据查询,条件只能使用设计好的label做统计条件;
- 对于非常细的统计场景,我们可以采用从ES里提供数据,因为这里面存储了我们的调用链信息;
- 指标查询的 PromQL 表达式配置告警是比较流行的做法,非常适合做最近几分钟内的异常检测告警,它提供的特别多的统计函数,可用于配置很丰富的告警规则 (MetricsQL 提供功能有:汇总功能,变换函数,标签操作函数 ,聚合函数)。
- 时序数据适合作为条件不多图表数据源,(条件仍然是设计好的那些 Label 维度),如:大盘的数据源,(时间段内发生的某事件次数,变化趋势,耗时分布,排名等)。
3.2 应用如何设计?
对于消息的处理流程设计图,如下:
3.2.1 指标设计
根据实际的需求场景规划要生成哪些维度的指标,我们目前主要分为以下几个维度:
a.页面维度:PV数,页面加载失败次数,慢页面次数(根据阈值计算),白屏次数(一是由前端认定,二是根据页面加载耗时阈值计算得出)。
- 各性能指标的耗时分布,如:启动耗时,路由切换耗时,首次渲染耗时,首屏渲染耗时,代码包下载耗时,JS 注入耗时,可交互时间等
b.接口维度:请求量,各状态码的数量,各业务错误码的数据,慢接口数量,响应耗时分布。
c.JS函数维度:慢执行次数,失败次数,执行耗时分布。
d.其它:代码异常类型,自定义异常打点,dns解析耗时,网络异常次数。
下面是抽出一些示例供大家参考(其中的预估量与最终透出的指标数限制有关)。
3.2.2 参数定义
a.应用类型,对于不同类型的应用所需要的指标维度也会有不同;
如:小程序,NODE服务,WEB应用,APP(规划中)
b.阈值定义 (主要用于以上指标提到的慢/白屏的认定)。
如:慢页面阈值,慢函数阈值,慢接口阈值,白屏阈值;这些阈值生效范围可以分为:指定应用,指定应用类型,全局生效。
3.2.3 程序设计(重心)
首先看一下当前已经实现的应用结构,主要处理逻辑为:
- 订阅队列数据 -> 消息代理类(进行数据分发) -> 应用类条件匹配 -> 指标类条件匹配 -> 形成指标;
以下对主要结构简单描述一下:
1、ApmConfigServer与MetricsConfigService
- 主要是监听管理中心配置变化信息的事件,以实时的动态更新指标服务内缓存的数据配置
- 指标配置信息主要有以下内容:(其中的condition还可以用来做告警消息关联日志详情的能力)
2、消息代理类: 为程序提供统一的订阅接口,使各应用类型的处理函数更容易进行消息订阅,将接收到的数据分发对应的Handler。
- 注意点: 消息匹配匹配条件都是灵活的配置(支持:等于,不等于,包含,不包含,正则匹配), 逐个解析配置再匹配消息,对于性能影响会比较大,我们针对这种场景,实现了一个生成静态匹配函数的方法,让海量数据的匹配开销做到很小。
3、ApmApp类 (对于创建的N多应用,为了避免数据集太大,需要合理的拆分,以利用分批拉取)
- 单一业务应用指标数据可以按应用隔离 (按应用分别创建实例,作为分批拉取的源目标)。
- 对于多业务的融合应用可以按应用+业务隔离(按应用+业务分别创建实例,作为分批拉取的源目标)。
- 每个实例都会对应一个获取 Metric 的端点 url,利用服务发现的机制,自动注册到 VictoriaMetrcs 中。
4、Metric类 (归属于ApmApp内的一个指标实例,可以创建多个,每个指标都是一个数据载体)
- 支持的统计维度有:COUNTER(计数),SUM(统计耗时),HISTOGRAM(耗时分布),SUMMARY(分位线耗时)注意点: 在实际场景中,发现有一些 label 的值,会非常多,比如有恶意扫描的许多不存在的接口 path,如果都记下来会导致透出的指标数据会特别多,会影响指标的正常拉取,使得我们不得不对 prom-client 进行包装,增加了 label 数的控制,并且还增强了更灵活的用法。
3.2.4 图表展示设计
查询指标可利用 VictoriaMetrics 的查询接口,常用有:Query(用来统计时间段内的汇总值),query_range(用于获取趋势图的数据) 。
1、可以将收集到的指标数据做成图表进行展示,比如:折线图、柱状图、饼图等,数据分布图等;
2、另外我们还利用指标数据设计了应用评分功能,让应用管理人员可以更直观地了解应用健康情况。
- 其中参与评分的条件有:JS错误率、请求错误率、慢请求率、首屏耗时、慢页面率、卡顿率、白屏率共7项指标;
- 各项评分满分为100分;评分=各项评分*权重 并相加,根据得分划分不同级别,以不同的颜色进行展示;
- 其中耗时相关的指标取值可以指定分位值进行计算,避免极端数据的影响。
3.2.5 告警设计
自定义告警是 APM 中一项很有必要的能力,规则配置要能支持界面简易化配置,便于使用者进行配置。而在性能问题发生后,告警触达非常重要。
- 告警的实现方案, 具体实现如下图所示:
(此处有个注意点是VmAlert的告警规则是从配置文件中读取的,而对于线上环境APM应用是不能直接访问VmAlert集群的,所以也就不能修改配置文件了,那该怎么办呢?查了文档发现VmAlert支持K8S环境下自定义CRD的接口(VmRule,CRD即自定义资源),调用接口后会自动将CRD的内容同步到VmAlert的配置文件里,从而实现了规则实时同步的功能。)
- 配置告警规则, 我们支持语义化和表达式两种配置方法,从而使告警规则的配置更加灵活,最后将配置生成的告警表达式同步到vmalert中。
常用的告警阈值条件类型有:异常数量、异常率、环比、同比等,比较完整的规则配置项可包含如下:
- 告警配置方式:1.语义化配置可用于较为简单的告警规则;2.表达式配置用于配置比较复杂的告警规则;
- 告警名称:便于识别,会展示到告警消息内 (能让接收者直观地清楚告警的类型);
- 生效环境:对于生产和测试环境 可以共用同一个规则;
- 规则条件:可选择指标名以及label并添加匹配条件;
- 时间间隔类型:持续时间,环比,昨日同比;
- 检查间隔:如:每分钟 / 每小时;
- 统计区间:数据区间,如:统计5分钟内的数据;
- 告警阈值:如:数值大于 1%;
- 告警级别:相当于严重等级,根据严重程度定义依次为:INFO,WARN,HIGH,DISASTER;
- 告警渠道(多选):短信,企微,电话,企微机器人 ,其中企微通道可以支持告警的认领与抑制;
- 告警接收人:当告警数据含子业务时,可针对子业务匹配相应告警接收人;
- 告警触达
<!---->
- 告警内容中需要有可以直接关联日志详情的链接,让告警接收人能方便里知道是具体的问题,这里有两个注意点:
- 一是我们日志明细查询的页面是查询ES的数据,而告警取的指标数据,前面指标配置的 condition 又能派上用场了;
- 二是企微的通知消息内容是有限制的,如果url太长会显示不下,可以选择用短链方式来实现;
- 利用内部统一的告警接口来触达;
- 打通了内部的员工账号,可直接将消息发送到多个渠道;
- 还支持告警的聚合,认领,抑制的相关能力;(在出现告警时,团队成员可以通过告警认领来主动标记自己来处理该告警,告警抑制可以暂时禁止特定的告警触发,以避免频繁告警产生的不必要的干扰。)
四、实践结果
4.1 数据展示
图表作为展示指标数据的工具,能够以直观的方式展现数据的变化趋势、异常情况,以及发现性能瓶颈和改进空间。
通过对指标数据进行持续的监控和分析,能够更好地优化应用的性能、稳定性和用户体验。
以下为实际的展示示例:
- APM图表展示 (概览页,掌握多个应用表现情况)
- APM图表展示 (页面性能)
- APM图表展示 (请求分布)
- 直接在grafana进行图表展示
4.2 告警配置以及触达效果
价值体现: 告警规则目前已创建了约几十条自定义规则,告警消息从一开始的一天几百条,经过应用优化或应用改造,到现在的每天几十条,使前端应用质量在逐步上升;
以下是实际的展示:
告警规则列表
告警消息内容,以及日志详情链接(示例图) 。
五、成果/优势
比较原有的 APM(应用性能管理)系统,以下列举了一些与指标相关的突出要点(其它调用链相关的不在这里描述):
1.聚合性能:
a.原APM:使用成本高,需要学习 Kibana 的聚合使用方法。
b.新APM:查询灵活,使用拖拉拽更容易,借用指标数据库的能力,提升了查询图表性能。
2.聚合能力:
a.原APM:聚合效率差,无法满足一些聚合类数据展示需求。
b.新APM:天生适合做聚合数据查询,可以满足大盘监控等需求。
3.多应用类型:
a.原APM:仅对应用名做了区分,没有根据应用类型适配展示。
b.新APM:支持按不同应用类型(如node,H5,APP,小程序等)适配页面的展示。
4.图表能力:
a.原APM:有限的特定图表。
b.新APM:接入指标规范,方便图表生成,支持第三方工具(如Grafana)。
5.告警维度:
a.原APM:仅支持针对需求定制告警。
b.新APM:支持用户自定义告警规则,并且告警支持多种告警通道,还支持认领与告警抑制。
新 APM 在性能、聚合、应用类型适配、图表能力和告警维度等方面有很大的改进。
六、项目接入APM
在新APM中,应用的接入也比较简单,对应用代码的侵入比较小,主要是有以下三步:
1.创建应用 (举例nodejs,另外还支持小程序,H5,WEB,APP)
a.主要填写:应用类型,应用负责人,默认告警通知人
b.创建完成后可得到上报数据的token
2.代码接入,默认会有一些通用数据,也支持应用自定义上报
a.在入口文件最顶端加入以下代码
-
-
-
-
import { init } from '@xxx/node-agent'; //目前仅内部可用global.tracer = init({ service : '你的应用名', token : '申请到的应用Key', ignorePath : ['/healthcheck'] // 忽略采集健康检查的路径});
3.然后可以在 APM 控制台查看默认图表了,以及自定义图表和配置告警规则。
七、未来规划
通过应用管理、指标配置、数据处理、指标透出、指标服务发现、告警规则与触发,以及告警操作等一系列环节的协同作用,我们能够构建一个高效的前端性能监控与告警体系。这个体系不仅有助于实时了解前端性能状况,还能够帮助我们迅速响应问题,提供卓越的用户体验和应用稳定性。通过持续优化性能,能够提升我们的业务竞争力,为用户创造更好的数字体验。 下面是我们目前规划的三个小目标:1.目前我们新的 APM3 已经变成了我们前端主力监控平台,有越来越多的应用进行接入,当前的消息处理量已达到每秒2W条,并且还在持续增长;2.区分存储周期更长的指标数据 (如:对比几个月的数据差异),可以对比长期的数据,来观测应用指标趋势。3.我们希望能将能力拓展到更广的适用范围,最好是可以将产品 SaaS 化,面向第三方开发者来接入。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。