具体实施方式
此处描述了模型检查***,该模型检查***通过提供模型和通用框架来检查应用不变属性、检测异常行为并监视应用健康从而更有效地验证和确认分布式应用的设计。模型检查***检查针对从应用的正式描述所导出的应用模型来检查在线应用行为,这被称为模型检查。该***将具体应用制定为抽象模型以及期望在所有条件下适用于应用的多个规则或属性。模型检查器将实际应用执行与模型相比较,并且确认属性保持为真或是报告属性被违反。
与现有模型检查方法相比,此处描述的模型检查***不遭受状态空间激增的问题和高级***抽象中的困难。在这一***中,应用模型是应用行为的充分选择的方面并以容易且直接的方式来描述。该***具有横向扩展和纵向扩展的灵活性。另外,该***提供追踪至根本原因以供错误分析的功能,这节省了大量人类调查的时间。在可同步或异步地进行各种验证和确认活动的情况下,实现了通用框架。对于应用专用模型、其对应的行为提供者、以及模型检查器,该框架易于扩展。
模型检查***将目标分布式应用建模成小的有限状态机的集合和依赖图来捕捉组件之间的相关。该***基于事件依赖图自动地执行根本原因分析。即使失败涉及多个机器、组件和日志,该***可将整个事件序列进行相关,以从在每一组件的贡献动作期间一直导致问题的操作来跟踪该问题。该***还提供通用框架以允许除了有限状态以外的可由应用开发者添加以供进一步测试其分布式应用的各种确认方法。由此,模型检查***提供了在现实的生产条件下对分布式应用的更有效且全面的确认。
以下段落更详细地描述模型检查***,从而呈现模型检查机制以便通过使用所提议的框架来确认并验证分布式应用的行为。建立模型使用某领域的知识来定义和构建该模型,并且这提供更多的灵活性来合并新特征、丢弃旧特征、确定要检查什么行为、以及要调查多少细节。这一机制有助于以更为成本有效的方式来在大规模应用的可靠性方面获得置信、减小错误调查时间、以及执行详细的验证。另外,该框架允许到其他应用的方便扩展。
模型
模型检查是基于一组所抽象的规则或不变属性来自动分析反应***的过程。它具有一旦错误发生在某些可观察输出级就检测到错误行为的能力。这具有在与晚期阶段发现相比校正更便宜的早期阶段标识定时问题并防止灾难性失败的潜能,其在生产环境中呈现很大的价值。在某些实施例中,模型检测***依赖于最终被表示为某些类型的日志文件的***行为。这样的日志可忠实地捕捉所有相关应用行为,包括应用状态转换、错误、以及性能度量。在某些实施例中,分布式***的日志被集成到中央存储以便于失败调查。只要提供了对应的日志读取器,模型检查引擎就不依赖于集中式轨迹存储。在引擎内部,这一工作是通过若干管理组件及其工作者的协作来完成的。
模型是要分析的目标应用的某些不变属性。为示出该框架,考虑一下三个类型的模型:——有限状态机(FSM)、错误、以及性能度量——作为示例,但它们不限于此处所讨论的类型。
第一类型的模型是有限状态机模型。为避免模型抽象的复杂性和状态空间激增的问题,该***聚焦于在各个机器上运行的FSM。FSM之间的关系是通过对不同机器上的事件进行相关来捕捉的。换言之,应用行为被变换成小的FSM集合以及事件依赖图。变量对于分布式***的大小都是不变的。该***将状态中的每一个定义为以下类型之一:Start(开始)(FSM的入口点),Normal(正常)(除最终以外的任何可接受状态),以及Final(最终)(没有事件可触发从这一状态的转换)。对于Start和Normal状态,状态生存期的某一统计信息在学习阶段期间被收集,随后它被用于执行验证。以下是典型状态机及其模型描述。
第二类型的模型是错误不变模型。错误不变是分布式应用的稳定属性之一,它可被描述为无死锁、无未经处理的异常、无断言等。该***还可检查其他非致命错误以将其他失败或正常行为进行相关。大多数分布式应用其有自我恢复的能力。由于定时问题,如果事件顺序改变,则可被忽略的某些错误可能触发大规模失败。对这样的错误的自动监视对于避免级联失败变得非常有帮助。以下是示例错误模型。
该错误模型包括错误项的集合。每一错误项具有担当该错误的标识符的类型以及用于指示该错误的严重性的等级。该错误项包含用于确定错误是否与该模型匹配的错误匹配准则列表、以及用于帮助从该错误本身提取相关关键字的关键项列表。属性Field(字段)、Keys(关键字)以及Regex(正则表达式)用于从错误日志提取信息。
第三类型的模型时性能度量模型。应用健康通常由一组性能度量来表示。对这些度量的持续监视可潜在地在问题的早期阶段检测到问题。当某些异常被检测到时,追踪至这些问题的根本原因是有用的。该框架提供了自动化这一过程的解决方案。以下描述将***可用性(高可用性是分布式***中的目标之一)作为一个示例。该模型定义三个阈值:Soft(软)、Hard(硬)、以及Duration(持续时间)。每一阈值具有基础值和比较方法。“Soft”是指示度量不正常但只要在“Duration”阈值所限制的时间段内返回正常则仍然为可以(okay)的界限。“Hard”是度量超过其不能正确地进行的边界。这三个阈值定义两个类型的可用性异常:长持续时间异常(“Soft”和“Hard”之间的可用性、并且持续比“Duration”更长的时间段)以及严重异常(可用性低于“Hard”)。以下是示例性能度量。
数据结构
以下段落描述模型检查***内的三个类型的数据:TraceRecord(轨迹记录)、StateInfo(状态信息)、以及McEvent(模型检查事件)。任何***行为将最终由轨迹管理组件转换成TraceRecord的格式。以下是TraceRecord的示例定义。
TraceRecord是属性和上下文对象的集合。将轨迹从其原始格式转换成TraceRecord是轨迹管理组件的责任。轨迹管理组件可包括用于从各种轨迹源提取轨迹信息的一个或多个轨迹读取器。该读取器提供被称为“时间戳(TimeStamp)”的属性,该时间戳的上下文是事件实际发生时的时间标志。尽管由于机器时钟偏移而导致时间戳在分布式应用中是不可靠的,但在单个节点上的排序仍然有效。
模型检查组件采用TraceRecord作为输入,并将数据转换成被称为StateInfo的另一格式,它包含用于检查变量的状态的四个属性:1)VariableId(变量Id):要监视的变量的唯一标识符,2)State(状态):变量的当前状态信息,3)CorrelationId(相关Id):可用于与其他变量进行相关的信息,以及4)TimeFlag(时间标志):在变量转换成当前状态时的时间戳。以下是StateInfo的示例定义。
每一检查器拥有特定变量的模型以及对应的检查器配置。从TraceRecord到StateInfo的转换是基于如以下示出的配置来完成的,其中StateInfo的四个属性和TraceRecord的字段(field)之间的映射被明确地指定。
由于模型检查组件处理个别状态机中的状态,因此该组件将基于事件依赖图来创建并将事件抛至事件池。事件可以是FSM中的状态或状态转换、错误、或性能度量中的异常。每一事件具有类型(对该事件的描述)、EventID(事件ID)(唯一的标识符)、用于与其他事件进行相关的一组属性(CorrelationKey(相关关键字))、与其相关的父(原因事件)和子(结果事件)的相关状态(ParentCorrStatus(父相关状态)和ChildCorrStatus(子相关状态)、以及当该事件发生时的时间戳(TimeStamp)。以下是McEvent的示例定义。
***组件
图1是示出在一个实施例中的模型检查***的各组件的框图。***100包括服务管理组件110、应用模型组件120、轨迹管理组件130、模型检查组件140、事件相关组件150、以及通知组件160。这些组件中的每一个都在此处进一步详细讨论。
服务管理组件110通过开始、停止、暂停、以及恢复模型检查服务来管理模型检查。例如,组件110可向其他组件中的每一个发出命令来初始化并准备或恢复模型检查、或者来关闭或暂停模型检查。
***模型组件120管理分布式应用的一个或多个模型,其中该模型描述了分布式应用的不变行为。组件120从数据存储或其他存储设施加载或更新应用模型。组件120还可基于服务配置改变来启用或禁用某些模型。例如,测试者可禁用报告太多虚假肯定的模型直到该模型可被更新。
轨迹管理组件130控制轨迹读取器的集合以便从与分布式应用相关联的各种资源中加载轨迹。该组件可从一个或多个日志文件、数据库中读取信息、通过查询该服务来直接从服务中读取信息。组件130使用轨迹读取器来将域专用输入格式桥接成可由模型检查***100理解的公共格式。
轨迹读取器是将轨迹从各种源中加载轨迹并将其转换成模型检查器所使用的TraceRecord结构的组件。如果新数据源被添加,则可将对应的读取器提供给该***。在某些实施例中,轨迹读取器从接口ITraceReader(接口轨迹读取器)继承并实现以下两个方法:
List<TraceRecord> Read(ReaderConfig readerConfig,ConfigRecordserviceConfig,ref object lastProcessedId,DateTime startLogTimeStamp,Guid tag);
List<TraceRecord> ReadLatestTransitions(ReaderConfig readerConfig,ConfigRecord serviceConfig,List<string>keys,TraceRecord record,Guidtag);
模型检查***使用第一种方法来持续地加载数据以供处理。该方法取读取器配置和服务器配置两者作为自变量。读取器配置包含关于数据源、读取器名称、以及时间戳字段的信息。服务配置定义如何加载轨迹,诸如每一查询所处理的日志数量。“lastProcessedId(最后处理的ID)”是读取器已经读取的最后一个轨迹记录的时间戳。“startLogTimeStamp(开始日志时间戳)”用于确定在开始该服务但没有保存历史信息时的日志的开始点。第二种方法在错误被检测到以及该服务尝试将所有相关的轨迹加载到单个地方以便于调查时使用。“record(记录)”是在检查下当前有问题的记录。“keys(关键字)”列表是当查询相关的轨迹时的一组约束。
模型检查组件140管理模型检查器的集合以学习并且验证分布式应用的行为。该组件开始不同检查器并向每一检查器分配特定模型,并且加载对应的检查器配置。分布式应用可正常地执行或遭受一个或多个测试场景。在该应用执行时,模型检查组件140监视分布式应用的各种组件以检查异常。如果非期望事件发生,或属性被检测到与模型所期望的不变不同,则组件140报告事件(有时被称为计数示例)以供进一步调查。
模型检查组件140扮演两个角色:模型学习者和检查器。当服务正在学习模式中运行时,组件140以空的或不完整模型开始。组件140从轨迹记录中提取信息并记住首次看到的变量。随着日志被处理,组件140逐渐构建应用模型直到没有新信息可从日志中被提取。在检查模式中,组件140参考已学习的模型来确认应用行为。使用FSM作为示例,组件140将监视实际应用状态转换,并验证该转换是否有效、以及应用保持在每一状态中的持续时间是否在边界内。组件140所管理的每一模型检查器记住最后看到的该状态机的状态。
事件相关组件150跨应用地对事件进行相关,并进行根本原因分析。事件可包括由特定日志条目、性能度量、或其他发生的事情所指示的一个或多个模型的违反。组件150使用定义独立和/或分布式应用组件之间的交互的预定义事件依赖图。组件150可用特定标识符来标识针对***所采取的每一动作,使得可逐组件地对动作的结果进行追踪。
为执行相关,***建立依赖关系。以下给出该模型和对应的类定义。在这一示例中,父事件是在FSM“Model1(模型1)”中从S1到S2的状态转换。这将触发到状态S3的由“Model2(模型2)”描述的FSM的转换。该组相关关键字类型为“Key1(关键字1)”和“Key2(关键字2)”。
事件相关组件150持续地扫描事件池。对于每一事件,组件150试图找出相关的原因和结果(父和子)事件。因为事件来自不同节点并由不同检查器处理,因此在该池中原因事件可能出现在结果事件之后的情况下事件重新排序变成了常见的场景。为减轻这一问题,每一检查器按照最后所处理的记录的时间戳(被称为检查点)来报告检查进展。组件150将检查某一检查器的进展以确定事件是否应到达该池。在某些实施例中,组件150假设:1)跨机器的时钟偏移将不大于阈值;以及2)原因事件不迟于结果事件发生。这简化了组件150的处理。
通知组件160提供标识由模型检查所标识的非期望应用行为的报告和警告。模型检查***100取各种格式的轨迹作为异常被检测到的情况下的输入和输出警告。组件160还可在请求时或周期性地提供详细的检查报告,作为对分布式应用的例行监视的一部分。
在其上实现模型检查***的计算设备可包括中央处理单元、存储器、输入设备(例如,键盘和定点设备)、输出设备(例如,显示设备)和存储设备(例如,盘驱动器或其他非易失性存储介质)。存储器和存储设备是可以用实现或启用该***的计算机可执行指令(例如,软件)来编码的计算机可读存储介质。此外,数据结构和消息结构可被存储或经由诸如通信链路上的信号等数据传送介质发送。可以使用各种通信链路,诸如因特网、局域网、广域网、点对点拨号连接、蜂窝电话网络等。
该***的实施例可以在各种操作环境中实现,这些操作环境包括个人计算机、服务器计算机、手持式或膝上型设备、多处理器***、基于微处理器的***、可编程消费电子产品、数码照相机、网络PC、小型计算机、大型计算机、包括任何上述***或设备、机顶盒、片上***(SOC)等中任一种的分布式计算环境等。计算机***可以是蜂窝电话、个人数字助理、智能电话、个人计算机、可编程消费电子设备、数码相机等。
该***可以在由一个或多个计算机或其他设备执行的诸如程序模块等计算机可执行指令的通用上下文中描述。一般而言,程序模块包括执行特定任务或实现特定抽象数据类型的例程、程序、对象、组件、数据结构等等。通常,程序模块的功能可以在各个实施例中按需进行组合或分布。
处理流水线
在某些实施例中,模型检查***可在两个模式中运行:学习和检查。在学习模式中,服务具有对日志的完全信任并且从其中学习不同模型。在获取模型之后可使用一次性手动审阅来纠正不遵守原始应用设计的任何模型错误。在检查模型中,模型检查器从由轨迹读取器所填充的轨迹队列中取得轨迹记录,并且随后针对应用模型检查该记录。如果检查器检测到与事件依赖图所描述的其他事件有依赖关系的任何事件,则检查器将该事件抛入事件池。事件相关组件持续地仔细检查事件列表,并试图找出对于任何目标事件的原因和结果事件。如果实际应用行为不遵守模型中所定义的属性,则模型检查器和事件相关组件两者都将连同有关的轨迹一起报告错误。随后人类调查可确定该错误是否为假警报。如果是假警报,则调查器可更新该模型。这可手动地完成或通过在学习模式中运行服务来完成。
图2是示出在一个实施例中的模型检查***用于使用模型检查来执行分布式应用的处理的流程图。在框210中开始,***接收描述分布式应用的期望行为的一个或多个模型。模型可包括应用的一个或多个不变属性,诸如有限状态机、错误、以及性能度量。在某些实施例中,***将应用的每一组件建模成有限状态机,并建立依赖图来追踪各组件之间的依赖性。模型(如果正确的话)定义在应用正确地行为时应用将展示的行为。有时,模型在正在进行的基础上进化。例如,测试可发现当错误被报告时应用正在正确地行为,因为模型是不正确的。在这些情况下,测试者可在学习模式中运行***或手动地更新模型以反映应用的正确行为。
在框220中继续,***开始监视分布式***的执行的模型检测服务以检测应用的异常行为。例如,服务可开始一个或多个轨迹加载器,该一个或多个轨迹加载器观察应用的组件以寻找描述应用内发生的事情的输出信息。轨迹加载器可监视日志文件、数据库、以及其他信息源以获取应用的状态。
在框230中继续,***收集将应用的行为描述为发生在应用的分布式组件处的一系列一个或多个事件的一个或多个轨迹。例如,***可将日志文件和其他轨迹信息收集到聚集的集中位置以供处理。对轨迹的处理可在应用已停止运行之后离线发生,以便异步检测非期望应用行为。***还可动态地标识应用行为。
在框240中继续,***基于所收集的轨迹来标识一个或多个事件。***可将事件进行相关以标识源自应用内相同动作的事件。例如,将数据存储在分布式存储应用中的请求可导致应用内的许多实际事件,诸如数据库查询、所接收的web请求、文件***访问等。***将有关事件进行相关,使得如果非期望的应用行为被标识,则可追溯事件链至失败的根本原因。
在框250中继续,***针对所标识的事件来检查所接收的一个或多个模型,以便确定是否发生了任何非期望的应用行为。例如,***可标识违反模型的状态转换、在应用正在正确地行为的情况下不会发生的错误、以及在可允许的边界以外的性能度量。
在判定框260中继续,如果模型检查失败,则***在框265处继续,否则***在框275处继续。在框265中继续,***标识与失败的模型检查有关的根本原因事件。例如,***可导航与使模型检查失败的事件相关的事件链。当找出根本事件时,将该根本事件标识为根本原因,并且存储相关的事件链以供以后分析。在框270中继续,***基于所标识的根本原因以及失败的模型检查来报告错误。***可将报告发送给个人以供手动分析以及更新模型或修复应用软件代码中的隐错。错误报告可标识有助于该分析的信息,诸如事件何时发生、哪些应用组件被涉及、失败所涉及的每一相关的事件等。
在判定框275中继续,如果完成了对应用的监视,则***在框280处继续,否则***循环到框230以继续收集轨迹信息。在某些情况下,模型检查是在应用已经运行之后对轨迹执行的。在框280中继续,***停止模型检查服务。***可响应于用户命令或预设监控持续时间的期满来停止。在框280之后,这些步骤结束。
图3是示出在一个实施例中的模型检查***用于学习分布式应用行为的一个或多个模型的处理的流程图。在框310中开始,***开始监视分布式***的执行的模型检测服务以学习应用的行为。例如,服务可开始一个或多个轨迹加载器,该一个或多个轨迹加载器观察应用的组件以寻找描述应用内发生的事情的输出信息。轨迹加载器可监视日志文件、数据库、以及其他信息源以获取应用的状态。出于创建应用行为的模型的目的,***可假设在学习期间所接收的输出是正确的。
在框320中继续,***设置模型检测服务的学习模式,该模型检查服务检测应用行为以便为应用建立正确行为的模型。例如,该服务可接收一个或多个配置参数,并且一个参数可指定该服务可在其中运行的模式。
在框330中继续,***收集将应用的行为描述为发生在应用的分布式组件处的一系列一个或多个事件的一个或多个轨迹。例如,***可将日志文件和其他轨迹信息收集到聚集的集中位置以供处理。对轨迹的处理可在应用已停止运行之后离线发生,以便异步学习应用行为。***还可动态地标识应用行为。在框340中继续,***基于所收集的轨迹来标识一个或多个事件。***可将事件进行相关以标识应用的各组件之间的依赖性以供建立依赖图。例如,将数据存储在分布式存储应用中的请求可导致应用内的许多实际事件,诸如数据库查询、所接收的web请求、文件***访问等。
在框350中继续,***建立应用的一个或多个组件的模型,其中该模型描述每一组件的正确行为。例如,***可建立有限状态机,该有限状态机表示每一组件以及该组件可经历的有效状态和转换。在框360中继续,***建立描述应用的各组件之间的一个或多个交互的依赖图。例如,***可建立与对每一组件进行建模的各有限状态机有关的图。依赖图描述各组件如何被相互关联以及在应用的各组件之间可发生什么事件。
在框370中继续,***停止模型检查服务。***可响应于用户命令、配置参数改变、或预设监视持续时间的期满来停止。在框380中继续,***存储所建立的模型和依赖图。***之后可在检查模式中运行,并且加载该模型和图以验证在各种负载和环境下的正确应用行为。在框380之后,这些步骤结束。允许***学习应用行为允许了测试者快速地将***应用于新的应用,而无需对***的深度理解或手动地建立模型。***可被提升并快速地运行以向测试者通知应用何时正以不寻常或以前未看到的方式行为。
在某些实施例中,模型检查***验证第三方应用组件的行为。复杂的应用常常利用许多组件,某些是现成的或是不在应用开发者控制下的第三方组件。然而,应用的正确行为可取决于第三方组件的正确行为,并且模型检查***可接收第三方组件的模型并在模型检查期间验证各组件的行为。模型检查***的学习功能允许***学习第三方组件的很好理解的行为的模型,并允许***报告背离所学习的模型的任何行为。
在某些实施例中,模型检查***离线执行模型检查。某些应用在其运行时可生成大量日志,或者出于其他原因可能难以实时地监视。模型检查***可执行对应用执行的事后(post-mortem)分析,以验证在应用已运行之后的长时间应用行为与期望行为的模型一致。***可在夜间或在其他方便时间完成日志,以提供对任何可疑应用行为的报告。在***的某些使用中,相对于应用所产生的轨迹,操作者可使该***按其自身的步调运行。一旦应用被声明为正确的直到某一点,则直到该点的轨迹可被丢弃,从而只留下还要处理的新轨迹或揭示错误应用行为的轨迹。
在某些实施例中,模型检查***将活动标识符分配给应用内的高级动作,并使用活动标识符来对应用内的事件加戳。因为时间戳和其他类型的追踪对于事件相关可能是不可靠的,因此活动标识符提供跨与相同动作有关的事件保持一致且***可用于跨应用组件对事件进行相关的单个量。
如此处所述的,模型检查***消费各模型,各模型指定应用异常或甚至期望的不变量。例如,即使看上去正确的应用行为也可在该行为太频繁地发生的情况下发出应用隐错的信号。重新配置可以是正常发生的事情,但单个周期中特定次数的重新配置可指示问题。这一类型的行为可在模型中被描述并且由***监视以便在该行为发生的情况下向某人发信号。
从上文将会认识到,虽然在此已出于说明目的描述了模型检查***的特定实施例,但是可以做出各种修改而不背离本发明的精神和范围。因此,本发明只受所附权利要求限制。