2023年的 CCF AIOps 挑战赛相较往年主要有以下几点不同:
- 赛题的形式从命题式转变为开放式,参赛队伍可以根据比赛场景自主选择方向,包括但是不限于异常检测、根因定位和故障诊断等等。最终成绩由评审专家根据队伍所选课题、方案和效果给出
- 比赛场景的丰富度进一步提升。微服务架构和调用关系的复杂度进一步提升,且提供指标、文本和调用链等各种模态的可观测数据。比赛场景更加贴合现实系统
这种比赛场景和赛题设置也反映了需要 AIOps 处理的实际问题越来越复杂。从早前的时序指标异常检测,到后来的结合指标和调用链的根因定位,再到目前的复杂微服务系统结合多模态数据进行根因定位。虽然日志数据是检查系统健康状况的重要数据,但是日志数据进入 CCF 比赛场景的时间并不长。这可能是与以下几个原因有关:
- 微服务系统的规模和复杂度日益增长,相应的日志规模和复杂度也在急剧上升,以人工方式或者规则方式进行日志分析难度越来越高,亟需自动化手段提取日志中的有效信息
- 虽然指标或者调用链分析可以提供较为直接和准确的异常信息,但这往往只是智能运维的起点,后续异常根因定位和故障恢复往往需要借助其他信息更加丰富的数据,如代码数据和日志数据等等
日志相关的 AIOps 任务主要分为日志异常检测、日志故障预测和日志故障诊断三类:
- 日志异常检测:检测日志数据中的异常事件,如不寻常的日志数量、顺序等等。需要注意的事,检测到的异常并不意味存在系统故障或者将会产生系统故障,也可能是由正常的系统抖动产生的。需要运维人员进一步分析这些异常。日志异常检测主要帮助运维人员预防故障或者缩小故障的调查范围
- 日志故障预测:基于日志数据或与其他数据结合预测是否会有故障产生、何时产生故障
- 日志故障诊断:当系统出现故障后,分析日志数据,判断系统故障的根因。往往需要和观测数据或专家知识结合
这里我们主要考虑日志异常检测,日志异常检测所产生的异常事件也往往日志故障预测和故障诊断的基础。日志检测的一般流程如下:
- 由于日志数据量较大,在进行异常分析前往往提取相似日志,去除相似日志中不相同的变量部分,生成日志模板(LogPattern)或日志事件(LogEvent)。在日志事件级别进行分析
- 按照某种方式对日志进行分组,往往将时间上连续出现的日志分在一组,构造日志序列(LogSequence)。一般使用固定窗口、滑动窗口或者会话窗口的形式进行日志分组
- 对日志序列进行向量化表示,如考虑日志事件顺序的 SequenceVector,考虑日志事件数量的 QuantitativeVector,和考虑日志事件语义的 SemanticVector
- 使用传统机器学习模型或者深度学习模型在日志序列的向量化表示上进行预测任务训练(无监督)或者分类任务训练(有监督)
大部分日志异常检测算法的区别主要在于第三、第四步,且都在实验数据上取得了不错的效果。如 DeepLog、LogAnomaly、LogRobust 等等都在实验数据上达到 90% 以上的准确率。看似这个问题已经得到了很好的解决,但是实践中却往往事与愿违。导致这种差异的主要原因在哪里呢?我认为主要有以下几点原因:
- 一些方法在测试时使用的检测方法有一定的数据泄露。检测模型在训练时采用随机采样的方式构造训练集和测试集,这样训练集和测试集中包含各个时间段的数据(数据同分布)。但是在实际应用中,检测模型只能使用到已经出现的数据。由于日志数据存在着随着系统更新迭代变化演进快的特点,已经出现的数据和将来的数据并不总是同分布的,因此在实际应用时效果下降。因此我们在算法测试时应该按照时间顺序构造训练集和测试集,以保证更符合真实情形。近些年的一些日志异常检测算法也是这样做的
- 数据标签不均衡导致的评价指标失效。系统中的异常或者故障出现的频率很低,因此日志数据中异常日志序列相较于正常日志序列少很多。评价检测算法的效果时,往往使用对于异常日志序列的准确率、召回率和 f1 值作为评价指标,即算法更加关注对于异常序列的识别效果。应用于实际场景时,往往会产生很多误报的情况。这种误报会浪费使用者大量精力排查故障,也进一步降低了使用者对于算法的信任。因此在算法验证时除了关注对于异常序列的识别,同样应该保证对于正常序列的识别
- 现有算法对于日志数据中的噪声敏感度较高。这种噪声主要来源于两个方面 LogParser 对于日志事件识别的误差和数据集标注的误差。我认为 LogParser 识别的误差是导致日志异常检测算法在实际应用中效果不及预期的主要原因。后面我们将重点介绍 LogParser 对于日志异常检测算法的影响,2023 CCF 中介绍的一些日志相关的论文都在 LogParser 准确率的方向上做出了尝试
日志数据存在数据量大、变化快的特点。下面是微软某个服务中的日志事件数量随着服务版本迭代的变化情况:
可以看到随着版本的迭代,日志事件数量逐渐上升,且不同版本中保持不变的日志事件数量越来越少。为了保证日志异常检测算法效果的稳定性,LogParser 必须可以适应这种日志数量的变化。一般的日志异常检测算法采用比较流行的 LogParser,如 Drain, Spell 和 IPLoM 等等。这些 LogParser 往往基于日志特征识别日志事件,如日志中的高频词组成日志事件,相同日志事件对应日志长度相同等等。这些特征并不一定存在于不同的系统版本中。另外这些 LogParser 受其超参数的选择影响较大,如分词符、相似度阈值等等。不同场景需要的超参数往往差别很大。这些原因导致了常用的 LogParser 并不能很好的使用系统的迭代,会产生大量训练阶段没有遇到过得日志事件,同时得到的日志事件中也可能有一些冗余字段或缺失某些关键字段。
实际应用中产生的大量新日志事件对于一些采用封闭域假设的日志检测算法影响较大。如 DeepLog,假设所有日志事件在训练阶段都遇到过,且 DeepLog 在日志序列向量化时采用 Quantitative Vector,向量的每一个维度表示某一个日志事件出现的数量。由于向量的维度无法扩展,因此无法容纳新日志事件。对此其他的日志异常检测算法转而使用 Semantic Vector 的方式进行向量化,如使用 Word2Vec 方法将日志事件和日志序列聚合到语义维度,与日志事件数量无关。在日志场景,语义向量化时使用的 Word2Vec 需要注意考虑是否可以有效的区分同义词或者反义词。如 open 和 close,on 和 off 等往往出现在相似的日志上下文中,但是表示的语义却完全相反。如果 Word2Vec 无法识别这种区别,那么会丢失很多有效的信息,进而降低日志异常检测算法的有效性。
实际应用中日志事件出现字段丢失或者字段冗余的情况对于日志检测算法的影响更大。冗余的字段会在日志序列的语义向量中增加噪声,而缺失的字段可能会使语义向量的含义完全不同。目前对于这种情况的解决方案主要有两个方向:
- 在日志异常检测流程中去除 LogParser,直接在原始日志上向量化。虽然这种方案可以防止信息丢失导致的异常检测错误,但是其缺点也是显而易见的。在大日志量场景逐条对日志进行向量化在效率和成本上是难以承受的,只适合数据量较小的场景
- 追求识别准确率更高的 LogParser,这也是日志解析和日志异常检测长期努力的一个方向。目前主要尝试从基于统计的 LogParser 向基于语义的 LogParser 转变,使用的模型也经历从 RNN 到 Transformer 再到 LLM 的尝试。希望利用日志的语义信息准确的识别日志事件,保留日志事件中的有效信息。2023 CCF 中介绍的3篇论文中,BigLog 和 KnowLog 使用 Transformer 模型尝试训练更好的日志表示,这种日志表示应用于基于语义的 LogParser 可以提高其准确率。另一篇 LogPrompt 尝试使用大语言模型进行各种日志分析,包括 LogParser 任务。这些方法虽然提高的 LogParser 的准确率,由于深度模型推理速度的影响在效率上仍不及传统的 LogParser,难以应用在海量日志场景。实际应用中需要考虑结合使用基于统计和基于语义的 LogParser,如 LLMParser
下面我们简要介绍 2023 CFF 中日志相关的几篇论文的工作。
BigLog
BigLog 的目的在于提供有效的日志语义表示,其训练和应用流程如下,采用的基于 Transformer 的 pre-training & fine-tunning 模式。
训练阶段相较于 bert 模型,主要有以下两点区别:
- 在数据预处理阶段,使用正则表达式将日志中一些变量替换成变量值,如 IP 地址、文件名等等。这可能是因为结合变量类型,模型可以更好的识别日志的语义
- 在训练阶段除了预测掩码 token,BigLog 构造了日志场景的 NSP(next sentence prediction)任务,预测两条日志是否是在时间上连续出现
应用到不同场景时 BigLog 需要使用少量日志数据进行微调,论文中的实验结果显示了模型有着不错的迁移能力。将 BigLog 应用在 LogParser 任务中时,采用类似 LogStamp 的流程,首先在日志向量化表示上对日志进行聚类,然后识别每个日志类别中的低频 token 作为变量,高频 token 作为日志事件。
KnowLog
KnowLog 的目的也是提供日志表示。KnowLog 在模型训练中引入外部知识和对比训练任务,使得模型可以更好的理解日志中的术语、缩写等等。
模型包含三个训练任务:
- 通过对比学习拉近相似日志的向量表示之间的距离,拉远不同日志的向量表示之间的距离
- 预测日志中的缩写,提高模型对于领域知识的认知
- 通过对比学习使得日志的表示和其描述信息的表示更相近,提高模型对于日志语义信息的认知
KnowLog 的整体也是 pre-training & fine-tunning 流程。但是外部知识(日志描述信息、术语短语词库等等)的构建往往需要时间和人力的积累,可能导致 KnowLog 不是很方便地直接应用在不同领域中。
LogPrompt
LogPrompt 尝试构造合适的 prompt,使得大语言模型可以更好的处理各种日志分析任务。配合使用 Self-prompt,CoT Prompt 和 In-context Prompt 构造 prompt,调用大模型直接处理日志解析和日志异常检测等任务,在 zero-shot 场景都取得了不错的效果。在大语言模型火爆以后,陆续出现了各种使用大语言模型进行 LogParser 的方法,如 LLMParser。这些基于大语言模型的 LogParser 相较于其他的方法需要额外考虑大语言模型调用的时间成本和经济成本,缩短 prompt、减少语言模型的调用次数,以保证 LogParser 的响应延迟和使用成本都在可接受的范围以内。这往往是通过与传统的 LogParser 结合使用实现的,常见的做法是使用传统的 LogParser 缓存和解析已知的日志事件,大语言模型处理未知的日志事件。这样传统的 LogParser 保证了对于已知事件的响应速度且不需要调用大语言模型;必要时调用大语言模型处理未知日志事件提高日志事件识别的准确率。
实际应用上看,为了取得效果和性能的平衡,日志解析和日志异常检测仍有很大的提升空间。深度学习,尤其是大语言模型的引入为优化日志异常检测算法提供了新的可能性,例如使用 LLM 进行 LogParser,或者直接使用 LLM 在原始日志进行异常检测等等。但其在实际场景中的应用潜力仍有待挖掘。
参考文献
- DeepLog: Anomaly Detection and Diagnosis from System Logs through Deep Learning
- LogAnomaly: Unsupervised Detection of Sequential and Quantitative Anomalies in Unstructured Logs
- Robust Log-based Anomaly Detection on Unstable Log Data
- Log-based Anomaly Detection with Deep Learning How Far Are We?
- Log-based Anomaly Detection Without Log Parsing
- Biglog Unsupervised Large-scale Pre-training for a Unified Log Representation
- KnowLog: Knowledge Enhanced Pre-trained Language Model for Log Understanding
- LogPrompt: Prompt Engineering Towards Zero-Shot and Interpretable Log Analysis
- LLMParser: A LLM-based Log Parsing Framework