在一个卡顿过程中,一般卡顿发生在某个函数的调用上,在这多个堆栈列表中,我们把每个堆栈都做一次hash处理后进行排重分析,有很大的几率会是dump到同一个堆栈hash,如下图:
我们对一个卡顿中多个堆栈进行统计,去重后找出最高重复次数的堆栈,发现堆栈C出现了3次,这次卡顿很有可能就是卡在堆栈3反映的函数调用上。由于采样频率不低,因此出现卡顿后一般都有不少的卡顿,如此可找出重复次数最高的堆栈,作为重点分析卡顿问题,从而进行修复。
举个实际上报数据例子,可以由下图看到,一个卡顿如序号3,在T1~T2时间段共收集到62个堆栈,我们发现大部分堆栈都是一样的,于是我们把堆栈hash后尝试去重,发现排重后只有2个堆栈,而其中某个堆栈重复了59次,我们可以重点关注和处理这个堆栈反映出的卡顿问题。
把一个卡顿抽离成一个关键的堆栈的思路,可以大大降低了数据量, 前面提及60W个堆栈就可以缩减为2W个堆栈(2000101=2W)。
按照这个方法,处理后的每个卡顿只剩下一个堆栈,进而每个卡顿都有唯一的标识(hash)。到此,我们还可以对卡顿进行聚类操作,进一步排重和缩小数据量。分类前对每个堆栈,根据业务的不同设置好过滤关键字,提取出感兴趣的代码行,去除其他冗余的系统函数后进行归类。目前主要有两种方式的分类:
1、按堆栈最外层分类,这种分类方法把同样入口的函数导致的卡顿收拢到一起,开发修复对应入口的函数来解决卡顿,然而这种方式有一定的风险,可能同样入口但最终调用不同的函数导致的卡顿则会被忽略;
2、按堆栈最内层分类,这种分类方法能收拢同样根源问题的卡顿,缺点就是可能忽略调用方可能有多个业务入口,会造成fix不全面。
当然,这两种方式的聚类,从一定程度上分类大量的卡顿,但不太好控制的是,究竟要取堆栈的多少层作为识别分类。层数越多,则聚类结果变多,分类更细,问题零碎;层数越少,则聚类结果变少,达不到分类的效果。这是一个权衡的过程,实际则按照一定的尝试效果后去划分层数,如微信iOS卡顿监控采用的策略是一级分类按最内层倒数2层分类,二级分类按最内层倒数4层。
对于我们产品,目前我们没有按层数最内或最外来划分,直接过滤出感兴趣的关键字的代码后直接分类。这样的分类效果下来数据量级在承受范围内,如之前的2W堆栈可聚类剩下大约2000个(视具体聚类结果)。同时,每天新上报的堆栈都跟历史数据对比聚合,只过滤出未重复的堆栈,更进一步地缩减上报堆栈的真正存储量。
卡顿监控系统的处理流程
用户上报
目前我们的策略是:
1、通过后台配置下发,灰度0.2%的用户量进行卡顿监控和上报;
2、如果用户反馈有卡顿问题,也可实时捞取卡顿日志来分析;
3、每天灰度的用户一个机器上报一次,上报后删除文件不影响存储空间。
后台解析
1、主要负责处理上报的卡顿文件,过滤、去重、分类、反解堆栈、入库等流程;
2、自动回归修复好的卡顿问题,读取tapd 卡顿bug单的修复结果,更新平台展示,计算修复好的卡顿问题,后续版本是否重新出现(修复不彻底)
平台展示
上报处理后的卡顿展示平台
主要展示卡顿处理后的数据:
1、以版本为维度展示卡顿问题列表,按照卡顿上报重复的次数降序列出;
2、归类后展示每个卡顿的关键耗时代码,也可查看全部堆栈内容;
3、支持操作卡顿记录,如搜索卡顿,提tapd单,标注已解决等;
4、展示每个版本的卡顿问题修复数据情况,版本分布,监控修复后是否重现等。
自动提单