【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs

Detecting Large-Scale System Problems by Mining Console Logs

Friday, August 9, 2019 9:14 AM

通过挖掘控制台日志来检测大型系统的问题

Wei Xu∗ Ling Huang† Armando Fox∗ David Patterson∗ Michael I. Jordan∗

∗EECS Department  †Intel Labs Berkeley

 University of California at Berkeley, USA   Berkeley, CA, USA

{xuw,fox,pattrsn,jordan}@cs.berkeley.edu  [email protected]

摘要:令人惊讶的是,控制台日志很少帮助操作人员检测大型数据中心服务中的问题,因为它们通常由独立开发人员编写的许多软件组件的大量混合消息组成。我们提出了一种通用的方法来挖掘这个丰富的信息源来自动检测系统运行时问题。我们首先通过结合源代码分析和信息检索来解析控制台日志,以创建复合特性。然后,我们使用机器学习来分析这些特性,以检测操作问题。我们展示了我们的方法能够实现以前方法无法实现的分析,因为它具有创建复杂特性的优越能力。我们还展示了如何将分析结果提取到一个操作符友好的单页决策树中,该决策树显示与检测到的问题相关的关键消息。我们使用Darkstar在线游戏服务器和Hadoop文件系统验证了我们的方法,在该系统中,我们以高精度和很少的误报来检测大量的实际问题。在Hadoop的例子中,我们能够在3分钟内分析2400万行控制台日志。我们的方法工作在任何大小的文本控制台日志上,不需要修改服务软件,不需要人工输入,也不需要了解软件的内部结构。

1.引言

       当由运行在数千台计算机上的数百个软件组件组成的数据企业规模的服务出现问题时,开发人员-操作人员需要他们可以使用的所有工具来排除和诊断操作问题。具有讽刺意味的是,几乎每个软件中都内置了一个信息源,它提供了反映原始开发人员对值得注意的或不寻常事件的想法的详细信息,但通常被忽略:不起眼的控制台日志。

       自编程诞生以来,开发人员使用了从printf到复杂的日志记录和监视库[8,9]等各种方法来记录程序变量值、跟踪执行、报告运行时统计数据,甚至打印出那些被设计供人类阅读的完整语句消息(通常由开发人员自己阅读)。然而,现代大型服务通常将由数百名开发人员编写的大型开放源码组件组合在一起,而负责处理日志的人员(部分集成人员、部分开发人员、部分操作人员)通常不是选择日志内容或原因的人员。(我们将使用主题操作员来表示一组潜在的不同人员,他们试图检测操作问题)。此外,即使在经过良好测试的代码中,许多操作问题也依赖于部署和运行时环境,开发人员无法轻松地重现这些问题。更糟的是,现代系统集成了经常修改或升级的外部组件(通常是开源的),这可能会改变日志中的内容或某些消息的相关性。这样的流失率加剧了运营商的困境。我们的目标是为他们提供更好的工具来从控制台日志中提取值。

       由于日志太大,无法手动检查[14,22],而且过于非结构化,无法自动分析,操作人员通常创建特殊脚本来搜索诸如“error”或“critical”之类的关键字,但这已被证明不足以确定问题[14,22]。基于规则的处理[24]是一种改进,但是操作人员对特定组件及其交互缺乏详细的知识,这使得编写规则来挑选最相关的事件集进行问题检测变得非常困难。我们不要求用户进行搜索,而是提供自动查找“有趣的”日志消息的工具。

       由于异常日志消息通常表示问题的根源,因此将日志分析形式化为机器学习中的异常检测问题是很自然的。但是,并不总是某一种消息的存在、缺失或出现频率就足以查明问题所在;更常见的情况是,问题表现为不同类型日志消息(相关性、相对频率等)之间关系的异常。因此,我们不是分析文本日志中的单词(例如,在[27]中),而是创建能够准确捕获日志消息之间的各种相关性的特性,并对这些特性执行异常检测。创建这些特性需要使用有关源代码的信息增加日志解析;我们提出的这种增强方法是我们贡献的一部分。

       我们研究了Internet服务中使用的许多流行软件系统的日志和源代码,发现典型的控制台日志的结构比它看起来的要复杂得多:它的“模式”的定义隐含在日志打印语句中,可以从程序源代码中发现。这个观察结果是我们的日志解析方法的关键,它产生了详细而准确的特性。考虑到开源软件在许多Internet系统中无处不在,我们认为对源代码的需求并不是我们方法的实际缺陷。

       我们的贡献是一个通用的四步方法,它允许将机器学习和信息检索技术应用到自由文本日志中,从而在不需要任何手工输入的情况下找到可能指示操作问题的关键,即"大海捞针"。具体来说,我们的方法包括以下四项贡献:

       1)一种分析源代码以发现控制台日志固有结构的技术;

       2)识别日志中的公共信息——状态变量和对象标识符——以及从日志中自动创建特征(利用发现的结构),这些特征可以通过各种机器学习算法进行分析;

       3)论证一种机器学习和信息检索方法,能够有效地检测从控制台日志中提取的大量特征的异常模式或异常问题;

       4)在适当的情况下,自动构建可视化程序,该程序将异常检测结果提炼成紧凑的、操作人员友好的格式,假设不了解用于分析特征的算法的细节。

       我们方法中的元素组合,包括源代码分析与日志分析的新颖组合以及异常检测功能的自动创建,使得日志分析中的细节水平在以前由于方法无法正确识别而无法实现的问题得以解决。

       我们的方法不需要对现有软件进行任何更改,并且可以处理任何大小的现有文本控制台日志,并且一些计算成本更高的步骤令人尴尬地并行,允许我们使用云计算将它们作为Hadoop[2] map-reduce作业运行,实现近乎线性的加速,每次运行仅几美元。。

       我们评估了我们的方法,并通过两个实际系统演示了它的能力和可伸缩性:Darkstar在线游戏服务器[28]和Hadoop文件系统。对于Darkstar,我们的方法能够在性能异常发生后立即准确地检测到它们,并提供有关根本原因的提示。对于Hadoop,我们检测通常被忽略的运行时异常,并将超过2400万行控制台日志(收集自203个Hadoop节点)提取为一个领域专家能够容易理解的单页决策树。这个自动化过程可以在3分钟内通过Hadoop map-reduce在60个Amazon EC2节点上完成。

       第二节是概述方法,第三节将详细描述我们的日志解析技术,第四节和第五节提出我们的解决方案:创建和异常检测功能,第六节评估我们的方法并讨论了可视化技术,第七节讨论了扩展和提供建议来提高日志质量,第八节总结相关工作,第九节为结论。

2.方法概述

2.1埋藏在文本日志中的信息

       重要的信息隐藏在数百万行无格式文本控制台日志中。为了自动分析日志,我们需要创建高质量的特性,即日志信息的数值表示,这是机器学习算法可以理解的。以下三个关键的观察结果导致了我们对这个问题的解决。

       源代码是日志的“模式”。尽管控制台日志以自由文本的形式出现,但它们实际上是非常结构化的,因为它们完全是由系统中相对较小的一组日志打印语句生成的。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第1张图片

       考虑图1中的简单控制台日志摘录和生成它的源代码。直观地说,使用源代码信息(特别是对于机器)更容易发现日志隐藏的“模式”。我们的方法利用源代码分析来恢复日志的继承结构。我们的方法最大的优点是能够准确地解析所有可能的日志消息,即使是在实际日志中很少看到的消息。此外,我们能够使用现有解决方案消除日志解析的大多数启发和猜测。

       共同的日志结构表明有用的特性。通常,开发人员将图1中的日志消息作为一个常量部分(starting: xact ... is和多个可变部分(325/326 and COMMITTING/ABORTING)。本文将常量部分称为消息类型,变量部分称为消息变量。

       消息类型(在日志消息中由常量字符串标记)对于分析控制台日志非常重要,并且在早期的工作[17]中得到了广泛的应用。在我们的分析中,我们仅使用常量字符串作为消息类型的标记,完全忽略了它们作为英语单词的语义,这是众所周知的歧义性[22]。

       消息变量也包含重要的信息。与之前专注于数值变量的工作[17、22、35]不同,我们通过研究许多系统的日志和访问大量使用控制台日志的Internet服务开发人员/操作人员,确定了两种用于问题检测的重要消息变量类型。我们承认日志还包含其他类型的消息变量,如时间戳和各种计数。我们在本文中不讨论这些变量,因为它们已经在现有的工作[27]中得到了很好的研究。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第2张图片

       标识符变量用于识别一个物体被程序(例如,图1中的事务id 325和346),而状态变量标签,则列举程序中一组可能的状态对象(例如图1中COMMITTING和ABORTING)。表1还提供了这样的变量的额外例子。我们可以根据给定变量在控制台日志中的频率来确定它是标识符还是状态变量。直观地说,状态变量有少量不同的值,而标识符有大量不同的值(详细内容见第4节)。

       消息类型和变量包含对操作员有用的重要运行时信息。然而,由于缺少提取这些结构的工具,操作人员要么忽略它们,要么花费数小时进行greping并手动检查日志消息,这既单调又低效。

       准确的日志解析允许我们使用结构化的信息,例如消息类型和变量,来自动创建捕获日志中传递的信息的特性。据我们所知,这是第一个从控制台日志中提取这种细粒度级别的信息用于问题检测的工作。

       消息是紧密相关的。当正确地对日志消息进行分组时,同一组内的消息之间具有很强且稳定的相关性。例如,包含特定文件名的消息可能高度相关,因为它们可能来自程序中逻辑相关的执行步骤。

       一组相关的消息通常比单个消息更能反映问题。许多异常仅由不完整的消息序列表示。例如,如果对文件的写操作无声地失败(可能是因为开发人员没有正确地处理错误),那么可能没有一条错误消息表明失败。但是,通过将关于同一文件的消息关联起来,我们可以通过观察预期的“关闭文件”消息丢失来检测这种情况。以往的工作仅根据时间窗对日志进行分组,检测精度受相关噪声影响[14,27,35]。相反,我们根据更精确的信息创建消息组,比如上面描述的消息变量。这样,相关性更强,更容易编码,因此异常相关性也更容易检测。

2.2我们方法的工作流程

       图2显示了挖掘控制台日志的通用框架中的四个步骤:

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第3张图片

        1)日志解析。我们首先将日志消息从非结构化文本转换为数据结构,该数据结构以(名称、值)对的形式显示消息类型和消息变量列表。我们从源代码获取所有可能的日志消息模板字符串,并将这些模板匹配到每个日志消息,以恢复其结构(即消息类型和变量)。实验表明,该方法在实际系统中具有较高的解析精度。

       有些系统只使用结构化跟踪,比如BerkeleyDB (Java edition)。在这种情况下,由于日志已经结构化,我们可以跳过第一步,直接应用我们的特性创建和异常检测方法。注意,这些结构化日志仍然包含标识符和状态变量1

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第4张图片

 

       事实上,表2中的最后一个系统(存储原型)是一个匿名研究原型,带有内置的自定义结构化跟踪。在没有任何上下文的情况下,甚至在不了解系统功能的情况下,我们的特性创建和异常检测算法成功地发现了开发人员认为有洞察力的日志段。

       2)特征创造。第二步,通过选择合适的变量并对相关信息进行分组,从提取的信息中构造特征向量。本文重点研究了状态比向量和消息计数向量特征的构造,这些特征在以前的工作中没有得到充分的利用。在我们对两个大型真实世界系统的实验中,这两个特征都得到了很好的检测结果。

       3)异常检测。然后我们将异常检测方法应用于特征向量的挖掘,将每个特征向量标记为正常或异常。我们发现基于主成分分析(PCA)的异常检测方法[5]对这两种特征都有很好的检测效果。该方法是一种无监督学习算法,在该算法中,所有参数都可以自动选择,也可以很容易地进行调优,不需要操作者事先输入。虽然我们在案例研究中使用了这种特定的机器学习算法,但它并不是我们方法的固有特性,而且使用不同提取特征的不同算法可以很容易地“插入”到我们的框架中。

       4)可视化。最后,为了让系统集成商和操作人员更好地理解PCA异常检测结果,我们将结果可视化到决策树[34]中。与基于pca的检测器相比,决策树以类似于系统集成商和操作人员熟悉的事件处理规则[10]的形式,更详细地解释了如何检测问题。

2.3案例研究与数据收集

       我们研究了22个广泛部署的开源系统的源代码和日志。表2总结了结果。尽管这些系统本质上是不同的,由不同的开发人员在不同的时间用不同的语言开发,但是22个系统中有20个使用免费的文本日志,我们基于源代码分析的日志解析适用于所有20个系统。有趣的是,我们发现大约1%-5%的代码行记录了大多数系统中的调用,但是这些调用很少被执行,因为它们表示错误的执行路径。使用如此大量不同的logger调用手动维护日志解析规则几乎是不可能的,这突出了我们从源代码自动发现消息类型的优势。平均而言,一条消息只报告一个变量。然而,有许多消息,例如启动服务器没有报告变量,而其他消息可以报告10个或更多。

       大多数C程序使用printf样式的格式字符串进行日志记录,尽管大部分程序使用包装器函数来生成标准信息,比如时间戳和严重性级别。即使定制了这些包装器,也可以通过格式字符串参数自动检测。相反,Java程序通常使用字符串连接来生成日志消息,并且常常依赖于标准的日志程序包(如log4j)。分析这些日志调用需要理解数据类型,我们将在第3节中详细介绍。我们基于源代码分析的日志解析方法成功地在大多数系统上工作,并且可以在表2中的22个系统中找到至少一个状态变量和标识符(其中16个同时具有),这证实了我们对它们的普遍程度的假设。

       为了简明扼要地揭示控制台日志挖掘中的重要问题,我们将进一步讨论表2中所示的两个代表性系统:Darkstar在线游戏服务器和Hadoop文件系统(HDFS)。这两个系统都处理持久性,这是大型Internet服务中一个重要而复杂的功能。然而,这两个系统在本质上是不同的。Darkstar专注于小型、时间敏感的事务,而HDFS则是一个用于存储大型文件和批处理的文件系统。它们代表了两个主要的开源贡献者(分别是Sun和Apache),具有不同的编码和日志风格。

       我们收集了运行在Amazon弹性计算云(EC2)上的系统的日志,并使用EC2分析这些日志。表3总结了我们使用的日志数据集。Darkstar的例子揭示了一种严重依赖于部署环境的行为,这导致了从传统服务器场景迁移到云环境的问题。特别是,我们发现Darkstar没有优雅地处理云计算环境中常见的性能变化。通过分析控制台日志,我们找到了这个问题的原因,如6.2节所详细讨论的。

       在满足Darkstar结果的基础上,为了进一步评价我们的方法,我们分析了更为复杂的HDFS日志。我们从运行在200多个EC2节点上的Hadoop集群中收集HDFS日志,生成2400万行日志。在确定Hadoop开发人员已经确认的运行时性能问题时,我们成功地提取了日志片段。

       所有日志数据都是从未经修改的脱机系统中收集的。控制台日志被直接写入每个节点上的本地磁盘,并通过简单地复制日志文件离线收集,这显示了我们的日志挖掘方法的便利性(没有检测或配置)。在HDFS实验中,我们使用默认的日志记录级别,而在Darkstar实验中,我们打开调试日志记录(日志框架中的更细级别)。

3.日志解析与源代码

       除了控制台日志中的标准“字段”(如时间戳)之外,我们还关注日志消息的免费文本部分。对于图1顶部的日志摘录,人类读者会合理地得出结论,325、346、COMMITTING和ABORTING是消息变量,其余是标记消息类型的常量字符串。然后,他们可以编写一个正则表达式,如start: xact (.*) is(.*)来对这些日志消息进行“模板化”。我们想要自动化这个过程。

       困难。除非日志本身用格式标记来区分这些元素,否则我们必须自动“模板化”。正如第2.1节所讨论的,对于机器来说,将源代码用作控制台日志的“模式”要容易得多。如果软件是类似C语言编写的,很可能的模板可以直接推断printf变异生成消息,如fprintf(LOG,“starting:xact % d % s”),与各种转义(% d % f,等等)告诉我们一些关于变量的类型。然而,在面向对象(OO)语言中,如Java,它更具挑战性,因为Java越来越多地用于开源软件(表2)。显然,txn对象的tid变量对应于图1的日志消息中的标识符325和346,而state变量对应于COMMITTING和ABORTING的标签。尝试通过简单地“grepping”源代码来提取正则表达式,只会得到start:(.*)(第1行),它没有将tid和state区分为具有不同可能值范围的独立特性。至关重要的是,正如我们稍后将展示的,我们需要这种更精细的特性解析来发现“有趣的”问题。

       在OO语言中出现这种困难有三个原因。首先,我们需要知道CLog标识一个logger对象;也就是说,仅知道logger类的名称是不够的。其次,用于打印的OO习惯用法是让对象实现toString()方法,该方法返回自身的可打印表示形式,以便插入到字符串中;在本例中,抽象类型事务的toString()方法实际上揭示了日志消息的底层结构。第三,由于类继承,在特定调用中使用的实际toString()方法可能定义在一个子类中,而不是logger对象的基类中。

       我们的解析方法。这三个原因都是由日志解析方法解决的,该方法由两个步骤组成:静态源代码分析步骤运行时日志解析步骤,如图3所示。特别是,我们并不声称能够正确地处理每种情况(尽管对语言习惯用法提供了广泛的支持),但是我们确实表明,我们的结果中使用的一些重要特性不能使用现有的日志解析技术提取。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第5张图片

       静态源代码分析步骤将程序源代码(可能还有记录器类的名称)作为输入。在此步骤中,我们首先生成源代码的抽象语法树(AST)[1],这是一种用于遍历和分析源代码的流行数据结构。我们使用构建在开源Eclipse IDE[25]中的AST实现。我们使用AST来标识类(或它们的子类)对象上的所有方法调用,并记录调用的文件名和行号。每个调用只给我们一个部分消息模板,因为模板可能涉及插入非原始类型的对象,如图1中摘录的源代码的第1行所示。然后,我们枚举所有类中的所有toString()调用,并查看这些调用中的字符串格式化语句,以推断消息模板中变量的类型,将此类型信息替换回部分模板中。我们递归地这样做,直到所有模板只插入基本类型;如果在继承路径的任何位置都找不到一个特定变量的toString()方法,那么我们假设该变量可以接受任何字符串值,并且不做进一步的语义解释。该过程的输出是完整的消息模板,其中的数据结构包含每个消息的模板(正则表达式)、源代码中的位置以及消息中出现的所有变量的名称和数据类型。我们将在附录A中详细描述模板提取方法。

       要解析日志,我们首先将所有消息模板编译成Apache Lucene[11]反向索引[20],这允许我们快速地将任何日志消息与相应的模板关联起来。遵循日志分析中已建立的启发式[17,30],我们通过删除所有数字和特殊符号,从每个日志消息构造索引查询。从反向索引搜索返回的相关度排序的候选结果列表中,我们选择排名最高的结果,该结果允许正则表达式匹配成功地匹配日志消息。我们注意到,一旦构造了反向索引(它通常适合内存),解析步骤就会并行执行;我们将其实现为Hadoop map-reduce作业,方法是将索引复制到每个worker节点,并在worker之间分区日志,从而实现近乎线性的加速。map阶段执行反向索引搜索;reduce阶段处理取决于要构造的特性,第4节给出了两个示例。

       总而言之,与现有的日志解析方法不同,我们的方法显示的结构的细粒度支持传统上仅使用结构化日志才能进行的分析。第7节讨论了源代码分析和日志解析中的许多内在细微之处。

4.特征创建

       本节描述从已解析的日志构造特性的技术。我们根据状态变量和标识符分别关注两个特性,状态比向量消息计数向量(参见2.1节)。状态比向量能够捕获系统在一个时间窗口内的聚合行为。消息计数向量有助于检测与单个操作相关的问题。这两个特性都描述了构建在其成员之间具有很强相关性的消息组。这些特性忠实地捕获了这些相关性,这些相关性通常是运行时问题的良好指示器。虽然这些特性来自相同的日志,并且在结构上相似,但是它们是独立构造的,并且具有不同的语义。

4.1状态变量和状态比向量

       状态变量可以出现在大部分日志消息中。事实上,来自Hadoop的32%的日志消息和来自Darkstar的28%的消息包含状态变量。

       在许多系统中,在正常执行期间,一个时间窗口中状态变量的每个值的相对频率通常保持不变。例如,在Darkstar中,在正常执行期间,ABORTING和COMMITTING之间的比率非常稳定,但是当出现问题时,这一比率会发生显著变化。注意,实际的数字并不重要(因为它取决于工作负载),但是不同值之间的比例很重要。

       我们创建状态比向量y以编码这种相关性:每个状态比率向量表示时间窗口中的一组状态变量,而向量的每个维度对应于不同的状态变量值,维度的值是该状态值在时间窗口中出现的次数。在创建基于状态变量的特性时,我们使用了一个自动过程,该过程结合了两个需求:1)应该经常报告消息变量,但是2)它们应该在不依赖于消息数量的少量常量值之间变化。具体来说,在我们的实验中,我们选择了至少报告0.2N次的状态变量,其中包含N条消息,并且对于N值较大的情况(例如,超过几千条),状态变量中有许多不同的值不随N增加。我们的结果对0.2的选择不敏感。

       时间窗口大小也会自动确定。目前,我们选择的大小允许变量在80%的时间窗口中出现至少10D次,其中D是不同值的数量。这种时间窗口的选择允许变量在每个窗口中出现足够多的次数,从而使[4]的计数具有统计意义,同时保持时间窗口足够小,以捕获瞬态问题。我们尝试了10和80%以外的其他参数,没有发现检测结果有显著变化。

      我们将m个时间窗的所有n维y向量进行叠加,构造m×n状态比矩阵。

4.2标识符和消息计数向量

       标识符在日志中也很常见。例如,HDFS日志中几乎50%的消息包含标识符。我们注意到,所有报告相同标识符的日志消息都传递关于标识符的一条信息。例如,在HDFS中,当分配、写入、复制或删除一个块时,会有多个关于该块的日志消息。通过对这些消息进行分组,我们得到了消息计数向量,它类似于执行路径[8](来自自定义插装)。

       为了形成消息计数向量,我们首先自动发现标识符,然后将具有相同标识符值的消息分组在一起,并为每个组创建一个向量。每个向量维度对应于不同的消息类型,该维度的值表示该类型的消息在消息组中出现了多少条。

       该特征的结构类似于信息检索[6]中的词包模型。在我们的应用程序中,“document”是消息组。向量的维由跨所有组的所有有用消息类型的组合(类似于所有可能的“terms”)组成,维的值是组中相应消息类型出现的次数(对应于“term frequency”)。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第6张图片

       算法1总结了我们构建特征的三个步骤。现在我们尝试在这个算法的设计选择背后提供直觉。在算法的第一步中,我们自动选择标识符(我们不想要求操作符指定搜索键)。直观的感觉是,如果一个变量满足算法1的步骤1中的三个条件,那么它很可能标识事务之类的对象。标识符的频率/不同值模式与其他变量非常不同,因此很容易发现标识符2。在所有的数据集中,我们几乎没有错误的选择,并且通过手工检查,可以很容易地消除少量的错误选择。

       与状态变量一样,标识符被选择为至少0.2N次报告的变量,其中N是消息总数。我们还要求变量至少有0.02N个不同的值,并在至少5个不同的消息类型中报告。

       在第二步中,消息组本质上描述了一个执行路径,有两个主要区别。首先,并非每个处理步骤都必须在控制台日志中表示。由于日志记录点是由开发人员手工选择的,因此可以合理地假设日志记录的步骤对于诊断非常重要。其次,由于许多计算机的时钟不同步,无法保证跨多个节点对消息进行正确排序。这种排序对于诊断与同步相关的问题可能是一个问题,但是对于识别许多类型的异常仍然很有用。

        在第三步中,我们使用单词包模型[6]来表示消息组,因为:1)它不需要在术语(消息类型)之间进行排序,2)在文档排序中赋予不寻常术语更多权重。在我们的例子中,罕见的日志消息确实可能更重要。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第7张图片

4.3实现特征创建算法

       为了提高map-reduce中特征生成算法的效率,我们对实现进行了定制。发现状态变量和/或标识符的步骤(第4.1和4.2节中的第一个步骤)是一个mapreduce作业,它计算所有变量的不同值的数量,并确定在进一步的特性生成步骤中包含哪些变量。从变量构造特性的步骤是另一个map-reduce作业,其中日志解析作为map阶段,消息分组作为reduce阶段。对于状态比率,我们根据时间戳对消息进行排序,而对于消息计数向量,我们根据标识符值进行排序。请注意,map阶段(解析步骤)只需要输出所需的数据,而不需要输出整个文本消息,这在减少之前的数据洗牌和排序过程中节省了大量I/O。与解析时间相比,特性创建时间可以忽略不计。

5.异常检测

       我们使用异常检测方法来发现日志中的异常模式。通过这种方式,我们可以自动找到最有可能指出问题的日志段。利用所构造的特征矩阵,可以利用离群点检测方法来检测日志中所包含的异常。我们研究了各种这样的方法,发现主成分分析(PCA)[5,16]结合信息检索中的项加权技术[23,26],在两种特征矩阵上都能得到很好的异常检测结果,而不需要太多的参数调整。

       PCA是一种统计方法,通过自动选择一组反映原始坐标间协变的坐标(主要组件)来捕捉高维数据中的模式。我们使用PCA来分离特征向量中的重复模式,从而使异常消息模式更容易检测。PCA在特征向量个数上具有运行时线性;因此,检测可以扩展到大型日志。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第8张图片

6.评价与可视化

       我们首先展示了日志解析方法(第6.1节)所实现的准确性和可伸缩性,然后讨论了我们在这两个实际系统中的经验。我们开始了使用Darkstar进行问题检测的实验,其中两个特性都给出了简单但有洞察力的结果(第6.2节)。对这些结果满意之后,我们将我们的技术应用到更复杂的HDFS日志中。我们还实现了较高的检测精度(章节6.3)。但是,对于系统操作员和开发人员来说,结果不太直观,因此我们开发了一个决策树可视化方法,该方法将PCA检测结果总结为一个单一的、直观的图(第6.4节),这对操作员更友好,因为该树类似于基于规则的事件处理系统操作员使用的[10]。

6.1日志解析的准确性和可伸缩性

       准确性。如表6所示,我们的日志解析方法在两个系统上都达到了99.8%以上的精度。具体来说,我们的技术成功地处理了罕见的消息类型,即使是那些在HDFS中超过2400万条消息中只出现两次的消息类型。相反,基于词频的控制台日志分析工具,如SLCT[32],不能发现我们在本文中使用的任何一个特性。状态变量太常见以至于不能仅通过单词频率与常量字符串分离。此外,这些工具忽略了构造消息计数向量所需的所有稀疏消息。

        只有少数几种消息类型是解析器无法处理的。几乎所有这些消息都包含长字符串变量。这些长字符串可能会淹没我们正在搜索的常量字符串,从而阻止反向索引搜索找到正确的消息模板。然而,这些消息通常出现在系统(或子系统)的初始化或终止阶段,此时系统的状态被转储到控制台。因此,我们没有看到丢失这些消息对我们的检测结果有任何影响。我们认为解析方法的准确性是至关重要的;只有使用准确的解析系统,我们才能从文本日志中提取状态变量和标识符(特征构造的基础)。因此,考虑到我们的技术产生的高质量解析结果,我们认为访问源代码的需求是一个很小的代价(特别是考虑到许多模块是开源的)。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第9张图片

       可伸缩性。我们使用不同数量的EC2节点评估了日志解析方法的可伸缩性。结果如图5所示:我们的日志解析和特征提取算法几乎是线性扩展的,最多可扩展到50个节点。尽管我们在48小时内解析了由200个HDFS节点生成的所有消息(使用积极日志记录),但是对于50个节点,日志解析只需要不到3分钟,对于10个节点,解析需要不到10分钟。当我们使用超过60个节点时,索引分发和作业调度的开销将决定运行时间。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第10张图片

6.2 Darkstar实验结果

       如第2.3节所述,我们观察到在性能干扰期间在诸如EC2的云计算环境中部署Darkstar服务器时的高性能(即,客户端响应时间)可变性,尤其是对于CPU争用。我们想看看是否能够仅从控制台日志就理解这种高性能可变性的原因。实际上,我们不熟悉Darkstar,所以我们的设置是现实的,因为操作人员通常对系统内部知之甚少。

       在实验中,我们在单个节点上部署了一个未经修改的Darkstar 0.95分布(因为我们使用的Darkstar版本只支持一个节点)。默认情况下,Darkstar不会记录太多日志,所以我们打开了debuglevel日志记录。我们部署了一个由Darkstar团队提供的简单游戏DarkMud,并创建了一个工作负载生成器,该生成器模拟DarkMud虚拟世界中的60个用户客户端执行随机操作,比如翻转开关、拾取和丢弃物品。客户机模拟器记录每个操作的延迟。我们进行了4800秒的实验,并通过将可用于Darkstar的CPU限制在时间1400到1800的正常水平的50%来注入性能干扰。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第11张图片

       通常,异常状态比可能是性能下降的原因、症状或后果。在Darkstar的情况下,这个比率反映了问题的原因:当系统性能变差时,Darkstar不会相应地调整事务超时,这会导致许多正常事务被中止并重新启动,从而导致系统的负载进一步增加。

       注意,在这种情况下,传统的基于grep的方法没有帮助,原因有二:1)作为Darkstar的普通用户,在不了解其内部的情况下,事务状态是模糊的实现细节。因此,用户很难从要搜索的许多变量中选择正确的变量。相反,我们系统地发现和分析了所有状态变量。2)由于Darkstar中使用的乐观并发模型,即使在正常的操作时间内也会发生ABORTING,其中中止用于处理访问冲突。捕获问题的不是单个ABORTING消息,而是ABORTING与state变量的其他值的比值。

       整个实验过程中,通道id变量没有出现异常,说明通道id变量与该性能异常无关。该结果与状态比向量检测结果一致。在控制台日志中,通常有几个不同的信息片段描述相同的系统行为。这一共性为今后的研究指明了一个重要方向:利用多源学习算法,将多个检测结果结合起来,进一步提高精度。

6.3 Hadoop实验结果

       与Darkstar相比,HDFS的规模更大,逻辑更复杂。在本实验中,我们可以自动发现HDFS中的许多异常行为。我们在203个EC2节点上设置Hadoop集群,运行Hadoop map-reduce示例作业48小时,生成并处理超过200TB的随机数据,从而生成HDFS日志。我们从HDFS收集了超过2400万行日志。

       为了进一步验证我们的结果,我们手工标记了每个不同的消息向量,不仅将它们标记为正常或异常,还确定了每个向量的问题类型。标记是通过仔细研究HDFS代码和咨询本地Hadoop专家完成的。在下一节中,我们将展示决策树可视化帮助我们自己和Hadoop开发人员理解我们的结果。我们强调,这个标记步骤只是为了验证我们的方法—当使用我们的技术时,这不是必需的步骤。标记50万个向量是可能的,因为许多向量是完全相同的。事实上,只有680个不同的向量,这证实了我们的直觉,即大多数块都经过一个公共的执行路径。

       表7为手动标签和检测结果。我们看到PCA检测器可以检测到数据中很大一部分异常,当我们使用TF-IDF对数据进行预处理时,可以得到显著的改善,这证实了我们在第5节中所预期的结果。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第12张图片

       在整个实验过程中,我们没有遇到任何灾难性的失败; 因此,表7中列出的大多数问题仅影响性能。

       表7中的第一个异常发现了一个长期隐藏在HDFS中的错误。 在某个(相对罕见的)代码路径中,当一个块被删除时(由于临时的过度复制),namenode上的记录在下一次写入块之前不会更新,导致文件系统相信一个副本, 不再存在,导致后续块删除失败。 Hadoop开发人员最近证实了这个错误。 这种异常很难找到,因为没有单一的错误消息表明问题。 但是,我们发现它是因为我们分析异常执行路径。

       我们还注意到,在传统的基于grep的日志分析中,我们没有引起混淆的问题。在HDFS datanode日志中,我们可以看到许多类似于#:Got Exception while serving # to #:#的消息。根据Apache issue tracking (jira) HADOOP-3678,这是HDFS的一种正常行为:当HDFS客户机在停止读取整个块之前没有完成时,HDFS数据节点生成异常。这些异常消息让许多用户感到困惑,正如Hadoop用户邮件列表上的多个讨论主题说明了这一点。虽然传统的关键字匹配(例如搜索Exception或Error之类的单词)会将这些标记为错误,但是我们的消息计数方法成功地避免了这个假阳性,因为这种情况发生的次数太多,不可能是异常。

       我们的算法确实报告了一些误报,这在任何无监督学习算法中都是不可避免的。例如,表7中的第二个假阳性是因为少数块被复制了10次,而不是大多数块被复制了3次。这些消息组看起来可疑,但是Hadoop专家告诉我们,当map-reduce系统向所有节点分发作业配置文件时,这些都是正常的情况。与数据访问相比,这种情况确实很少见,但在系统设计中是正常的。消除这种“罕见但正常”的假阳性需要领域专家知识。作为一个未来的方向,我们正在研究半监督学习技术,它可以获取操作员的反馈,并进一步改进我们的结果。

       检测状态比率向量。 我们的特征生成算法在HDFS日志中选择的唯一状态变量是节点名称。 节点名称可能听起来不像状态变量,但由于节点集(总共203个)在HDFS中相对固定,并且它们的名称符合4.1节中描述的状态变量标准。 因此,状态比向量特征减少到每个节点活动计数,这是在现有工作中充分研究的特征[12,17]。 与之前的工作一样,我们能够检测瞬态工作负载不平衡以及节点重启事件。 但是,我们的方法不那么特别,因为状态比率特征是根据控制台日志中的信息自动选择的,而不是手动指定的。

6.4 用决策树实现检测结果可视化

        从操作员的角度来看,PCA底层的转换是一个黑箱算法:它没有对检测结果提供直观的解释,也不能查询。人工操作人员需要手动检查异常以了解根本原因,而PCA本身在这方面提供的帮助很少。在本节中,我们将展示如何使用决策树增强基于PCA的检测,从而使操作人员更容易理解和操作结果。决策树的结果类似于许多系统事件处理程序[10]中使用的(手工编写的)规则,因此对于非机器学习专家来说更容易。这种技术对于具有许多维度的特性特别有用,比如HDFS中的消息计数向量特性。

       决策树在分类中得到了广泛的应用。由于决策树构造工作在输入数据的原始坐标下,其分类决策往往易于形象化和理解[34]。构建决策树需要一个带有类标签的训练集。我们使用自动生成的PCA检测结果(正常与异常)作为类标签,这与通常使用决策树不同。我们的决策树是用来解释检测算法的底层逻辑的,而不是用来解释数据集的本质。

【PaperReading】Detecting Large-Scale System Problems by Mining Console Logs_第13张图片

       图7是使用RapidMiner[21]从HDFS日志异常检测结果生成的决策树。它清楚地显示了最重要的消息类型。例如,第一个级别显示,如果块地图(保存块位置的数据结构)更新超过3次,则为异常。这说明存在过度复制问题(表7中为异常4或假阳性1)。第二级表示,如果一个块接收次数不超过2次,则为异常;这表明复制不足或块写失败(表7中的异常2和异常3)。决策树的级别3与我们在6.3节中讨论的错误有关。

       综上所述,使用决策树对结果进行可视化,可以帮助操作人员和开发人员发现异常行为的类型,而不是单个异常事件,这可以大大提高查找根源和预防未来报警的效率。

7.讨论

       我们应该用结构化跟踪完全替换控制台日志吗?有各种各样的这样的努力[8,29]。然而,进展一直很缓慢,主要是因为没有一个标准来支持所有开放源码开发人员都接受的结构化跟踪。设计一个全局“模式”来以结构化格式容纳控制台日志中包含的所有信息在技术上也是困难的。即使存在这样的标准,手动地将所有遗留代码移植到模式中也是非常昂贵的。自动将遗留日志代码移植到结构化日志中(syslog没有结构化,因为它大量使用自由文本字段)并不比我们的日志解析简单。我们的特征创建和异常检测算法不需要在只有结构化跟踪的系统中进行日志解析,我们在2.2节中描述了一个成功的例子。

       改善控制台日志。我们发现了一些不好的日志记录实践,这些实践大大降低了控制台日志的有用性。有些问题很容易解决。例如,Facebook的Cassandra存储系统跟踪了互相发送消息的节点的所有操作,但它不写入记录的消息的序列号或ID。如果一台机器上的多个线程并发地发送消息,这使得日志几乎毫无用处。然而,仅通过添加消息ID,我们的消息计数方法就可以很容易地应用,并有助于检测节点通信问题。

       在以前的工作中发现的另一个糟糕的日志记录实践是对事件严重性的糟糕估计。许多“致命”或“错误”事件并不像开发人员认为的那么糟糕[14,22]。这个错误是因为每个开发人员只在自己模块的上下文中判断严重性,而不是在整个系统的上下文中。正如我们在Hadoop read exception示例中所展示的,我们的工具基于事件的频率,可以为开发人员提供对单个事件真实严重性的洞察,从而提高未来日志记录的质量。

       日志解析的挑战。由于我们依赖于静态源代码分析来从日志中提取结构,所以在某些情况下,我们的方法可能会失败,转而将日志消息的大块标识为未解析的字符串。例如,如果程序员使用非常一般的类型,比如Java中的Object(在实践中非常少见),那么类型解析步骤就会失败,因为有太多的可能性。我们通过将一个类的后代数量限制为100来防止这种情况的发生,这个数量足够容纳我们研究的所有日志,但又足够小,可以过滤掉真正的JDK、AWT和包含许多子类(如Object)的Swing类。现代OO语言中的泛型和mix-in等特性提供了通常需要的机制,以避免在非常一般的类中声明对象。此外,一些日志消息是未修饰的,只发出一些基本类型的变量,没有任何常量标签。这些消息通常是调试阶段遗留下来的,我们只是忽略了这些消息。

 

8.相关工作

       大多数现有的工作将整个日志视为重复消息类型的单个序列,并使用时间序列分析方法挖掘它。Hellerstein等人开发了一种新的方法,从企业网络中的SNMP数据中挖掘消息突发、周期性和依赖性等重要模式[12,18]。Yamanishi等人将syslog序列建模为隐马尔可夫模型(HMM)的混合体,以便发现可能与关键故障[35]相关的消息。Lim等人分析了一个带有多个启发式过滤器的大型企业电话系统日志,以找到与实际故障[17]相关的消息。然而,将日志视为单个时间序列在具有多个独立进程的大型集群中并不能很好地执行,这些进程生成交错日志。模型变得过于复杂,参数很难用交错日志[35]进行调优。我们的分析基于消息组,而不是单个消息的时间序列。分组方法使得使用简单、高效的算法(如PCA)获得有用的结果成为可能。

      在以前的工作中,一个关键但有问题的假设是可以准确地检测到消息类型。有些项目[12,18]使用SNMP数据中的手工类型标签,这些标签通常在控制台日志中不可用。许多其他项目使用简单的启发式方法(例如删除所有类似于IP地址的数值和字符串)来检测消息类型[17,35]。这些启发式不够普遍。如果启发式未能捕获一些相关变量,则结果消息类型可能是数以万计的[17]。SLCT[32]、Loghound[33]、Sisyphus[27]和[7]使用更高级的聚类和关联规则,以及信息检索中的评分方法,提取用于日志解析的消息模板。IPLoM[19]使用了一系列启发式方法来捕获相似日志消息的差异,以确定消息类型。虽然这些方法可以成功地检测重复出现的模式,但是它们是通过考虑日志的文本属性来实现的。相反,我们的方法从日志消息中提取关于程序对象的信息,并且我们的检测基于与这些对象相关的事件跟踪,而不是基于文本属性。事实上,正如我们在4.2节中指出的,我们的消息计数向量特性更类似于基于路径的问题检测方法,如查明点[3,8]。

       软件开发涉及除控制台日志之外的其他文本信息。 通过利用源代码,Tan等人提出了一种新方法来检测文本评论与程序逻辑之间的不一致[31]。 我们的想法是类似的,因为我们可以通过使用高度结构化的源代码来为人类设计可以理解的文本信息。 但是,控制台日志分析存在独特的挑战,因为除了源代码之外,我们还必须分析运行时信息。

 

9.结论与未来工作

       我们提出了一种通过分析控制台日志(大多数软件系统中内置的监视信息)来检测问题的通用方法。使用源代码作为参考来理解控制台日志的结构,我们能够准确地解析日志。日志解析的准确性使我们能够提取标识符和状态变量,这些标识符和状态变量在日志中广泛存在,但是由于日志解析的困难,它们通常被忽略。使用控制台日志,我们能够构建以前只在结构化跟踪中使用的功能强大的特性。这些特征揭示了系统执行的准确信息;因此,像PCA这样的高效算法产生了很有前途的异常检测结果。此外,我们使用决策树可视化技术对检测结果进行了总结,这有助于操作员/集成商/开发人员快速理解检测结果。

       我们的工作开辟了许多新的机会将内置的控制台日志转化为强大的监测系统来检测问题,并建议各种可以探索未来的发展方向,包括:1)从程序中提取日志模板二进制文件,而不是源代码,这不仅使我们的方法可以在non-open-source模块上有效工作,而且还带来了很多操作方便便利性;2)设计其他特征,充分利用控制台日志中丰富的信息;3)开发在线检测算法代替现有的postmortem分析;4)研究将来自多个相关应用程序的日志关联起来的方法,并检测更复杂的故障案例。

你可能感兴趣的:(操作系统与计算理论,学习历程记录)