- AIOps路线规划
- 异常检测
- 平台化建设
- 故障管理智能化
AIOps即智能运维,是 Gartner 在2016年提出的概念。最初的定义是Algorithm IT Operations,指通过机器学习,数据仓库以及大数据等技术手段,将人工智能应用于运维领域,基于运维产生的数据(日志,监控,应用等)进行分析决策,得出最佳的运维策略,并随着技术的成熟,最终走向无人化运维。
一、AIOps路线规划
1、AIOps能力阶段
罗马非一日建成,根据之前发布的企业级AIOps实施白皮书指出AIOps的发展主要有以下的五个阶段,这个在我们目前的实践过程也确实得到了验证。
- 开始尝试应用AI能力,还无较为成熟的单点应用。
- 具备单场景的AI运维能力,可以初步形成供内部使用的学件。
- 有由多个单场景AI运维模块串联起来的流程化AI运维能力,可以对外提供可靠的运维AI学件。
- 主要运维场景均已实现流程化免干预AI运维能力,可以对外提供供可靠的AIOps服务。
- 有核心中枢AI,可以在成本、质量、效率间从容调整,达到业务不同生命周期对三个方面不同的指标要求,可实现多目标下的最优或按需最优。
网易游戏智能运维团队于2018年开始进行算法研究以及具体落地场景的选择,后续在在线人数、异常检测、日志异常检测方面尝试单点应用突破,并取得显著的成效。目前通过串联各维度运维信息和报警信息来进村后故障发现和故障自愈的目的,达到多个单场景AI运维模块串联的流程化AI运维能力。
这里的学件指的是AI运维组件,由南京大学周志华老师原创,是指模型+规约,具有可重用、可演进、可了解的特性。
AIOps阶段
2、人员结构
相较于Devops,AIOps的人员结构肯定也发生了一些变化,最显著的变化就是加入了算法工程师这个角色。有的团队会倾向于叫算法开发研发工程师,也就是既具备算法的能力也具备平台开发能力的工程师。当然如果一个算法工程师能够具备良好的工程能力,这个对于整体的团队发展肯定是有正向影响的。但很抱歉,一个团队里要求每个算法工程师都具备良好的工程能力其实是比较困难的,特别的是在招人的时候会发现,算法和工程还是有一定割裂的。
所以我们团队的配置,更多是下面这三个角色:运维工程师,也可以说是我们的用户,他们负责向算法工程师提供具体的业务场景及需求,挖掘潜在的智能化场景,同时向平台研发工程提供平台开发的场景需求。另外就是平台研发工程师与算法工程师,一个主要负责工程化以及平台化的建设,懂一点算法,但其主要职责更多偏向工程开发。而算法工程师则注重算法对应业务的调研,开发以及调优,这种结构也是为做到术业有专攻的目的。
实际合作下来,这种合作方式极大地提升了业务开发的效率,但也存在一定技术盲区的问题。
3、业务领域
1)时间序列异常检测
时间序列数据是按时间顺序排列的、随时间变化且相互关联的数据序列。由于运维场景的特殊性,运维数据天生便与时间序列密切相关。AIOps提供的时间序列智能分析的能力,即是通过研究历史数据的变化趋势和内在性质,来实现时间序列预测,异常数据监测等无需人工参与的智能分析功能。
2)故障定位与根因分析
随着微服务的发展,业务组网愈加复杂,问题的定界定位分析变得尤为困难。故障的识别和诊断是运维场景中智能分析的核心部分。AIOps提供的故障识别和根因定位能力,即是通过数据挖掘的手段,综合故障数据和人工经验自动提取故障特征,自动定位故障。
3)文本处理分析
文本的处理有广阔的空间。AIOps提供了范围极广的文本处理分析的能力,涵盖信息提取,语义分析,智能搜索,对话系统等领域,提供可直接应用于产品策略的NLP技术能力。
4)聚类与相似性分析
将物理或抽象对象的集合分成由类似的对象组成的多个类的过程被称为聚类。聚类即是根据某种相似性进行抽象的过程。AIOps提供的聚类和相似性分析服务,能够使用有监督或无监督算法,结合统计学特征,对给定格式的数据进行相似性聚类,从而极大的降低数据的识别和处理成本。
二、异常检测
1、问题
传统的静态阈值目前已经难以适配多变的业务场景,阈值过高会遗漏告警,阈值过低会引发告警风暴。时间序列指标的异常检测,不同于传统的静态阈值,用户不需要自己手动配置。AIOps通过机器学习算法结合人工标注结果,实现自动学习阈值,自动调节参数,提高告警的精确度和召回率。异常检测能够更适配业务多样化的需求,覆盖更多的异常类型。
2、适用场景
1)异常阈值难以定义
- 难以明确定义正常、异常数据,没有明显的阈值界限。
- 在不同的时间段有不同的阈值。
- 有一些数据的异常突变没有达到预定义的阈值。
- 需要识别的异常是与历史数据的某种表现模式的异常,无法设置阈值来检测。
2)人工配置成本高
- 不同的曲线配置不同的阈值,曲线很多的情况下人工配置成本很高。
- 随着业务变化,预定义的阈值需要随之变化,运维成本高。
- 本身含有噪声,难以区分噪声和异常数据,需要花费大量人力检测。
对于异常检测,其实网上很多文档或者书籍都给出了一些常用的算法或者工具,我们这方面相应用的也是这些算法或工具,当然了也做了许多相应的算法优化和调整,我这里给出一些我们团队的在这方面的思考跟策略。
在模型是线上我们选择统计+规则的无监督方案,主要优势在于:
- 无监督无数据标注成本
- 统计+规则的方式可解释性强
- 模型预测时延较低
- 受曲线时间粒度的影响较小
3)毛刺异常
毛刺异常表现为在某个时刻,KPI曲线上突然出现的一个不具有周期性的局部极大值毛刺。如果仅用KPI的幅值进行阈值判断,很多时候无法准确找到异常值,因为KPI值本身也可能存在一定的趋势。使用一阶差分可以有效去除趋势项,使得异常能够暴露出来。此外,SR算法对于此类的异常也具有较好的检测效果。
4)突升突降异常
突升突降异常表现为当KPI曲线上出现异常突升或突降,并未马上恢复,KPI的值持续保持在该异常值附近的异常。这是一种持续异常,很多业务如在线人数、CPU使用率等都非常关注这类的异常。识别此类的异常可通过异常点两端窗口内的均值偏移来识别。
但是由于KPI本身具有趋势和周期,正常点两端窗口也存在均值偏移。此时,可以使用STL对时间序列进行分解,然后对残差部分进行均值偏移的计算,即可降低趋势项和季节项带来的误报。另外,大毛刺也会产生均值偏移,容易产生误报。因此在计算两端窗口均值前,用esd检验来进行异常值的去除,这样可以去除大毛刺对均值的影响,减少模型的误报。
5)频率变化异常
频率异常表现为持续的毛刺异常,此时曲线的震荡加大,也属于一种持续异常。虽然此类曲线比较少见,但是也是业务比较关心的异常类型。
可以使用窗口内一阶差分异常计数值来进行判定。
3、异常判定方法
在设计出各类检测模型后,需要根据模型的输出进行异常判定,从而确定当前点是否为异常。针对瞬时异常和持续异常,需要使用不同的方法进行异常判定。
1)分布法
根据对数据分布的假设,设定阈值,适用于瞬时异常的判定。我们使用3sigma和箱型图来判定瞬时异常,经测试,在大部分曲线上具有较鲁棒的判定结果。
2)业务计数阈值法
根据业务需求,设定计数阈值,适用于持续异常的判定。我们为持续异常设定计数阈值,如果异常计数超过该阈值的时候,就进行报警。如鲁棒回归时统计实际曲线和预测曲线差值异常的计数;如窗口内一阶差分异常的计数等均可直接通过计数阈值来判断。
此外,为了融合不同模型的输出,得到更鲁棒的判定结果,可以把分布法、业务计数阈值法通过线性转换转化为0-1之间的分数,此时模型融合可以通过分数加权的方式得到,融合分数超过0.5的即为异常,可以在不同的曲线中保持较优的异常判定效果,也具有较强的鲁棒性。
三、平台化建设
AIOps本身也是一个迭代式的开发模式,在平台化期间我们也遇到了一些问题。首先是算法和工程边界比较模糊,算法工程师希望能够专注算法的开发和调优,不想花过多的时间在工程上。还有就是算法包跟工程强耦合,算法的每次调优和参数变化都需要工程配合发版。
我们希望算法,工程能够更好的解耦,既能满足算法快速迭代的的需求,也能满足工程平台开发稳定性的要求。
另外我们还发现AIOps使用到的数据可能是多种多样的,就异常检测一个场景来说,基础指标数据、日志数据、模板数据都不同。
扩展到故障定位可能还需要用到配置相关的数据,比如业务拓扑网络拓扑的CMDB数据,甚至再结合到异常事件,变更事件这一类事件信息数据等等。
1、系统架构设计
基于以上的问题和目标,我们设计如图所示的五层系统架构,其核心目标是可按需加载不同的算法,编排不同的检测流程,在保障高可用的同时,达到提供多种服务类型但是又能统一管理,各个业务之间甚至进程之间隔离,通过统一的平台进行调度,为了节省资源,对算力进行动态调整,保证整个服务的运行效率。
1)数据接入层
最下面的数据接入层负责对各类监控指标,系统日志,业务日志以及业务指标进行实时的采集。对于系统及业务指标,可以通过我们监控团队自主开发的agent进行数据收集,一般在各服务器初始化的时候就会自动安装配置。
2)数据层
由上面数据接入层采集到的数据会写入到HDFS进行持久,同时该层也会负责将采集到的数据进行预处理、ETL、聚合等等。为了提高性能和可用性,指标数据会根据冷热数据的区别分别存储在TSDB和Redis中,而我们的检测用到的历史数据就是从这里面获取的。
3)服务层
这里主要通过离线的方式对模型进行模型训练,将训练完成的模型上传到S3上进行存储,当模型迭代或者算法策略变更时,算法工程师可以自主的完成全链路的开发测试,不需要平台工程师的接入。由于模型是从平台框架中抽离出来出来的,可以进行独立的配置和管理,更进一步的降低了算法和工程的耦合。另外当有新的业务场景接入的时候,算法和工程师可以通过约定接口的方式,各自独立进行代码开发,各自上线。
4)应用层
区别于网络服务的应用层,这里更多是指各个不同的saas平台的功能性应用,基础运维负责反应真是的指标波动情况,通过数据层对数据进行聚合,目前我们监控团队已经做到了秒级监控的数据展示。而AIOps平台也是嵌入在这一层里面的,其主要的功能是通过实时流,任务调度等方式,通过调用相应的模型对数据进行各种算法检测。
5)展示层
用于检测结果展示,已单个事件或数据图谱形式展示。
2、检测流程设计
这里主要介绍一下应用层的检测平台内部实现思路,整体的一个数据流向如这张图所示。用户会在我们的运维门户网站上建立相应的检测任务,并将配置同步到flink规则数据库中进行保存,这个时候agent会采集相应的指标数据发送到flink里进行预处理,flink根据规则数据库中配置对数据进行前置的过滤与预处理。
处理后的数据还会经过一个算法编排的模块,这个模块主要是根据之前用户的配置以及我们预设的匹配规则,为检测的数据增加上一些编排,任务,策略相关的信息,这类信息决定了算法所用到的模型,历史数据,特征等信息。随后根据这些信息,动态的加载模型进行调用并输出结果。
算法模型作为算法的抽象,可通过注册上传的方式将模型上传至S3种进行存储,注册完成后的算法模型会相应的生成编排,训练的组件。平台与组件之间,通过定义算法的唯一标识,接口,输入输出类进行交互。平台调度引擎会根据上述配置,动态的加载相应的算法模型进行检测调度。
具体检测架构实现思路如图所示,首先算法模型作为一个可插拔的算法包存在服务当中,每个算法包拥有独立的线程资源,利用python的类加载方式可根据需要进行下载和更新,实现算法模型的热部署。
框架本身相当于一个调度管理工具,负责加载不同版本的算法,执行算法路由以及策略计算。同时我们设计一套相关的编排调度协议,将具体的参数配置及编排模式开放给工程师自己进行定义,进一步解耦了算法和工程,业务和平台之间的关联。
如一些业务场景往往需要用到历史数据,历史数据的获取跟预处理其实算法工程师并不在意,这类的操作一般都交给平台工程师来处理。
我们在平台内部将历史数据获取的逻辑进行了抽象化,具体业务数据的获取和存储由平台工程师根据业务需要编写相应的输入输出,算法调用模块通过协议获取一些关键的参数与配置,内部自动调用这些具体的类和方法获取数据,并将数据传递给模型进行检测。
其实在对历史数据获取和处理的过程中,历史数据的抽取往往会成为瓶颈,比如算法可能需要7~8天的历史数据作为输入,那随着检测数量的增加,这对于TSDB是有巨大压力的,再加上计算历史特征可能需要的输入量不尽相同,冷热数据,读写分离都能以解决,对我们平台内部也维护了一套历史数据的内存存储,通过pipeline加数据压缩的方式进行历史数据缓存。同时将部分的计算特征通过内存进行存储,减少实时计算模块的压力。
这里是我们抽象化类图的实现方式,基础类里面提供了存储,编排,更新等基本操作,平台开发工程师根据业务场景自行定义数据以来,通过组合这些独立的功能,从而满足各种不同的业务需求。
在用户体验方面我也做出了一定的改变,首先是异常标注的方式,我看许多的平台都是以事件和同环比的形式展示出来,因为我们本来就有了一个报警平台兄弟系统,而且实际使用下来发现这种单个事件同环比的形式很容易给用户造成误解,所以我们用像grafna的大图形式进行异常的展示和标注。
另外其实用户反馈和标注是很重要的,很大程度上决定了模型的调优,提升算法的准确性,有的时候用户其实挺懒的,往往疏忽了标注这件事,我们通过内部的消息工具popo,直接将检测结果与标注链接发送给用户,培养用户标注的好习惯。
四、故障管理智能化
随着游戏及系统架构的日渐复杂,运维人员收到的报警信息也变得多种多样,在面对故障时,纷杂的报警信息令运维人员一时难以理清逻辑,甚至顾此失彼,无法在第一时间解决最核心的问题。在与我们程序与SRE交流过程中,我们发现他们面对故障主要存在以下痛点:
- 游戏架构日渐复杂,出现故障后排查链路比较长。
- 故障产生后,往往会引发多个报警,但是这些报警比较零散,没有按照一定的规则去分类和可视化。导致排查过程中需要人工先去梳理,和过滤报警。
- 目前故障定位依赖人工经验,这些经验难以被复用。
众所周知,业务指标是最直观反应故障情况的手段,日志记录是记录应用程序运行状态的重要工具。我们希望在保留细节的同时,将上述泛化的报警信息通过聚类的方式进行概括,使得在报警发出后,结合指标、日志、tracing、变更事件等信息,通过故障传播链关联起来,找到最有可能造成故障的原因。
业务指标是整个故障定位的触发源,我们选择了游戏SLO中的重要指标,按照群组的维度进行分类。由于SLO业务指标毛刺较多,直接用普通的毛刺无监督模型会产生较多的误报,只有异常持续抬升或者下降一段时间,才能被认为是异常,因此SLO异常检测模型使用抬升异常检测。
抬升异常检测主要由两个模型构成,一个是均值偏移模型,另一个是预测均偏移模型,最终的结果会融合两个模型的输入输出。
1)均值偏移模型
- 计算左右两侧给定数量的均值差。
- 当差值大于或者小于一定阈值时,则认为出现抬升异常。
2)均值预测偏移模型
- 先用左侧、右侧给定数量的点分别进行线性回归,预测右、左两侧给定数量的点的值。
- 再将其与右、左两侧真实值作差。
- 对这些差值求均值。
- 当该均值大于或小于一定阈值时,则认为出现抬升异常。
在业务指标异常后,启动故障定位,开始机器指标异常检测及排序。通过异常分数排序的方式得出最有可能的异常根因。
- 当业务指标出现异常的时候,在当前时间点往前推的20min的区间内对所有指标进行毛刺异常检测,计算异常检测分数。
- 异常检测分数乘上时间衰减系数,作为根因分数,即越早发生的异常越有可能是根因。
- 输出20min内根因分数的最大值作为该指标的根因分数,然后在机器名范围内进行排序,在仅考虑单根因的前提下,异常最多的机器作为根因机器,其中指标的异常按照根因分数排序输出指标根因列表。
在对机器指标进行异常根因排序的同时,我们还会扫描相关saas的机器指标与报警信息,最终结合日志异常检测及分类,将根因结果展示给用户。
Q&A
Q1: 上智能化运维前期规划上有什么好的方向及规划建议?
A1:首先智能运维不是一个一蹴而就的过程,是作为一个长期演进的系统存在,其根基还是运维自动化,数据收集,分析,监控等基础运维工具。在前期规划上需要解决的问题包括海量数据的存储,分析与处理,数据仓库的搭建,基础监控的实践经验等。好的数据往往比模型更具有价值。在完成上述基础建设后,可与具体业务人员了解其最关注的SLO,通过这方面进行异常检测建设。在模型选择方面,尽管有监督的标注成本会很高,但有监督模型比无监督模型更加容易贴近业务需求,在后期更新迭代上占有绝对优势。
Q2:AIOps基础肯定是大量的历史监控数据,数据的收集规则与建模规则你们怎么设计?
A2:目前我们已基本完全采用了prometheus的接入方式,并在此基础上建设了数据采集中心。其主要收集规则基于收集器与适配器模式,用户通过收集器进行数据上传,适配器对数据进行重新组装直接发送到相应的消息队列中等待存储。数据模型统一使用json标识,数据格式则采用prometheus的数据格式。
Q3:日志的采集规则,您能讲讲吗?现在日志检测的思路的是怎样的?
A3:用户通过我们自定义的client定义相关日志指标,自行采集数据,sdk单独开启进程定期读取内存中数据,组装成日志格式,由我们这边的日志团队进行数据收集。具体数据格式如上一个问题。对于容器日志收集的方法,一般是通过以下几种方法:
- 容器内收集日志:容器进程自行写出;agent收集。
- 容器外部收集:docker logs api及docker log-dr;日志收集agent;挂载volumes;自行开发agent。
我们目前日异常检测算法主要依赖日志智能分类算法,需要在获得日志实时分类模板后,根据各模板的日志量的历史数据使用3sigma与箱线图进行异常判定,从而发现其中的异常模式,并将对应的异常通过告警发送给用户。
Q4:做告警收敛,都有哪些思路,哪些效果比较好?
A4:告警收敛的方式主要有几种:
- 基于预设好的规则进行收敛。比如A、B报警来自于相同机器/模块,就将AB收敛合并。
- 基于报警时间/报警次数的收敛。如将5min内报警合并发送。
以上两种是策略型,可以将部分的报警进行收敛,但不能得到报警之间的关联性。
- 基于拓扑收敛。根据拓扑结构将报警进行关联,达到收敛效果。 可以得到报警之间的关联性,利于排障。但一般比较难获取到拓扑。
- 基于关联规则挖掘的收敛。根据历史报警信息,挖掘出频繁同步出现报警规则,进行合并。 可以得到报警之间的关联性,但依旧没有形成故障现场,有一定的排障效果,并不依赖于拓扑。
- 构建报警知识图谱,进行收敛。理想化方式,效果最佳。但需要拓扑和历史数据积累,和专家知识,较难实现。
Q5:基于互联网电商应用监控的动态阈值算法怎么选型?
A5:主要可分为有监督选型和无监督选型:
- 有监督异常检测的方案可采用先利用CNN+AutoEncoder模型对曲线进行分类,并建立无监督模型来抽样找出异常样本,从而建立起样本库。并利用建立在经验基础上选取的一系列特征,作为有监督模型的数据输入。最后,使用集成模型对数据进行训练来以保证模型的稳定性。
- 无监督异常检测的方案采用通过建立包括3-sigma,百分位数分布和箱型图等的集成模型,计算对历史数据中特征的多个分布来判断该特征在当前的异常可能性,然后把不同特征计算出来的异常分数,按比例结合起来,与按照经验设定的异常阈值比较,检测异常。