日志聚类引擎的探索"事故的多数原因可以追溯到监管和防护机制的失败。"---詹姆斯·里森(James Reason) 1.
"事故的多数原因可以追溯到监管和防护机制的失败。"---詹姆斯·里森(James Reason)
1. 背景
1.1 异常分支监控的重要性
异常分支是什么:在程序执行过程中,由于某些原因(如错误的输入、不符合预期的操作、资源不可用等)导致程序未按照正常的控制流程继续执行,而是进入了一个特殊的处理路径。
在代码中对异常分支进行监控具有非常重要的意义:
-
提高系统稳定性:
异常分支是代码中未按预期执行的部分,可能导致系统崩溃或业务功能异常。通过监控这些分支,可以及时发现问题,从而采取措施避免系统故障,提高整体系统的稳定性。
-
快速问题定位和修复:
当异常发生时,如果有针对异常分支的监控,开发和运维团队可以迅速定位问题的根源,减少排查问题所花费的时间。这样可以更快地进行问题修复,降低对业务的影响。
-
预防性维护:
异常分支监控不仅可以用于事后分析,还可以用于预测潜在问题。通过分析监控数据中的异常模式,可以提前识别出可能会引发严重问题的趋势,并在问题发生之前进行预防性维护。
1.2 如何对异常分支监控
在我们看来,监控的主要作用是:实时持续观察和分析目标对象,并在出现异常时自动触发报警。
我们先看看一小段代码片段:
private void example1() {
try {
doMethod();
} catch (BussinessException bussinessException) {
// 异常分支
}
}
private void example2() {
if (doMethod() == null) {
// 异常分支
}
}
上述异常分支中,基于我们现在的能力,我们该怎么监控呢?
-
加Prometheus打点(metric counter)?不可行!原因如下:
- 并非所有异常分支都需要通过打点来增强感知。例如,参数校验异常通常不需要这样做。
- 如果将过多的异常分支都通过打点进行监控,这将对监控平台造成负荷,进而可能导致瓶颈问题。
- 在打点之前,必须先定义相关指标,这一过程既繁琐又耗时,从而降低了编码效率。
-
向外抛异常?不可行!原因如下:
- 并非所有异常分支都适合直接抛出异常。
-
日志记录?可行但有缺陷!原因如下:
- 日志只能做事后分析问题,不能发现异常时自动触发报警
结论:当前,我们没有一个很好的方法去对异常分支进行监控
1.3 日志聚类引擎引出
一个令人欣慰的方面是,我们按照编码习惯和要求,在异常分支都需要记录error日志。鉴于此,我们可以通过加强对日志的监控来实现对异常分支的监控,从而提高系统的稳定性。
图1
然而,目前的日志分析主要依赖于人工操作,这种方法不仅效率低下,而且可靠性也不高。为了实现对日志的高效且可靠监控,我们首先需要具备以下能力:
-
能够对日志进行有效分类,这样我们就能迅速把握日志的全貌。
-
具备按时间顺序保存分类数据的能力,从而便于我们对数据进行趋势分析。
-
具备自动报警的能力,能够在新类别的异常日志出现或数据趋势发生波动时及时发出报警,这样我们可以快速感知并响应潜在的问题。
根据上述分析,我们计划开发一套名为“日志聚类引擎”的工具。该工具将具备对日志进行分类的能力,帮助我们有效地分析日志数据。此外,它还能自动识别异常并触发报警,从而提高我们对系统状况的监控和响应速度。
2. 难点与挑战
开发之前,我们先盘一盘开发一套日志聚类引擎的难点与挑战
2.1 该分哪几类
📌面对一堆日志,怎么确定有哪几类呢,谁和谁又该归到一类呢
图2
看上面的案例,对于我们开发者来说,我们很容易知道要分哪几类。 那我们来告诉工具怎么分类吗?可以,那怎么告诉呢?
方法 | 致命缺点 |
---|---|
编码时,日志加上类型id,这样就可以通过日志里的类型id进行分类了 | 1. 需要投入大量人力,将已有日志进行手动打标2. 每加个日志都要考虑类别是哪个,增加开发的成本 |
维护类型模板,通过正则表达式与日志原文进行匹配分类,例如: type1:xxxx已过期 type2:查询xx<*>配置为空 | 1. 一个服务的日志类别巨多,非常难维护2. 日志种类是不断新增的,每次新增都得手动维护模板库3. 当不同服务新接入时,又得投入大量的人力去配置模版 |
难点与挑战:
- 我们不能告诉工具分哪几类,而是让工具自己去决定分哪几类
2.2 怎么正确分
📌日志内的有效信息散列分布,没有规律
案例
图3
难点与挑战:
- 在日志中,有效信息的位置是随机散布的,没有什么固定的模式或顺序,所以不能用简单的字符串group by的方式去分类
2.3 怎么接入简单
📌不同服务的日志格式各不相同
案例
图4
难点与挑战:
- 不同服务的日志格式是千奇百怪的,为了让新服务接入简单,工具需要自适应不同格式的日志
3. 聚类收益
看了难点和挑战,我们再来看看收益,然后再决定有没有必要迎难而上
图5
-
填补对异常分支的监控
- 通过对日志的监控从而达到对异常分支的监控
-
降低日志分析成本
- 减少手动分析:自动聚类减少了对日志进行手动检查和分析的需要,从而减少了人工成本。
-
提升系统稳定性
- 预防性维护:及时发现日志中的异常模式和潜在问题,提前采取预防措施,避免问题升级成更严重的故障。
- 异常报警:通过聚类发现 新增异常日志、异常趋势变化 进行报警
日志聚类引擎对事中发现防护网进行了补充
图6
事中发现防护网 | 监控对象 |
---|---|
监控平台 | 1. 系统可靠性指标,例:error、exception2. 系统资源利用率指标,例:CPU、内存3. 系统性能指标,例:rt |
实时、离线核对 | 1. 业务特征指标,例:入参决定结果、结果决定结果 |
💡日志聚类引擎 | 1. 异常分支监控:例:出现即异常的分支、命中数突然升高的异常分支 |
4. 方案设计
决定干,开始进入方案设计
4.1 组件图:
图7
4.2 功能拆解
- 定时任务触发:使用XXL-JOB定时任务调度系统,按预定计划触发日志聚类引擎服务的API接口。
- 日志获取:日志聚类引擎服务调用kibana日志查询接口,获取指定时间段内的error日志数据。
- 日志聚类处理:引擎对获取到的日志数据应用聚类算法,处理日志并生成日志模板和处理后的日志明细。
- 数据存储:将聚类生成的日志模板和明细数据保存到数据库中,供后续查询和分析使用。
- 数据展示:开发人员或运维人员可以通过日志聚类数据展示管理后台访问和查看聚类结果,包括不同日志聚类类型的数量趋势图等信息。
- 监控与报警:日志聚类引擎服务将关键聚类数据指标发送到Prometheus进行监控,根据设置的报警规则进行风险预警,及时发现潜在问题。
4.3 时序图
图8
4.4 日志聚类流程图:
图9
4.5 算法选型
4.5.1 算法调研
特点/算法 | Spell | K-means | 层次聚类 | DBSCAN |
---|---|---|---|---|
机器学习 | 否 | 是 | 是 | 是 |
适用场景 | 专门针对日志数据,自动提取日志模板。 | 适合数值数据,需要预先知道聚类数量。 | 适合任意形状的聚类,不需要预先知道聚类数量。 | 适合任意形状的聚类,特别是有噪声的数据。 |
优点 | 高效处理日志数据,能区分常量和变量部分,不需要预设聚类数。 | 快速且简单,适合大规模数据。 | 能发现数据的层次结构,不需预设聚类数。 | 不需预设聚类数,能识别噪声,适合复杂形状。 |
缺点 | 主要针对文本日志,可能不适用于非日志类型的数据聚类。 | 对初始中心敏感,假设聚类为凸形。 | 计算复杂度高,不适合大规模数据。 | 对参数敏感,处理不同密度的聚类效果不佳。 |
算法特性 | 基于日志模式识别的聚类。 | 基于距离的聚类。 | 基于连接的聚类。 | 基于密度的聚类。 |
4.5.2 算法选型试验
前期调研以上算法,考虑到 通用性、不需要大量人工投入 预训练,所以选择了 DBSCAN和spell 进行试验。
-
聚类效果:
- DBSCAN:将日志文本数据转换为数值特征向量,基于密度进行聚类。聚类后的数据,往往没有业务关联性,聚类效果不好掌控
- spell:基于日志源文本,使用最长公共子序列(LCS)进行匹配,聚类后的效果肉眼可知其含义
-
维护成本
- DBscan:对参数敏感,不同appid服务接入成本高
- spell:不需要预先指定聚类相关参数,对新服务接入友好
-
模板提取
- DBSCAN:其通过识别数据点的“紧密度”来形成聚类,不能直接提取
- spell:基于日志文本进行聚类,可直接提取
聚类效果 | 维护成本 | 模板提取 | |
---|---|---|---|
DBSCAN | ❗️ | ❗️ | ❗️ |
spell | ✅ | ✅ | ✅ |
结论:基于上述分析与比较,spell占优,所以决定使用spell算法。
4.5.3 Spell 算法介绍
Spell算法是一种用于日志解析的算法,并从日志数据中提取模板。这种算法是面对那些没有固定格式或标准化输出模式的日志文件时特别有用。它能自动识别和提取日志条目中的常量和变量部分,从而生成日志的模板。
工作流程图:
图10
lcs算法介绍
最长公共子序列(LCS)算法的原理是基于动态规划,通过建立和填充一个二维数组来求解两个序列的最长公共子序列。动态规划是一种通过将大问题分解成较小子问题,解决每个子问题仅一次并存储它们的解,从而高效进行计算最长公共子序列。
5 功能介绍
让我们看看具体有哪些功能
图11
5.1 自动日志聚类
- 某一时间段,聚类的效果(数据来源于测试数据)
原日志数据:
Error: Failed to load resource: the server responded with a status of 404 (Not Found)
Warning: Deprecated function called in /var/www/html/app.php on line 111
Error: Connection timeout while connecting to the database
Error: Connection timeout while connecting to the database
Error: Connection timeout while connecting to the database
Warning: Deprecated function called in /var/www/html/app.php on line 222
Fatal: Maximum execution time of 30 seconds exceeded in /var/www/html/script.php
Error: Failed to load resource: the server responded with a status of 404 (Not Found)
Error: Failed to load resource: the server responded with a status of 404 (Not Found)
Notice: Undefined index: name in /var/www/html/index.php on line aaa
Notice: Undefined index: name in /var/www/html/index.php on line bbb
Notice: Undefined index: name in /var/www/html/index.php on line ccc
Fatal: Maximum execution time of 10 seconds exceeded in /var/www/html/script.php
Warning: Invalid argument supplied for foreach() in /var/www/html/loop.php
Warning: Invalid argument supplied for foreach() in /var/www/html/loop.php
Warning: Invalid argument supplied for foreach() in /var/www/html/loop.php
Fatal: Out of memory (allocated 123) (tried to allocate 112 bytes) in /var/www/html/memory.php
Fatal: Out of memory (allocated 456) (tried to allocate 353 bytes) in /var/www/html/memory.php
Fatal: Out of memory (allocated 789) (tried to allocate 566 bytes) in /var/www/html/memory.php
Warning: Deprecated function called in /var/www/html/app.php on line 333
聚类后的数据:
size:3 Error: Failed to load resource: the server responded with a status of 404 (Not Found)
size:3 Error: Connection timeout while connecting to the database
size:3 Warning: Deprecated function called in /var/www/html/app.php on line <*>
size:2 Fatal: Maximum execution time of <*> seconds exceeded in /var/www/html/script.php
size:3 Notice: Undefined index: name in /var/www/html/index.php on line <*>
size:3 Warning: Invalid argument supplied for foreach() in /var/www/html/loop.php
size:3 Fatal: Out of memory (allocated <*>) (tried to allocate <*> bytes) in /var/www/html/memory.php
5.2 数据可视化
- 将聚类后的数据 可视化展示,包含聚类数据详情、聚类数据趋势曲线图。示例如下:
图12
5.3 自发报警
- 将日志模板数据打点上报Prometheus,针对趋势进行添加报警。示例如下:
图13
图14
6 优点
- 高效的日志解析:无需预先定义的日志模板,可以自动从未标记的日志数据中提取日志模板。
- 自适应:可以自适应新种类日志,不需要额外的人工干预就可以很好地对其分类
- 低资源消耗:相比于其他需要复杂机器学习,SPELL算法在内存和处理时间上通常更为高效。
- 接入简单:新的服务接入,不需要大量手工配置或预训练模型的日志解析算法,接入成本较低
"你不能管理你不测量的东西。" ---彼得·德鲁克(Peter Drucker)
转载自:https://juejin.cn/post/7402822739219071027