讲师简介
张戎
机器学习研究员
社交网络运营部
我是一个做机器学习的人,目前接触运维的时间并不长,大约半年左右。
主要做社交网络的运维、监控和异常检测方面的工作。本文将按照下面四大块内容分享。
1. 时间序列异常检测
监控领域做运维,最基础的是时间序列的异常检测。如果是基于机器学习的智能运维,主要分三个场景:
第一步是发现问题,如果我们无法发现问题就无法定位问题、甚至解决问题。
既然提到发现问题,最主要的是发现一些时间序列的异常、日志的异常和设备的异常以及网络流量的异常。
第二步,发现问题之后自然要分析问题,发现问题并不足以解决问题。
分析完后,当然想自动或者半自动的智能化把问题解决掉,这就是我们最后要做的工作。
第三步,解决问题,包括扩容、调度甚至优化方面的工作。
怎样才能发现问题?首先要知道我们的问题究竟在哪儿,要知道时间序列到底代表什么。时间序列包括在线的用户量、主机CPU使用量和定时任务等。
上图有六个异常情况的例子,左上角的图是用户陡升了,可能做了一些活动。后面的图又下跌了,可能是异常变更导致的用户量下降。
做运维的都知道,时间序列异常检测是一个老大难的问题,因为以前的技术是使用一些人工巡检或者配阈值的方式监控时间序列。
首先,这样做有一定的风险在,包括制定阈值,可能告警电话比较多。
其次,海量的时间序列不是一条、两条甚至十条,可能是成千上万的而且种类还特别多。
还有,单独建立独立的模型是不现实的,配阈值也是不现实的,不管是配最大值、最小值或者方差是不能解决这个场景问题的。产品在未来可能发生变化或者用户量发生变化了,阈值可能并不能解决。
针对上述难点和挑战,提出一个问题来,如何找到通用的算法同时监控百万条曲线?
如何通过更加普适性的算法来进行时间序列异常的检测呢?首先看传统的方法,说到传统方法自然想到统计学的做法,通常用ARMA模型,要做这个公式模型就需要定阶,拟合这个模型后就可以做这一块工作了。
使用统计学的算法,会有一个前提假设条件,需要假设时间序列有自相适性,假设它是平稳或者弱平稳的状态。
对于运维的场景,比如说DAU或者在线用户量有一个周期性的特性,在某些场景下用这个算法是OK的。
但是,在很多场景下,是没有办法判断这个时间序列是否具有周期性,这时候就需要人工判断或者其他方法来做。
在这些假设条件下,上面的算法是有一定局限性的,并不能完全适用于所有的时间序列场景。
提到时间序列,有一些其他的想法。比如说时间序列是一维的时间序列。
在一维情况下未必能看得很清楚,如果提升到高维空间上,用高维空间的手段来看原始的时间序列是否存在某些问题。
这确实具有一定的优势,但是这样的方法也是聚在某一些具体场景下,同样存在一定的弊端,并不能适用于所有的时间序列场景。
跟很多搞AI的同学交流过,提到时间序列,他们第一反应就是文本或者语音的场景。文本和语音就是我跟你说一段话,你能生成文本或者语音,或者我说对联的上联,可以对出下联。
这比较适合语音或者文本的场景,因为有固定的模式在。
比如说“我吃苹果”,“我吃”后面肯定接某个物品。
时间序列在这个点陡升是正常的,或者有一些时间序列在这个点陡升是异常的,基于单条时间序列或者同类型的时间序列来做,RNN或者LSTM是有一定效果的,这在我们的场景上也有一些尝试。
既然传统的时间序列有各种各样的问题,我们就要想办理解决这些问题。
传统的统计算法是基于正态分布的假设,基于弱平稳型的假设和基于趋势性、周期性的假设。
我们能不能把这些问题去掉呢?比如说时间序列里面提到了异常假设,你提到的异常,对应的就是正常,异常和正常就对应了二分类的问题,标签等于零或者等于一。
在这种使用场景下就要转化为机器学习的问题,有一些是异常,有一些是正常。
其他的机器学习就是二分类的问题,这在我们这种情况下也有一定的弊端,就在于在业务平稳情况下大部分业务指标是正常的,即使是在系统里,点击率也不会太高,一般出现100个,别人点4个就差不多了,而且大部分面临着样本不均衡、不全面、稀少的问题。
如何解决这些问题?如果从人工巡检或者人工标注的方法,是没有精力和时间来标注这些异常样本,大部分时间花在找正常样本。我们就使用了无监督和有监督有机结合的方案。
为什么要使用无监督算法呢?寻找异常样本的时候,就相当于在海量时间序列里面捞一根针,这个成本很高。有没有一些方法,比如说通过筛子的方法,把从大海里面捞一根针变成从游泳池里面捞一根针呢?用无监督或者统计判别的方法,可以把范围大大的缩小。
使用这些技巧缩小,把算法过滤到大量的正态样本,剩下的就是疑似异常。人工标注的人力成本会在这个地方得到体现,人工标注样本后,再通过有监督学习算法对这些样本进行训练,从而提升系统的准确率和召回率。
我这边是用了一个不太成熟的解决方法,就是无监督和有监督的技巧。
这张图是织云monitor时间序列异常检测的技术框架。离线训练数据模块是数据存储,包括样本的标注、提取,把模型训练好之后,并没有做完这个事情,这只是离线评测或者评估。
剩下的要做在线的预测,要把离线训练模型加载到线上,在时间序列上需要读取这份数据。我们的算法没有办法一次性把这个调到最好,就需要不断迭代的过程。
既然需要迭代,就要切流量分成两块,同时跑两个算法,哪个算法高效就把哪个算法推到主流量上,通过ABTest模块进行技术更新和迭代。整个技术框架大概就是这样的,细节将在下面会详细阐述一下。
第一层算法是统计判别和无监督的算法,都是在无监督算法的范畴里面。
左上角的时间序列化,用3-sigma原理,就是用S减均值,方差大于3倍,用这个可以优化出来,同样可以由这个无监督的框架。3-sigma有可以解决的和不可以解决的点,存在一定的弊端。
比如左下角的图用3-sigma是没有办法监督出来,因为没有超过昨天或者历史的最大值,我们就需要其他技巧来解决这个问题。
谈到其他技巧,需要讲一下无监督的算法。无监督的算法是没有标注的过程,我们用“孤立森林”或者是SVM、RNN来解决问题。用孤立森林,它的目的是从多维数据空间中寻找异常点。
SVM是建立超平面来寻找异常点。无监督算法也有一定的弊端,比如说左上角这幅图,可以明显找到蓝色的地方是异常,左下角的图就是异常任务。
无监督算法也有能解决的问题和不能解决的问题。其实我们很难保证每一次无监督输出的异常都是真的异常。左上角的图就标注为异常。左下角的图,由于每天或者每周都是这样,我们就标注为正常,后面会进行人工标注。
孤立森林是一个无监督学习的算法,由南京大学教授提出的。这里适用于连续数量的异常检测,病人使用多棵树形成森林来判断是否异常。
比如右上角这幅图,中间的点认为是正常点,外围的是异常点。
我们用孤立森林可以很轻松的分离开,认为这些是异常点。而后端就很难分开,我们认为后端是很难被发现的异常。
这就是无监督学习算法,这一块也有一些应用场景和使用的地方。
无监督学习算法,远远不只是孤立森林,还有一些周边的算法,如SVM。
SVM是作为线性的方法,但是使用了超平面的思想。就是把一个点进行提升或者平面加固,用超平面的思想把点和点之间区分开。
举个例子,比如说桌面上有很多苹果、梨、乒乓球和西瓜,用相同的力度各自拍一下,由于苹果、梨、乒乓球和西瓜的重量不一样,弹出来的高度也不一样,可以利用弹出来的高度使用一个平面区分开,SVM就是用了这样一个思想。
右边这副图里,这个圆或者这些红点,很难找到一个平面把它区分开。平面中只能找到圆形的框架,高维空间或者特征空间里面可以容易的找到一个高维平面区分开,这是一个无监督的思想,通过它以把找出异常点。
RNN是复制的神经网络。右边这副图是左边输入,右边是输出。训练这个神经网络,左边的输入和右边的输出是一样,中间的节点远小于左边和右边的节点个数。比如说左边的输出等于右边的输出,中间做了一个信息压缩的过程,提炼了关键的特征。
对于一些正常点和大部分点,输入和输出的误差不会变得特别大,但是对于一些异常点来说,它的特征跟正常点有明显区别。
使用这个训练好的神经网络,输入和输出的误差会相对偏大一点。在相对偏大的过程中,认为误差偏大的这些点就是我们要寻找的异常点。
在这个过程中要做特征工程的工作,判断一些疑似异常。
无监督算法也并不能解决所有问题。比如中下图,用无监督算法,蓝色的点都会认为异常点,因为用拟合都认为它肯定是高异常。基于周期性或者图像来看可能是无异常的。
我们把人工标注过的异常或者疑似异常样本进行训练,通过决策树或者RF、GBDT的模型,得到我们想要的值,然后再通过这个样本就可以得到训练和预测的过程。
时间序列是可以做特征的。时间序列的特征可以大概分为三类:
时间序列的统计特征
时间序列的拟合特征
时间序列的分类特征,如形状或走势的分类。
时间序列的统计特征。右边这幅图是一个时间序列,大家就算没有做过机器学习也知道最大值、最小值等等指标,也可以写出来,这些公式我们之前都有接触过。
讲一下时间序列的拟合特征,这里面使用了子的时间序列模型,去提炼一些特征,可以使用带权重的移动平均算法或者EWMA等等算法。
左边的图是时间序列,红色的点是想要提取的时间序列特征的片段。
我们现在进行平均的过程,通过原始的时间序列,可以得到光滑后的时间序列,自然就有一个光滑值,光滑值可以作为我们的一个特征。
用EWMA或者Double EWMA算法,把时间序列进行平滑操作,平滑后的值可以作为特征的工具。
对于这些值,基于海量时间序列很难通过一种模型,如EWMA。但是,可以把时间序列输出的模型作为一个特征,通过这个特征作为一个集成学习的思想,用孤立森林的模型对这些特征进行学习,相当于把很多个时间序列的模型融合到最终的一个大的模型里面,这样就能解决很大一部分问题。
如此的话,这个模型具有更好的通用性,不仅可以检测一些DAU或者再现用户量,同样也可以检测一些主机信息或者定时任务的一些指标。这就是时间序列提取特征的过程,使用了集成学习的思想。
除了时间序列提取拟合特征,还可以得到分类特征。右边这些图是很多时间序列,上面这些图是昨天放量型的,开始有走势,今天显示比较平稳。
第二部分是毛刺型的。
第三部分是平稳走势型的。我们可以提取其他值的特征,把序列简单的大概分成几类。通过这一块,我们不仅做了聚类,也做了分类。这个时间序列,通过走势就可以简单的进行分类的操作。
AIOps智能监控,除了准确率、机器学习框架还有召回率。织云只能监控的准确率达90%。通过计算召回率也得到了相应比较高的值达70%。
除了前面所提到的基于历史数据的聚类和关联分析、相似判断分析与提取,我们现在做的是时间序列的异常检测和联动分析框架,包括时间序列的未来趋势预测。
我们现在基于历史数据,学习历史数据,预测未来数据,这是时间序列相关技术的整体规划。
2. 智能多维下钻分析
既然发现完问题,自然要有分析问题的过程。这幅图就是一个时间序列,展示成功量或者播放成功率,通过业务埋点或者监控系统,可以汇聚到相关数据,统计的维度有IOS、安卓,客户端版本,成功量、失败量。
通过人工巡检或者人工配置阈值的方式判断成功率是否下跌,由于业务变化,确实不一样,以前异常不代表未来也异常。
第二步是人工查找可疑维度,查看成功率和成功数,看可疑的维度。
人的精力毕竟有限,每次故障都人力分析,没有这么多人力,而且基本上先分析单个维度,再分析多个维度,随着维度的增加,有一个组合是二元次方,根本就不在认得搜索能力范围。
因此我们必须引入机器学习或者其他的思想来解决这些的问题。
基于机器学习的根因分析分两层:
第一步,发现问题。数据存储或者时间序列的异常等等;
第二步,分析问题。我们自然要拉取正负样本,以一个工程来分析根因。
左边的发现问题相当于单点应用,是异常检测的模型。右边的分析问题是另外一个学界,是分析或者定位故障的过程。
这两个过程串联起来就是白皮书里面写的串联应用,我们也在做这一块工作,把两个模块打通到第一层上,是一个发现问题、定位问题、分析问题的过程。
提到根因分析的机器学习模型,我们也有其他想法,可以把刚才说的JSD或者其他框架提炼出来。
我们通过一些调研,既然提到根因分析,就要输出一个异常的定位或者解释。
首先这个模型必须要有解释性,不可能用一个深度学习或者深度神经网络,这个虽好,但是没有解释性。
它要求的结果是输出一个规则或者输出一个解释。比如说裴教授论文里面写了,用“决策树”的技巧,可以用减支的方案来做。这个模型的性质是解释性好,可以进行离线分析。
基于机器学习的决策树的模型的大概想法和框架大概如上图所示。成功率下跌了可以作为异常样本,成功率保持稳定的是正常样本。
通过一定的比例或者特征工程可以得到很多特征,以这些特征可以进一步得到有监督的模型学习,最后输出一个规则体或者疑似异常的过程。
基于机器学习的模型,首先我们要选择一些样本,并且得到相应的特征,使用这样一棵决策树。建树时间比较长,也需要一定的训练时间,随着业务的迁移,当前的这棵决策树现在训练好了,半个月后可能就不太适用了,因此我们进行了其他方案的调研。
找到一些关键节点,然后通过关键节点回溯到根节点,自然就会打出根因,我们进行冗余规则的合并,最后可以输出最终的异常。
最终的异常的解释就是我们刚刚所说的发现问题,也就是发现异常,这就是最大可容的问题。决策树的建树规模会很大,特征工程也会很复杂,对于这一块我们也尝试了其他的方案。
根因分析的一般流程是数据处理、剪枝操作、维度组合。
我们要做的是移除正常维度,聚焦异常维度。对决策树等模型选择合适的场景,就需要对决策树的理念和理论要有更加细致的了解。
决策树正如我们刚刚所说的,最终会用到熵和Gini系数来做。
左边这副图男女分布情况,如果对这款APP来说,男性下载量大,女性下载量小,是不是可以得出结论这款APP男性受欢迎度大,女性受欢迎度小。
比如说音乐,男女喜好比例并不是1:1,如果男女分布本来不均衡,你从得到的下载量判断出这个APP是否受男女欢迎。
中间这幅图是APP1的下载量,从APP1的下载量和男女分布情况来看,几乎保持一致,但是APP2的下载量差异比较大。
我们本质上是希望做一个概率之间的距离,其实点和点之间是可以描述距离的,同样概率和概率分布之间也有距离。
概率之间的距离可以用KL散度来做,KL散度具有不对称性。
概率分布之间的距离可以用Jensen Shannon Entropy对称模型来做。
比如说左边的图和中间的图,它们两个概率分布几乎为零,可得出APP1的下载量是男女同等受欢迎的。
左边这幅图和右边这幅图APP下载量和男女分布情况差异很大,可得出APP2可能更受某一类人群的欢迎。
提到根因分析的机器学习模型,我们也有其他想法,可以把刚才说的JSE或者其他框架提炼出来。
要计算概率分布,首先要考虑量的问题,比如说某个人群基数很少或者在某个时间点人群数量很少,在这种情况下,总量或者其他波动很大,有可能一个用户没有登录上成功率就直接为零了。
只使用概率分布不能解决所有问题,除了总量或者成功量,还要考虑一些总量或者贡献值的指标。因此我们使用了微软提出的JSD的方案,不仅要考虑概率分布,还要考虑量。
比如说失败率陡升或者成功率下跌了,几个量交叉在一块,如果都发生异常,我们才认为是异常。如果只是概率分布距离发生了异常,做的量小,这个差距还是很大的。
3. 告警收敛根源分析
时间序列异常检测是发现问题,发现问题串联起来就是分析问题。其实报警根源分析也是相当于串联应用的场景。
在海量的时间序列告警情况下,哪一些属于异常?
有一些可能是网络抖动,有一些是机房故障,有一些是程序异常或者有一些日志变更,导致了我们时间序列异常,这时候可以通过报警根源来分析哪些发生异常。
这是一个串联应用场景,它的挑战难度比时间序列还要大。时间序列首先要告警相对准,不可能前面时间序列告警准确率只有20%,后面希望做到100%,这是不可能的。
首先,我们要解决历史包袱,如误告邮件多、误告消息多或者告警电话多等等。
比如说搞活动,海量的时间序列可能也会发现走势跟之前不一样,我们能否通过根本的原因来发现它是搞活动还是程序发布导致的异常,这是我们当前在想的问题。
织云ROOT根源分析,我们通过抓包来得到调用关系,通过机器学习的思想来发现哪些地方是我们最想要的根因。
通过拓扑调研分析来得到关键节点,这些关键节点就是我们重点要分析的东西。关键节点间的调用拓扑关系可以通过社交网络技术来实现。
告警收敛我们正在做,不管某个程序是否发布了,在这段时间有两条时间序列经常一起发现异常,其实就有某种关联关系。
哪些告警是经常一起告警出来的,通过提炼告警规则得到一个关系,然后排查告警的时间差。
比如说A发生告警,随后B发生告警的概率可以轻易的算出来,只要能积累相应的数据和报警数据准。告警收敛可以等待队列,最后把告警发送出来。通过这个可以做到告警压缩和收敛。
通过一些检测的方式得到一个0和的1序列,其中0是异常,1是正常。经过KPI技术判断这两条告警序列是否一致,告警的时候一块告警,不告警的时候一块不告警。通过KPI的统计方法,来判断这两条告警序列的相似性。
如果相似性高,我们认为这两条序列是相关的。如果告警的相关性很低,我们认为是不相关的。基于告警的划分,我们也可以做到告警收敛和压缩。
这是织云ROOT的根源分析的过程图。比如收取到一个模块ID,把告警序列拉取出来,通过调研关系进行根源分析。这里面有一个是主调告警,有一个是被调告警,这就是根源和异常的过程。
4. AIOPS的未来规划
织云AIOPS的规划大概是三类:
首先是发现问题,比如时间序列的异常问题检测,包括聚类、分类、局部相似度、整体相似度和关键部分提取。
根因分析,除了多维下钻分析,我们还会做故障传播链分析,这个正在进行中。
最终是要解决问题。解决问题就是智能决策,包括扩容、决策、优化、调度的框架。
说明:本文根据腾讯 张戎博士于 GOPS · 深圳站的分享整理而成。