一、预测
监控项的样本就是时间序列,通过分析监控项的序列,得到未来一段时间的预测值。根据波动剧烈程度,监控项可以分为波动不太剧烈和剧烈的,根据周期性,可以分为具有周期性和不具有周期性等等,当然还有很多划分的标准。可见,不同时间的序列,需要使用不同的模型去预测。
模型 时间开销 准确率 开源包
LR(线性回归) 少 低 sklearn
ARIMA 少 低 statsmodels
浅层神经网络,回归树等 中等 中 pybrain, sklearn
LSTM 大,需要GPU 高 tensorflow
预测大体上分为故障预测、容量预测和性能预测。业界基于 RSTM 的一个算法,该算法是基于时序数据预测的一个经典算法。
二、异常检测
异常检测是AIOPS最常见的场景,算法也有很多,业界比较流行的比如普通的统计学习方法–3σ原则,它利用检测点偏移量来检测出异常。比如普通的回归方法,用曲线拟合方法来检测新的节点和拟合曲线的偏离程度,甚至有人将CNN和RNN模型应用到异常点的检测。
异常值本质上是一个数据点。通常,大多数应用程序中的数据是由一个或多个反映系统功能的程序产生的。当底层应用程序以不正常的方式运行时,它会产生异常值。
通常所说的异常大致分为异常值、波动点和异常时间序列三类。
1 .异常值( Outlier)
2. 波动点( Change Point )
3.异常时间序列( Anomalous Time-series )
在监控系统中,主要处理的是时序数据,而时序数据具有一定的特征。
同比环比预测器
同比环比是比较常用的异常检测方式,它是将当前时刻数据和前一时刻数据(环比)或者前一天同一时刻数据(同比)比较,超过一定阈值即认为该点异常。
基线预测器
同比环比使用历史上的单点数据来预测当前数据,误差比较大。t时刻的监控数据,与 t-1,t-2,…时刻的监控数据存在相关性。同时,与t-k,t-2k,…时刻的数据也存在相关性(k为周期),如果能利用上这些相关数据对t时刻进行预测,预测结果的误差将会更小。
比较常用的方式是对历史数据求平均,然后过滤噪声,可以得到一个平滑的曲线(基线),使用基线数据来预测当前时刻的数据。
Holt-Winters预测器
同比环比预测到基线数据预测,使用的相关数据变多,预测的效果也较好。但是基线数据预测器只使用了周期相关的历史数据,没有使用上同周期相邻时刻的历史数据,相邻时刻的历史数据对于当前时刻的预测影响是比较大的。
计算序列的周期性数据
时间序列的周期性数据不需要实时计算,按周期性更新即可,如外卖订单大盘监控,s(t)只需要每天更新一次即可。对于s(t)的计算,可以有多种方法,可以使用上面提到的Holt-Winters按公式计算出时间序列的周期性数据,或直接使用前一天的监控数据作为当天的周期数据(这两种方式都需要对输入序列进行预处理,保证算法的输入序列不含有异常数据)。也可以将历史数据做平均求出基线作为序列的周期性数据。
残差数据实时预测
计算出周期数据后,下一个目标就是对残差数据的预测。实际监控数据与周期数据相减得到残差数据,对残差数据做一次滑动平均,预测出下一刻的残差,将该时刻的残差、周期数据相加即可得到该时刻的预测数据。残差序列的长度设为60,即可以得到比较准确的预测效果。
离散度Filter:根据预测误差曲线离散程度过滤出可能的异常点。一个序列的方差表示该序列离散的程度,方差越大,表明该序列波动越大。如果一个预测误差序列方差比较大,那么我们认为预测误差的报警阈值相对大一些才比较合理。
阈值Filter:根据误差绝对值是否超过某个阈值过滤出可能的异常点。阈值Filter设计了一个分段阈值函数y=f(x),对于实际值x和预测值p,只有当|x-p|>f(x)时报警。实际使用中,可以寻找一个对数函数替换分段阈值函数,更易于参数调优。
无阈值KPI曲线异常识别。
四大黄金指标包括交易量(业务实时产生的交易量)、业务成功率(业务成功量/交易量)、系统成功率(系统成功量/交易量, 业务成功量和系统成功量的区别在于是否明确捕捉到系统异常)、平均时延(交易的平均耗时)。这四大黄金指标都是分钟级数据,这四个指标统计维度不同,波动规律也有所差别,因此需要用不同的算法检测。
检测方法主要有三种:
基于LSTM与高斯分布的检测,这个算法主要用于交易量和时延的检测。大部分的曲线突变都能准确检测到,但算法的死角在于小幅度长时间的缓慢变化容易被漏掉。
基于k-means算法的特征检测,主要用于填补第一种算法的盲区,在交易量缓慢变化的案例效果较好。
基于概率密度的检测,主要用于业务成功率和系统成功率的曲线,因为成功率曲线的背后隐藏着无数的可能,需要用一个更接近本质的量来衡量异常的程度。
而以上三种方法都有一个共同的判断原则——少见即异常。在我们确立了无监督为主的大前提下,异常检测的问题转换成了如何衡量当前的情况是否“少见”的问题。
首先是数据源的异常检测。
Z-score算法
Z-score算法,就是每个点减去均价再除方差,衡量计算这个点与整体情况的偏离度,达到一定程度就标记为极度异常数据(不纳入指标统计)。
用最简单的方法先过滤掉,在正常情况下,z-score能够帮助我们过滤掉更多的异常,而在真正出现故障时,可以减少对合理异常数据的过滤。
但是这个z-score算法,优点的计算简单,计算成本低,但是缺点是后期人工成本高;比如对于数据滑窗参数要手工调整,同时阈值也需要手工判断,成本较高。同时,算法本身对于异常点突出效果不明显的话,阈值难以取舍。接下来就是来了基于Boxplot箱线图的改良算法。
Boxplot算法
该算法核心是基于箱线图算法来改良的,在这个思想里,默认异常数据百分比是比较低且相对稳定的,不过,指标数据一般不是完美的正态分布,比如时延指标是有右偏(偏大)情况,会往高的时延方向偏移,因此,我们在原有的箱线图算法中加了一个重心偏移。同时,我们还发现时延数据不仅有重心偏移,还存在长尾效应,因此我们还加入了长尾修正参数,即:99分位数据减去中间值除上75分位与中间值来衡量这个长尾效应,这样,算法很好地解决了存在重心偏移以及长尾效应的异常数据过滤。
时间序列分解算法
数据源的异常检测解决好后,指标的异常检测就有了基础。
大家经常用到异常检测方法的时间序列分解法,周期项、趋势项、残差项的计算都在其中。从算法表现图上来看,通过周期学习,趋势计算后,原始数据减去周期再减去趋势,就变成了白噪声。通过置信空间的计算,叠加原来计算的周期与趋势,就得到了指标的上下阈值。
因为用户少,少量用户的异常失败就会导致整个指标下降30%甚至更多,而且每天发生这种下降的随机性很强。
多工况检测算法
上面时间序列分解算法所不能适应的场景,就是多工况检测(MRCheck)算法的由来,这个算法外部用的很少,在此分享下,我们通过历史数据的特征进行贡献度识别,其实数据的波动和请求量还有时间是有关系的。因此,如图所示流程,会根据特征(请求量和时间),建立不同的工况(本质是聚类算法),如3~20种工况,然后通过各个点与聚类中心点的距离进行工况划分的评估,确定工况划分的合理性。
可以这么理解,以前时间序列是只有一种工况的特例,而现在我们通过变成多种工况,重新评估置信空间,异常检测阈值线根据工况变化随之发生变化,很好的解决了原来时间序列分解算法的问题。
三、报警收敛
数据聚合与关联技术
对时序数据的处理大致分为两类
1.单系列时序数据聚合
单系列是指同一个类别组成的系列,比如订单表中订单时间这个维度。聚合的含义就是汇总,对一组数据通过系列运算得出单 值的过程,这里的运算是指在固定周期内(10s 0s等)对实时、时序数据流的运算。
2. 多系列时序数据关联
多系列是指多个类别组成的系列。数据关联的结果是将不同系列的数据整合到一起,方便后续的数据应用
1.数据聚合
聚合数据有两个层面,
一是对数据的聚合运算(计数、平均、抽样等)
二是多维度的聚合(在实际应用中维度通常指时间、地点、业务线、服务、接口等,它们也可以被称作“标签”,用来标注看待数据的不同角度〉。
2.降低维度
例如告警这个场景,当一个业务/服务有问题时,可能会触发多个维度的事件,如接口维度、机房维度、服务池维度等,如果都触发了告警,就变成了噪音,你没有办法快速定位根本原因,一天收到成千上万个告警,基本上就等于告警无效了。
通过机器学习技术对一组己知的告警数据进行训练学习,生成分类模型(会不断调整、优化),然后模型对新接收的告警数据进行分类,是否会减少误报的概率昵?
基于告警分类器的减少误报的方法 “分类”是人工智能和机器学习领域的重要算法,分类方法是一种对离散型随机变量建模或预测的监督学习算法,有监督的学习意味着需要有一些己标注的数据作为训练样本。通常我们会提供一个告警结果页面,供开发和运维人员来选择一一处理、忽略、误报等选项可以将告警数据标签化,然后建立训练样本分类器既可以由人工构建,也可以由机器学习技术自动构建。分类算法有近邻(KNN)、贝叶斯分类器(NB)、Logistic回归 )、支持向量机(SVM)和随机森林)等,有时候需要不同的算法交叉验证学习效果。
3.数据关联
数据关联一般指根据一定的规则和关联关系连接各类数据以便形成新的数据。而在监控系统中,经常遇到的情况是实时数据关联。
利用算法分析出这些报警项之间的关系,再加上人工经验,将很大程度减少报警的数目。如何通过算法去分析出报警项之间的潜在关系。采用机器学习中关联分析常用的算法Apriori来分析历史报警,该模型利用频繁项集分析出A—>B这种关系。将这种规则应用到报警中,如果A报警发出,则B报警就不需要发出,这样就能够成倍减少报警次数。
四、根因分析
在根因定位方面,放弃了传统的组件告警收敛专家经验的定位方法,以消息总线的消息日志为基础,基于算法生成交易链路,异常时绘制故障交易链路图,定位中断子系统,然后以中断子系统为圆心,使用知识图谱算法发散式根因挖掘。
另外,历史异常事件的数据也导入知识图谱,修正知识图谱中的专家经验。从运维管理的角度进行异常识别和根因定位标记,不断迭代修订基础模型数据。
异常报警根因分析的设计大致分为四个部分:收集报警信息、提取报警信息的关键特征、聚类处理、展示报警摘要。
聚类算法采用论文“Clustering Intrusion Detection Alarms to Support Root Cause Analysis [KLAUS JULISCH, 2002]”中描述的根因分析算法。该算法基于一个假设:将报警日志集群经过泛化,得到的泛化报警能够表示报警集群的主要特征。可以将报警抽象为各种层次,抽象层次越高,细节越少,但是它能包含的范围就越大;反之,抽象层次越低,则可能无用信息越多,包含的范围就越小。这种抽象的层次关系可以用一些有向无环图(DAG)来表达。
算法描述
算法假设所有的泛化层次结构Gi都是树,这样每个报警集群都有一个唯一的、最顶层的泛化结果。
将L定义为一个原始的报警日志集合,算法选择一个属性Ai,将L中所有报警的Ai值替换为Gi中Ai的父值,通过这一操作不断对报警进行泛化。
持续步骤2的操作,直到找到一个覆盖报警数量大于min_size的泛化报警为止。
输出步骤3中找到的报警。
人工智能在故障定位领域的应用
传统的故障定位技术(监控告警型和日志分析型)非常依赖人的经验,但是一方面,经验的传承与积累受组织结构和人事变动的影响非常大;
另一方面这些代表经验或知识的规则显然是隐含的,只可意会不可言传,很难被人为地总结成基于显式规则的专家系统。 人工智能就是通过算法和不断学习,实现隐含规则的自动学习以及更高知识粒度的学习推理。
1 基于关联规则的相关性分析
就像本章开头所介绍的,故障一般会通过事件、错误、症状表现出来,前面我们也介绍过通过聚类来处理告警(降低维度),那么这些事件、错误、告警数据之间有没有联系?它们之间的关系是否能为故障定位提供帮助?
“关联规则挖掘是指从一个大型的数据集中发现有趣的关联或相关关系,即从数据集中识别出频繁出现的属性值集(也称为频繁项集),然后利用这些频繁项集创建描述关联关系规则的过程。”
关联规则挖掘是一种基于规则的机器学习算法,它的目的是利用一些度量指标来分辨数据集中存在的强规则。也就是说,关联规则挖掘用于知识发现,而非预测,所以属于无监督的机器学习算法。关联规则的度量(筛选和过滤)方法有:最小支持度(Minimum support)和最小 置信度(Minimum confidence)。
2 基于决策树的故障诊断
决策树是附加概率结果的一个树状的决策图,是直观地运用统计概率分析的图法。在机器学习中,决策树是一个预测模型,表示对象属性和对象值之间的 种映射,树中的每个节点都表示对象属性的判断条件,其分支表示符合节点条件的对象。树的叶子节点表示对象所属的预测结果。
和关联规则不同,决策树属于有监督的机器学习方式。在实际应用中,可以通过对数据进行处理,利用归纳算法生成可读的规则和决策树,然后使用决策树对新数据进行分析。决策树是一种非常典型分类方法(算法)。
简单来说,决策树算法其实就是根据己知的经验来构建一棵树。可以认为是根据数据的某个维度进行切分的,并不断重复这个过程。当然,如果切分的顺序不同,则会得到不同的树。
回到故障分析和诊断问题上,假如对于某类故障的处理有了一定的经验,形成了一系列的规则,就可以对这些规则进行总结,当某个应用发生告警时,其判断逻辑可以取得经验值。
一种模型,能够帮助运维人员缩小报警排查范围,快速定位到问题。该项目中要分析两个维度数据:
一个是事件维度,关注的是六大类报警事件;
一个是指标维度,关注机器维度的监控项(大约有200左右个监控项)
那如何在事件发生后,找到跟它相关的指标呢?实现的方法如下:
针对每个事件,使用在2014年SIGKDD会议上发表的论文《Correlating Events with Time Series for Incident Diagnosis》中提到的方法,看哪些指标跟这个事件发生有关系。这样的目的能够对指标进行初筛,达到降维的目的。
针对第一步选出来的指标,求出这些指标的信息增益比,选择前k个(360取得值是5)特征作为最后的影响指标;
最后使用xgboost对影响指标进行分类,验证效果。
专家系统的技术实现,主要有以下原因:
首先,“业务异常”的数据是“小数据”。在“小数据”的基础上,机器学习在根因分析方面的应用相对有限。
其次,“根因分析”是需要有较强的解释性的,每次业务异常后,运维工程师都会有完整的异常事件分析报告,机器学习在可解释性上相对较弱,而专家系统能更好的解释根因是如何分析出来的,更符合人类的思考逻辑。
最后,利用人类专家“举一反三”的能力,可以短期内构建出根因分析系统。
因此我们先选择了专家系统的解决方案,将IT专家的经验总结起来形成推导规则。
知识图谱
传统根因推导过程是运维工程师通过对软件架构和调用关系的理解将异常发生时的告警、日志等信息联系在一起,应用运维知识经验来排查推导异常根因,相当于在大脑中存储和训练了一个知识图谱。其中最大的挑战在于,运维工程师的知识经验存在差异而且往往仅精通本领域知识,同时人脑存储的信息量也相对有限。
图形数据库(图形数据库是一种非关系型数据库,应用图形理论存储实体之间的关系信息)可以针对每个异常事件创建一个覆盖多应用域及基础架构的全专业图谱,沉淀运维知识进行因果推导。相比于专家规则引擎系统,基于图数据库的知识图谱更利于开发维护,并且具备结合机器学习实现复杂推理和新知识发现的扩展性,可视化的推导链路也具有较好的可解释性易于复盘和优化。
针对异常事件建立的知识图谱包含每笔异常交易的路径信息、CMDB关联数据库等基础架构信息、相关性分析得出的告警/日志/变更信息,针对这些数据基于基础组件影响上层应用等运维知识进行因果推导得出根因,如果存在多种结论则依据加权评分进行可能性排名。
异常事件的知识图谱是结合“动”态和“静”态数据来设计,“动”态数据包括业务流水相关的日志、证据数据,“静”态数据则来自于CMDB等配置系统。两类数据共同构建起一个完整的异常事件图谱。一般来说,知识图谱设计及根因分析一般包括信息收集、根因定位、根因补充三个阶段。
在做根因分析的时候,我们首先要做的就是要把指标和应用的一些关联拓扑构建出来。指标和应用的拓扑依赖关系应该如何去构建呢?这主要依赖于分布式跟踪系统进行自动探测应用拓扑。
但在实际应用中,通常我们探测的拓扑关系比较复杂需要结合人工标注的方式为拓扑增加相应的权重作为拓扑依赖关系的一个修正。有了应用拓扑之间的依赖关系之后,基于大量历史告警数据进行自学习,分析每个故障时间点应用和指标之间的关联关系汇总为知识库数据,并存储到知识库系统。
这个不断完善的知识库系统可以作为研发定位问题的依据,也可以作为故障自动处理的依据,还可以作为运维机器人的知识来源。同时,知识库也支持人工添加一些常见的故障以及故障原因并给予较高的分析权重。基于不断修正的业务拓扑关系,系统就可以自动找出一个或几个故障的根因。
五、APM
关于 APM,Google Dapper 可以说是所有 APM 产品的鼻祖。基于 Dapper,近年来也出现了非常多优秀的 APM 产品。除了商业化的 APM 厂商,还有一些比较优秀的开源项目:Pinpoint / Zipkin / Cat / EagleEye / OpenTracing / SkyWalking 等。各种 APM 产品各有优劣,结合自身业务需求并充分对比分析后我们选择基于 Pinpoint 进行二次开发实现 APM。
它的缺点在于性能方面比 Zipkin、SkyWalking 要差一点,但是 Pinpoint 也有其他项目不具备的优势,比如接入简单无需修改代码,再比如可以跟踪到代码级别等等。
基于 Pinpoint 开发的 Jtrace 分布式跟踪系统拥有 7 大能力:
分布式事务跟踪;
自动检测应用拓扑;
水平扩展支持大规模服务集群;
代码级别的可见性,这是相对于其他产品最大的不同,它可以跟踪方法堆栈,特别清晰;
使用字节码增强;
集成了 SQLAdvisor,在抓到 SQL 之后,我们会分析到哪些是比较慢的 SQL,慢的 SQL 到底慢在哪里,我们可以通过这个给出一些优化建议;
智能化采样率,基于业务访问量自动调整采样率,大大降低了业务性能方面的开销。
关于性能方面,我们从以下几个方面进行了优化:
使用二进制格式(thrift 协议),高压缩比,在网络传输上可以减轻很多开销;
使用变长编码和格式优化数据记录(thrift CompactProtocol);
用常量表替换重复的 API 信息,SQL 语句和字符串;
智能采样率;
使用异步数据传输来最小化应用线程中止;
使用 UDP 协议传输数据。
优化后性能损失与目前流行的 Zipkin 相近。相对于我们获取的数据精度来说,这个是可以接受的结果。
六、运维体系规划。最下层是资源层,包括物理资源、虚拟资源、应用、中间件以及数据库。上层是平台层。
在平台层,我们建立了维护基础数据的 CMDB 系统,在 ITSM 管理方面,集成了事件管理、问题管理、值班管理等运维流程化管理模块。
在 CMDB 系统基础上我们建设了大规模资源监控平台、网络监控平台以及多个运维平台。
再往上,是数据化层。在这一层,我们期望通过对监控和运维平台产生的大量数据进行分析,做趋势性的预测和智能分析,提供一些比较有价值的统计报表,来指导业务运营和决策。
最上层是 AIOps 层,我们是从三个方面去实现的:发现问题,解决问题,规避问题。基于AIOps,我们可以在异常检测、根因分析、故障预测、智能故障处理、智能运维机器人等方面继续发力探索。在解决问题方面,可以借助 KPI 聚类分析进行告警知识库自学习和故障自动处理等。
如何从架构方面落地实现的呢?我们将整体系统架构拆分为底层数据处理架构和业务架构,底层数据处理架构负责监控数据的采集、数据清洗、校验、告警和通知操作。业务架构负责监控数据统计分析、展现。
首先我们采用被动监控的方式,通过部署监控 Agent,把监控数据收集到 Kafka 消息队列里。消费模块从 Kafka 拿到数据后转存到 jimdb(京东内部的内存数据库中间件)中,jimdb 实际是一个内存的分布式消息队列。
这里加了一层 jimdb 的队列。为什么要加这层呢?因为我们如果直接消费 Kafka,Kafka 有分区的概念,不同的分区之间可以并发生产消息,但是 Kafka 的分区是消耗磁盘 IO 的,如果我们建的分区太多,这个磁盘 IO 可能就会是一个瓶颈,而且意味着我们要需要更多的硬件资源。
考虑到这一点,我们增加了 jimdb 层,它是一个生产者消费者模型的分布式消息队列,理论上可以有无数个 Consumer,这些 Consumer 之间并发消费数据,从而实现并发数据处理。
我们把所有的监控平台的监控数据整合在一起,接入了京东目前所有的监控系统,包括 log 监控、Docker 监控,MDC 的监控,DBS 的数据库监控,还有调用链监控等,把数据收集起来做统一的报警和分析。在 2.0 版本,我们会把所有监控平台的指标收集上来之后,在应用维度做统一的整合。这样在一个应用页面,就可以看到这个应用相关的所有监控信息,比如操作系统维度的指标,数据库相关指标、应用性能相关指标以及日志相关的指标等。
此外,我们还加入了日志分析的相关功能,使用的是业界比较成熟的方案:通过 agent 将日志发送到 Kafka,Kafka 里面做一些 Cluster,Filter,最后存储和索引。
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/301914.html