1

搞定这个日志智能分析设计,大小故障都无处可逃 - 运维 - dbaplus社群:围绕Data、Blo...

 1 year ago
source link: https://dbaplus.cn/news-134-4538-1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

搞定这个日志智能分析设计,大小故障都无处可逃

sw 2022-06-05 11:26:00

一、背景

随着系统的日益复杂,生成的日志是海量的。当发生故障时,人工从海量错误日志中定位异常的成本非常高,主要原因:



  • 日志格式繁多,难以依靠人工划分,而传统的日志规则分类需要配置复杂的规则和正则,难以通用化;



  • 日志量级大,报警多,难以定位需要关注的异常,一些无关的错误日志容易掩盖真正的问题。

日志智能分类算法可以自动根据日志的相似性对日志进行流式聚类,并提取其中的关键信息——日志模版,有效避免相似日志的无效查看,大幅节省排查时间。并且日志异常检测可以从海量日志中发现潜在的异常日志模式,帮助程序快速定位异常。

二、日志智能分类

1、设计方案

最初的日志分类服务在具体的算法选用上选择了 Drain 算法来对日志模板进行提取。随着业务经验的累积,为了提高日志分类的准确性,用两级模型对日志进行流式分类并生成日志模版。其中一次分类相当于是预分类,然后把预分类结果再进行二次分类,将预分类没有分好的日志进行融合,形成最终满足预期的分类结果。

2、一次分类

一次分类使用的是一种改进的前缀树。

图片
从根节点开始,第一层为长度层,同样长度的日志进到同一个结点,接下来的节点就是根据token进行判别,只有匹配了同样的token的日志,才往对应的路径分。此外,还会设置一个阈值,当叶子结点到达阈值后,会增加一个<*>结点,用于匹配所有未成功匹配的日志。由于树深是提前设定的,一般会设得比较小,因此匹配的速度会非常快。整个树生成和匹配的过程实际上就是一个加入长度层的前缀树。

算法流程如下:

  • 预处理,以分隔符/空格为单位将日志切分为一个个的token;



  • 根据日志token长度去第二层(每个节点对应一个长度)寻找对应节点,比如Receive from node 4匹配的节点对应日志token长度为4;



  • 根据日志token按顺序去进行分裂,这里受到depth限制,分裂树深为depth-2(去除root和length层);



  • 分裂到叶子节点后,计算日志与各个模板的相似度simSeq,返回simSeq大于阈值st并且相似度最高的模板;



  • 更新Parsetree,当日志在叶子节点匹配到了模板,并且部分token有差异,则用<*>替换;当没有匹配到模板时,则将新的日志加入到该叶子节点的模板列表,作为新的模版。



3、二次分类

二次分类使用的是基于最长公共子序列匹配的算法。

图片
一次分类第一层会有一个长度匹配,那不同长度的日志必然不会被分到一类;而且一次分类是根据token的顺序一个个匹配的,计算相似度也是顺序计算的,两条很像的日志,如果仅中间某些token划分不能对齐,就会导致无法分到同一类。为了克服上述问题,引入了基于最长公共子序列的匹配算法,将一次分类获得的模版进行二次合并,获得聚类效果更佳的模版。同时,由于最长公共子序列的时间复杂度较高,因此设计了前缀树、简单循环等两种前置预匹配方法,减少部分LCS的匹配,提升算法整体的效率。

算法流程如下:

1)预处理,以分隔符/空格为单位将日志切分为一个个的token。



2)前缀树预匹配,可以匹配到则返回匹配的分类和模版;匹配不到转到(3)。



3)简单循环匹配,可以匹配到则返回匹配的分类和模版;匹配不到转到(4)。



4)计算最长公共子序列,进行LCS匹配,可以匹配到则返回匹配的分类和模版,计算更新后的模版,差异部分用<*>替换;匹配不到则新增分类和模版。

4、traceback日志的处理

traceback日志与普通日志不一样,普通错误日志以分隔符/空格来划分token比较合适,但是traceback错误日志是一个trace的结构,按行看比较合适,因此把每一行traceback日志作为一个token,这样可以把trace类似的错误聚到一起,方便查找问题。

5、解决冷启动问题

日志智能分类算法会比较日志和模版,保留相同部分(常量),填充差异部分(变量)为<*>,更新模版,因此天然具有提取日志公共部分的能力。但是如果直接把原始日志输入到算法中,需要较长时间才可以完成模版的收敛;且收敛后的模版与输入的顺序有很大的关系,无法获得一个鲁棒的结果。这样会导致新接入的项目无法很好地应用日志智能分类。但如果能提前识别出变量,提前将其填充为<*>,则可极大地提升日志模版的收敛速度,也可以获得更加鲁棒的日志模版。通过正则将数字、base64编码和地址编码提前填充为<*>极大地提升了模版的收敛速度,原来要一周才能稳定并可用的模版,现在接入后马上可用。

三、日志异常检测

1、设计方案

目前业界对日志异常检测的研究有很多,总结来说主要为以下几类:

图片

我们日志异常检测算法主要是是基于统计+无监督的日志模版异常检测算法,完全没有人工标注成本,计算简单并具有较好的可解释性。目前日志异常检测算法需要依赖日志智能分类算法,需要在获得日志实时分类模版后,根据各模版的日志量的历史数据进行异常判定,从而发现其中的异常模式,并将对应常通过告警发送给用户。

2、具体算法

日志异常检测算法设计为1min粒度的:

1)按机器维度获取该机器的日志模版以及对应日志量的历史数据。



2)将不同模版的日志量历史数据使用卡方分布进行聚合。



3)对聚合后的数据进行异常检测,当发现异常时,触发(4),如果未发现异常,则返回结果为正常。



4)对每个日志模版对应的日志量的历史数据进行异常检测,根据异常程度,返回Top5的异常模版。



5)如果没有返回异常模版,则本次检测返回结果为正常;如果返回了异常模版,则本次检测返回结果为异常,并将异常结果、异常模版告警。

这里的异常检测设计为两步主要是因为:

  • 每台机器的日志生成的模版数量都很多,对应日志量历史数据中噪声也较多,直接进行模版的异常检测容易产生较多无效的报警;



  • 模版数量较多,全量进行1min粒度的异常检测计算压力较大,可能不能在1min内完成检测。因此考虑先从全局的角度设计一个噪声较少的指标,先对该指标进行异常检测,当异常检测结果为异常后,再下钻到具体的模版进行异常检测,找到异常模版,既能减少误报,也可以降低CPU压力。

设计平方和作为全局具有代表性的指标,采用卡方分布进行数据聚合,假设n个模版的频率特征符合标准正态分布,基于此构建模版的平方和特征,该特征满足卡方分布,在n较大时,卡方分布可近似为正态分布,可以使用3sigma的方式进行异常检测。

图片

日志异常检测使用的异常检测算法除了使用3sigma方法外,还使用了箱线图的方法,将两者的结果转换为异常分数后再进行融合。

3、减少周期性误报

周期性异常是指昨天或者上周出现过的同样的异常,此类报警属于周期性误报。此时,昨天或者上周对应时间点的异常分数也会较高,可以利用这个历史分数对当前分数进行抑制,达到消除周期性误报的效果。但是,出现异常的时间点可能会有一定的偏移,因此需要对昨天和上周一定时间窗口内的分数进行中心rolling_max操作,再使用当前异常分数减去昨天或者上周较大的那个分数,得到抑制后的分数。

4、新日志类别报警

某些情况下希望当出现新的日志模版类的时候,对新日志类别进行告警。但是当日志智能分类结果尚未稳定的时候,会经常出现新的日志类别,有可能产生很多误报。我们设计了自适应的新日志类别报警,当一天内出现新的日志类别超过一定阈值时,对新日志类别报警进行抑制;当低于一定阈值时,进行新日志类别的告警。

四、应用效果

图片

当日志异常检测检测到日志异常时,会告知用户异常的模版。

图片

进入日志计数页面可以看到,当前时刻确实出现了异常的日志暴增。

>>>>

活动推荐

相信大家通过上文,在日志智能分析上汲取了不少经验,在智能运维的落地过程中,大家还面临着这些难题:如何进行时序数据的异常检测?如何有效缩短故障定位时长?如何进行硬件故障预测?

在即将到来的6月17日,Gdevops全球敏捷运维峰会-广州站邀请了网易游戏-技术中心-智能监控AIOps团队负责人施望,给大家带来的《网易游戏AIOps探索与实践》主题分享,将会给大家解答上述疑难。同场还有高可用架构设计、故障自愈、智能化运维等精选数据库议题,欢迎扫描下图二维码了解更多:

图片

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK