原始题目:DeepLog: Anomaly Detection and Diagnosis from System Logs through Deep Learning
中文翻译:DeepLog:通过深度学习对系统日志进行异常检测和诊断
发表时间:2017年10月30日
平台:CCS'17
来源:犹他大学计算机学院(School of Computing, University of Utah)
文章链接:DeepLog | Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security
开源代码:GitHub - wuyifan18/DeepLog: Pytorch Implementation of DeepLog.
摘要
异常检测是建立安全可靠系统的关键步骤。系统日志的主要目的是记录系统状态和各种关键时刻的重要事件,以帮助调试系统故障和执行根本原因分析。这种日志数据在几乎所有的计算机系统中都是普遍可用的。日志数据是理解系统状态和性能问题的重要而有价值的资源;因此,各种系统日志自然是在线监测和异常检测的良好信息源。我们提出 DeepLog,一种利用长短期记忆(LSTM)的深度神经网络模型,将系统日志建模为自然语言序列。这允许DeepLog从正常执行中自动学习日志模式,当日志模式偏离 从正常执行下日志数据训练的模型 时,检测异常。此外,我们演示了如何以在线方式增量地更新DeepLog模型,以便它能够随着时间的推移适应新的日志模式。此外,DeepLog从底层系统日志中构建工作流,这样一旦检测到异常,用户就可以有效地诊断检测到的异常并进行根本原因分析。对大量日志数据的大量实验评估表明,DeepLog的性能优于其他基于传统数据挖掘方法的基于日志数据的异常检测方法。
7. 结论
本文提出了一种基于深度神经网络的在线日志异常检测与诊断通用框架DeepLog。DeepLog学习和编码整个日志消息,包括时间戳、日志键和参数值。它在每个日志条目(entry)级别执行异常检测,而不是在每个会话(session)级别执行异常检测,因为许多以前的方法仅限于此。DeepLog可以从日志中分离出不同的任务,并使用深度学习(LSTM)和经典挖掘(密度聚类)方法为每个任务构建工作l流模型。这使得能够进行有效的异常诊断。通过整合用户反馈,DeepLog 支持LSTM模型的在线更新/培训,因此能够整合并适应新的执行模式。对大型系统日志的大量评估清楚地表明,与以前的方法相比,DeepLog 具有更高的有效性。
未来的工作包括但不限于将其他类型的 RNNs(循环神经网络)整合到DeepLog中以测试其效率,并集成来自不同应用程序和系统的日志数据以执行更全面的系统诊断(例如,MySQL数据库的故障可能是由单独的系统日志中所述的磁盘故障引起的)。
1. 引言
异常检测是建立安全可靠的计算机系统的一项重要任务。随着系统和应用程序变得比以往任何时候都更加复杂,它们受到更多的bug和漏洞的影响,对手可能利用这些漏洞来发起攻击。这类攻击也变得越来越复杂。因此,异常检测变得更具挑战性,许多基于标准挖掘方法的传统异常检测方法已不再有效。
系统日志记录各种关键时刻的系统状态和重要事件,以帮助调试性能问题和故障,并进行根本原因分析。这样的日志数据在几乎所有的计算机系统中都是普遍可用的,并且是了解系统状态的宝贵资源。此外,由于系统日志记录了活跃运行进程中发生的值得注意的事件,因此它们是在线监控和异常检测的良好信息来源。
利用系统日志数据进行异常检测的现有方法可以大致分为三组:
- 基于PCA的日志消息计数器[39]方法
- 基于不变( invariant)挖掘的方法来捕获不同日志键[21]之间的共现( co-occurrence)模式
- 基于工作流的方法来识别程序逻辑中[42]的执行异常。
尽管它们在某些情况下是成功的,但它们没有一个是有效的通用异常检测方法,能够在网上防范不同的攻击。
DeepLog 是一种数据驱动的异常检测方法,可以利用大量的系统日志。DeepLog设计背后的关键直觉来自自然语言处理: 我们将日志条目( entries)视为遵循特定模式和语法规则的序列元素。实际上,系统日志是由遵循一套严格的逻辑和控制流的程序产生的,非常像自然语言(尽管更结构化和词汇限制)。为此,DeepLog是一个深度神经网络,它使用Long - term Memory (LSTM)[18]对日志条目序列进行建模。这允许DeepLog从正常执行中自动学习日志模式的一个模型,并将正常系统执行的偏差作为异常。此外,由于它是一种学习驱动的方法,因此可以逐步更新DeepLog模型,以便它能够适应随着时间的推移出现的新的日志模式。
挑战。日志数据是非结构化的,它们的格式和语义在不同的系统中可能有很大的差异。即使知道发生了错误,使用非结构化日志诊断问题也已经很困难了[43]; 从海量的日志数据中进行在线异常检测更具挑战性。一些现有的方法使用基于规则的方法来解决这个问题,这需要特定的领域知识[41],例如,使用像“IP地址”这样的特性来解析日志。然而,这并不适用于一般的异常检测,因为它几乎不可能知道在不同类型的日志中什么是有趣的特征(以及防范不同类型的攻击)。
异常检测必须及时,以便用户能够干预正在进行的攻击或系统性能问题[10]。决定将以流媒体的方式做出。因此,需要对整个日志数据进行多次传递的离线方法在我们的设置中不适用[22,39]。我们还希望能够探测到未知类型的异常,而不是针对特定类型的异常。因此,之前使用正常和异常(针对特定类型的异常)日志数据条目来训练用于异常检测的二分类器的工作[44]在此上下文中没有用处。
另一个挑战来自并发。显然,日志中日志消息的顺序为诊断和分析(例如,识别程序的执行路径)提供了重要的信息。但是,在许多系统日志中,日志消息是由几个不同的线程或并发运行的任务产生的。这种并发性使得基于工作流的异常检测方法[42],该方法使用一个工作流模型将将单个任务看作生成模型来匹配日志消息序列, 难以应用。
最后,每个日志消息都包含丰富的信息,比如一个日志键、一个或多个度量值,以及它的时间戳。整合和利用这些不同信息的整体方法将更有效。大多数现有的方法[22,32,39,41,42,44]只分析日志消息的一个特定部分(例如,日志键),这限制了它们可以检测到的异常类型。
我们的贡献。循环神经网络(RNN)是一种人工神经网络,它使用一个环路将上一个状态的输出转发到当前输入,从而跟踪历史进行预测。长短期记忆(Long -term Memory, LSTM)网络[13,18,27]是RNNs 的一个实例,具有记忆序列长期依赖关系的能力。LSTMs 已经证明在各种任务中取得了成功,如机器翻译[35]、情感分析[8]和医疗自我诊断[20]。
我们观察到系统日志中的条目是由结构化源代码执行产生的一系列事件(因此可以被视为一种结构化语言),受此启发,我们设计了DeepLog框架,使用LSTM神经网络对系统日志进行在线异常检测。DeepLog不仅使用日志键,还在日志条目中使用度量值进行异常检测,因此,它能够捕获不同类型的异常。DeepLog只依赖于一个由一个“正常日志条目” 的序列组成的小型训练数据集。在训练阶段,DeepLog可以识别正常的日志序列,并以流的方式对输入的日志条目进行在线异常检测。
直观上,DeepLog 隐式地从与正常系统执行路径对应的训练数据中捕获日志条目之间潜在的非线性和高维依赖关系。为了帮助用户在发现异常后诊断问题,DeepLog还根据训练阶段的日志条目构建工作流模型。DeepLog将并发任务或线程产生的日志条目分成不同的序列,这样就可以为每个单独的任务构建一个工作流模型。
我们的评估表明,在之前的工作[22,39]探索的大型HDFS日志数据集上,DeepLog只训练正常系统执行的日志条目的很小一部分(小于1%),对剩余99%的日志条目几乎可以达到100%的检测精度。一个大型 OpenStack 日志的结果也显示了类似的趋势。此外,DeepLog还可以结合实时用户反馈,在检测阶段逐步更新其权重。更具体地说,如果一个正常的日志条目被错误地归类为异常,DeepLog提供了一种用户反馈机制。DeepLog可以使用这样的反馈来在线动态调整权重,以适应新的系统执行模式(也就是新的日志)。
2 预备知识
2.1 日志解析
我们首先将非结构化的、自由文本的日志条目解析为结构化的表示,这样我们就可以学习这些结构化数据的顺序模型。正如之前的几项工作[9,22,39,42,45]所示,一种有效的方法是从每个日志条目中提取“日志键”(也称为“消息类型”)。日志条目的日志键是指源代码中在代码执行期间打印e的print语句中的字符串常量k。例如,日志条目 e ="Took 10 seconds to build instance." 的日志键k
是 k =Took * seconds to build instance., 它是打印语句 printf("Took %f seconds to build instance.", t). 中的字符串常量。注意,参数(s)在日志键中被抽象为星号(s)。这些度量值反映了底层系统状态和性能状态。某些参数的值可能会作为一个特定执行序列的标识符,例如HDFS日志中的block_id, OpenStack日志中的instance_id。这些标识符可以将日志条目分组在一起,或者将并发进程产生的日志条目整理成单独的单线程顺序序列[22,39,42,45]。最先进的日志解析方法由Spell[9] 表示,这是一个无监督的流式解析器,它基于 LCS(最长公共子序列) 的思想以在线方式解析传入的日志条目。
过去的日志分析工作[22,39,42,44]丢弃了日志条目中的时间戳和/或参数值,只使用日志键来检测异常。DeepLog将每个日志条目e的参数值,以及e与其前一个条目之间的时间间隔存储到一个向量 中。除日志键外,这个向量被DeepLog使用。表1给出了一个示例,它展示了在OpenStack 中执行多轮虚拟机(VM)删除任务的一系列日志条目的解析结果。
表1:OpenStack VM删除任务的日志条目。
2.2 DeepLog架构及概述
DeepLog的架构如图1所示,主要由三部分组成:日志键异常检测模型、参数值异常检测模型和工作流模型来诊断检测到的异常。
图1:DeepLog架构。
训练阶段。DeepLog 的训练数据是来自正常系统执行路径的日志条目。每个日志条目被解析为一个日志键和一个参数值向量。DeepLog 使用从训练日志中解析的日志键序列来训练日志键异常检测模型,并构建用于诊断的系统执行工作流模型。对于每个不同的键 k , DeepLog还训练和维护一个模型,用于检测由这些度量值相关的系统性能异常,由 k 的参数值向量序列训练。
检测阶段。新到达的日志条目被解析为日志键和参数值向量。DeepLog 首先使用日志键异常检测模型来检查输入的日志键是否正常。如果是,DeepLog将使用该日志键的参数值异常检测模型进一步检查参数值向量。如果新条目的日志键或参数值向量被预测为异常,则将其标记为异常。最后,如果被标记为异常,DeepLog的工作流模型为用户提供语义信息来诊断异常。执行模式可能会随着时间的推移而改变,或者不包括在原始的训练数据中。DeepLog还提供了收集用户反馈的选项。如果用户将检测到的异常报告为假阳性,DeepLog可以将其作为标注的记录来增量更新其模型,以合并和适应新的模式。
2.3 威胁模型
DeepLog学习正常系统执行路径产生的日志条目序列中嵌入的全面和复杂的相关性和模式。因此,我们假设系统日志本身是安全的,并且受到保护,对手不能攻击日志本身的完整性。我们还假设对手不能修改系统源代码来更改其日志记录行为和模式。也就是说,一般来说,我们考虑的攻击有两种类型。
(1)导致系统执行错误行为的攻击,从而导致系统日志中的异常模式。例如,拒绝服务(DoS)攻击,它可能导致执行缓慢,从而反映在日志时间戳不同于参数值向量序列的性能异常;导致服务器重复重启的攻击,如BROP攻击[5],显示为服务器重启日志键太多;任何可能导致任务终止的攻击,例如相应的日志序列提前结束和/或异常日志条目出现。
(2)由于系统监控服务的日志记录活动而可能在系统日志中留下痕迹的攻击。入侵检测系统(IDS)记录的可疑活动就是一个例子。
3 异常检测
3.1执行路径异常
我们首先描述如何使用日志键序列检测执行路径异常。由于源代码中不同打印语句(打印日志条目)的总数是常量,因此不同日志键的总数也是常量。令 是来自日志生成系统源代码的一组不同的日志键。
一旦日志条目被解析为日志键,日志键序列就会反映一个执行路径,该路径会导致日志打印语句的特定执行顺序。 表示日志键序列中位于 位置的键的值。显然, 可能从K中获取n个可能的键的一个,并且强烈依赖于 之前出现的最近的键。
我们可以将日志键序列中的异常检测建模为一个多分类问题,其中每个不同的日志键定义一个类。我们在最近的上下文中将DeepLog训练成一个多分类器。输入是最近的日志键的历史记录,输出是来自 K 的n个日志键的概率分布,输出表示 在这个序列中的下一个日志键是 一个键 的概率。
图2总结了分类设置。假设 是将要出现的下一个日志键的序列 。对于分类的输入是一个窗口 w 的 h 最近的日志键。即 ,每个 都在 K 中,是日志条目 的日志键。注意,相同的日志键值可能在 w 中出现多次。训练阶段的输出是一个条件概率分布的模型,对于每个 , 。检测阶段使用该模型进行预测,并将预测的输出与实际出现的观察到的日志键值进行比较。
图2:日志键异常检测模型概述。
训练阶段。训练阶段依赖于底层系统正常执行产生的一小部分日志条目。对于训练数据中每个长度为 h 的日志序列,DeepLog更新其模型,以 作为下一个日志键的概率分布。例如,假设一个正常执行的小日志文件被解析为一个日志键序列: {k22, k5, k11, k9, k11, k26}。给定窗口大小 h = 3,用来训练DeepLog的输入序列和输出标签对将是: {k22, k5, k11→k9}, {k5, k11, k9→k11}, {k11, k9, k11→k26}。
检测阶段。DeepLog 在在线流媒体设置中执行异常检测。为了测试传入的日志键 (从传入的日志条目 解析)是正常还是异常,我们发送 到DeepLog作为它的输入。输出是一个概率分布 描述来自 K 的每个日志键作为给定历史的下一个日志键出现的概率。
在实践中,多个日志键值可能以 的形式出现。例如,如果系统正在连接到一个主机,那么可以是 'Waiting For * to response '或'Connected to *'; 两者都是正常的系统行为。DeepLog必须能够在训练期间学习这样的模式。我们的策略是根据它们的概率 对可能的日志键K进行排序,并将一个键视为正常值,如果它位于前 g 个候选键中。否则,日志键将被视为来自异常执行。
3.1.1 传统的N-gram语言模型
给从固定词汇表中提取的单词序列分配概率的问题是语言建模的经典问题,被自然语言处理(NLP)社区[24]广泛研究。在我们的例子中,每个日志键都可以看作是 k 词汇表中的一个单词。为任意长的序列分配概率的典型语言建模方法是 N-gram 模型。人们的直觉是,一个特定的词在一个序列中只受其最近的前辈的影响,而不是整个历史。在我们的设定中,这个近似等于设定 ,其中 N 表示要考虑的最近历史的长度。
对于训练,我们可以使用来自大型语料库的相对频率计数来计算这个概率,从而给出最大似然估计。给定一长串键 ,我们可以利用相对于 的相对频率计数来估计观察的 i-th 键 的概率。换句话说,。注意,我们将使用大小为 N 的滑动窗口在整个键序列上计算这些频率。
为了在我们的操作中应用N-gram模型,我们简单地使用 N 作为历史窗口的大小,即在我们的实验中使用N-gram模型时,我们设置h = N,其中 h 为历史滑动窗口的大小,如图2所示。我们将此作为基准方法。
3.1.2 LSTM方法
近年来,使用循环神经网络的神经语言模型在各种NLP任务中被证明是非常有效的[3,25]。与 N-gram 语言模型相比,基于LSTM的模型可以编码更复杂的模式,并在序列[34]上维护长期状态。系统日志中并发任务的复杂模式和交错日志条目会降低传统语言模型的效率。DeepLog使用LSTM神经网络[18]对日志键序列进行异常检测。
给定一个日志键序列,训练一个LSTM网络,使 作为下一个日志键值的概率在训练数据序列中最大化。换句话说,它学习了一个概率分布 ,使训练日志键序列的概率最大化。
图3:使用堆叠LSTM的日志键异常检测模型的详细视图。
图3 说明了我们的设计。图的顶部显示了一个单独的LSTM块,它体现了LSTM的循环性质。每个LSTM块将其输入的状态作为一个固定维向量来记忆。上一个时间步的LSTM块的状态也被喂进到它的下一个输入,连同它的(外部)数据输入(在这个特殊的例子中是),以计算一个新的状态和输出。这就是在单个LSTM块中传递和维护历史信息的方式。
一系列LSTM块在一个层中形成循环模型的展开版本,如图3的中心所示。每个 cell 维持一个隐藏向量 和一个细胞状态向量 。它们都被传递给下一个块来初始化它的状态。在我们的例子中,我们为来自一个输入序列 w (一个包含h个日志键的窗口)的每个日志键使用一个LSTM块。因此,一层由 h 个展开的LSTM块组成。
在单个LSTM块中,输入(例如 ) 和之前的输出()被用来决定
(1)有多少之前的细胞状态保留在状态 中,
(2)如何使用当前的输入和之前的输出来影响状态,
(3)如何构造输出。它是通过一组门控函数来完成的,通过控制从输入和前一个输出中保留的信息的数量,以及进入下一个时间步的信息流的数量来确定状态动态。每个门控函数由一组待学习的权值参数化。LSTM块的表达能力由存储单元的数量决定(即隐藏状态向量H 的维数)。由于篇幅限制,我们建议读者使用NLP启蒙书(例如[12])来对LSTMs进行公式化表述。
训练步骤需要对 weights 进行适当的分配,以便 LSTM 序列的最终输出产生所需的标签(输出),该标签来自训练数据集中的输入。在训练过程中,每个输入/输出对通过梯度下降最小化损失来增量地更新这些权值。在DeepLog中,输入由 h 个 日志键的窗口 w 组成,输出是 正好是w后 右边的日志键值,正好是w。我们使用分类交叉熵损失进行训练。
训练完成后,我们可以对输入 使用一层h LSTM块来预测输出。w中的每个日志键提要到该层中相应的LSTM块。
如果我们将多层叠加起来,使用前一层的隐藏状态作为下一层每个对应的LSTM块的输入,它就变成了一个深度LSTM神经网络,如图3的底部所示。为了简单起见,它省略了由标准编码-解码方案构造的输入层和输出层。输入层将K中的n个可能的日志键 编码为one -hot向量。
也就是说,为日志键 构造了一个稀疏的n维向量,使得对于所有其他 , , 。输出层使用标准的多项式逻辑函数来表示每个 的 ,将最终隐藏状态转换为一个概率分布函数。
图3中的示例只显示了两个隐藏层,但可以使用更多层。
3.2 参数值与性能异常(官方代码只实现了 键的 异常检测,就是单层LSTM ......)
日志键序列对于检测执行路径异常非常有用。然而,一些异常并不是显示为偏离正常的执行路径,而是显示为不规则的参数值。这些参数值向量(对于相同的日志键)形成一个参数值向量序列,这些来自不同日志键的序列形成一个多维特征空间,对于性能监控和异常检测非常重要。
基线方法。一种简单的方法是将所有参数值向量序列存储到一个矩阵中,其中每一列都是来自一个日志键 k 的参数值序列(注意,根据参数值向量的大小,k可以有多个列)。这个矩阵的第 i 行表示一个时间实例 。
以表1中的日志条目为例。在本例中有3个不同的日志键值,它们的参数值向量的大小分别为2、2和1。因此,该矩阵中的第1行表示时间实例 ,值为 [t1 - t0, file1Id, null, null, null]。同理,第2行和第3行分别为[null, null,t2 - t1, 0.61, null]和[null, null, null, t3 - t2]。
我们还可以要求每一行表示一个时间实例范围,以便每一行对应该时间范围内的多个日志消息,从而变得不那么稀疏。但当对数键值较多且/或存在较大的参数值向量时,矩阵仍然会非常稀疏。此外,该方法给异常检测过程带来了一定的延迟,并且难以确定每个范围的长度。
有了这个矩阵,可以应用许多著名的数据驱动的异常检测方法,如主成分分析(PCA)和自组织映射(SOM)。它们对于获取不同特征维度之间的相关性非常有用。然而,这种方法在日志数据上下文中的一个主要限制是,在一个特定的时间实例中出现多个日志键的可能性通常是相等的。例如,表1中 k1 和 k2 的顺序是任意的,因为同时运行的任务。这种现象,以及矩阵稀疏的事实,使得这些技术在我们的设置中无效。最后,他们不能建立存在于参数值向量序列中的自相关模型(在单个向量序列中随时间变化的规则模式)。
我们的方法。DeepLog通过将每个参数值向量序列(对于一个日志键)作为一个单独的时间序列来训练一个参数值异常检测模型。
考虑表1中的示例。k2的参数值向量序列的时间序列为: 。因此,我们的问题简化为从多变量时间序列数据进行异常检测。可以再次应用基于LSTM的方法。我们使用类似的LSTM网络(如图3所示)对多变量时间序列数据建模,并进行以下调整。注意,为每个不同的日志键的参数值向量序列构建了一个单独的LSTM网络。
输入。每个时间步的输入只是来自该时间戳的参数值向量。我们用训练数据中相同参数位置的所有值的平均值和标准差对每个向量中的值进行归一化。
输出。输出是一个实值向量,用于根据最近历史的参数值向量序列预测下一个参数值向量。
训练目标函数。对于多变量时间序列数据,训练过程试图调整其LSTM模型的权值,以最小化预测和观测参数值向量之间的误差。我们利用均方损失来减小训练过程中的误差。
异常检测。预测和观测参数值向量之间的差异由均方误差(MSE)来测量。我们将训练数据划分为两个子集:模型训练集和验证集,而不是以一种特别的方式为异常检测提供一个神奇的错误阈值。对于验证集中的每个向量,我们应用训练集产生的模型来计算预测(使用验证集中之前的向量序列)和 之间的MSE。在每一个时间步,验证集的预测向量与实际向量之间的误差均建模为高斯分布。
部署时,如果预测值与观测值向量的误差在上述高斯分布的高可信区间内,则认为输入日志项的参数值向量是正常的,否则认为异常。
由于日志消息中的参数值记录了重要的系统状态度量,该方法能够检测各种类型的性能异常。例如,性能异常可能会被视为“减速”。回想一下,DeepLog将连续日志条目之间的时间间隔存储在每个参数值向量中。上述LSTM模型通过将参数值向量建模为一个多变量时间序列,能够在该时间序列的一个或多个维度上检测异常模式;运行时间值只是这样一个维度。
3.3 在线更新异常检测模型
显然,训练数据可能不会涵盖所有可能的正常执行人员。系统行为可能会随着时间的推移而改变,另外还取决于工作负载和数据特征。因此,DeepLog有必要在其LSTM模型中增量更新权重,以合并和适应新的日志模式。为此,DeepLog为用户提供了一种反馈机制。允许DeepLog使用假阳性来调整权重。例如,假设h = 3,最近的历史序列为 {k1, k2,k3}, DeepLog预测下一个日志键为k1的概率为1,而下一个日志键值为k2,将被标记为异常。如果用户报告这是一个假阳性,DeepLog能够使用以下的输入输出对 {k1, k2, k3 k2} 来更新它的模型的权重来学习这个新的参数。因此,下一次给定历史序列{k1, k2, k3}, DeepLog可以用更新的概率输出k1和k2。同样的更新过程也适用于参数值异常检测模型。注意,DeepLog不需要从头开始重新训练。在初始训练过程中,DeepLog中的模型以多个多维权重向量的形式存在。更新过程输入新的训练数据,并调整权重,使模型输出与假阳性情况下的实际观测值之间的误差最小化。
待续。。。