一种灵活配置的分布式服务器监控报警框架

2022-06-18 08:00苑舒斌宗晓萌于俊涛
电子元器件与信息技术 2022年4期
关键词:入库实例报警

苑舒斌,宗晓萌,于俊涛

中海油信息科技有限公司北京分公司,北京,100010

0 引言

随着信息化程度的日益加深,以及对信息安全和技术资产的日益重视,越来越多的企业将保护核心的数据资产和防范企业核心业务数据泄漏提上日程。对此,一种可行的解决思路为推进云办公,实现重要数据的隔离、备份和流转审计。在此场景下,可能涉及大量的物理服务器和虚拟主机,需要进行监控,以及时发现系统问题,复盘历史故障[1]。因此需要一种高度可扩展、可配置的监控报警平台,实现对服务器系统的在线监控报警。平台应当可定制被监控的数据种类,必要时随时通过扩展模块增加新数据。采集来的数据需汇总到平台集中存储,并集中进行分析报警。针对报警功能,应允许用户便利地定制报警规则,基于采集到的数据按需报警。同时,平台中的数据采集模块可能运行在服务器本身以及虚拟主机上,因此采集模块必须轻量化,减少不必要的开销,并在采集架构设计上实现必要的弹性,可轻松应对不同规模的系统。

现有的服务器监控平台,如Zabbix、Ganglia、Nagios等,他们各具特色,但在集群构建、报警规则定义、规模横向扩展能力、二次开发能力、监控目标扩展能力、故障容错能力等方面各自有一定的缺陷[1]。本文设计的平台依托已有集群环境中的服务组件构建,设计上侧重于规则模板的灵活构建和可编程性。

1 平台架构

基于以上考虑,平台架构设计将侧重于分布式、可扩展、可配置和轻量化等方面。

图1所示为系统的整体功能框图。在被监控的服务器、虚拟主机等设备中安装采集程序,负责对终端数据的初步收集。然后通过采集程序的接口模块进行整理,变为标准消息内容,发送到消息队列。根据系统规模不同,消息队列可组建为集群模式。作为消息队列的消费者,入库程序也可根据处理负载情况动态增减。最终,入库程序将监控数据保存到时序数据库中,供用户做历史数据查询时展示使用,并可作为复杂报警功能的判断条件。报警程序的数据来源可以是数据库,但是数据库本身可靠性较低,尤其是系统发生故障的情况下,难以保证数据库系统仍可以正常运行。因此,报警判断依赖的原始数据必须可由入库程序直接提供。

图1 系统整体框图

运行于主机中的采集程序负责定时获取对象的运行状态数据,如CPU、内存、硬盘、网络、IPMI等硬件运行状态,以及运行于其上的关键进程、数据库、消息队列、虚拟机、Docker服务等软件运行状态[2]。因为采集程序需要运行在大量主机上,所以首先要考虑其运行效率,需以最小的资源占用实现采集需求;同时,也要便于扩展,能便利地加入新的监控对象采集需求,甚至可以由用户定制需求。

一方面,消息队列实现了横向扩展需求。依靠队列提供的集群功能、消息路由和负载均衡功能,可快速配置适应不同规模的接入主机数量,并可随时增减作为消息消费者的入库程序模块。另一方面,消息队列提供了数据缓存和持久化功能[3]。当网络抖动或其他意外导致系统负载波动时,消息队列可为系统提供必要的缓冲;入库程序和数据库本身发生故障,也可为待处理的数据提供持久化功能,保证已采集的数据不因平台故障而丢失。

入库程序消费消息队列数据,包括数据预处理、摘要数据生成、数据入库、数据自动分表和过期数据清理等功能模块,如图2所示。来自消息队列的原始采集数据可能具有不同的数据命名方式,或者数据单位。同时,一部分需入库的数据可能需要通过收集到的原始数据计算后才能得到。因此,首先需对收到的数据进行预处理,之后将这些数据转换为对应数据库的入库语句存入数据库。这里考虑到数据库存入可能失败,批量处理失败的数据应退回到消息队列,等待后续处理,如图2中虚线所示。故障诊断及数据展示过程中,会需要系统能提供较长时间范围内原始数据的统计信息,如最大值、最小值、平均值等,因此入库程序还需提供数据摘要服务,计算原始数据若干时间范围内等级的统计结果,并存入数据库以供查询。常见的时序数据库也支持持续查询等摘要生成功能,但基于数据库本身功能的摘要生成就缺乏灵活性,且对各种异常情况缺乏容错能力,因此由程序实现该功能。另外,出于数据库查询性能和数据量控制的考虑,程序还应提供自动分库分表和过期数据清理功能。为了实现分布式数据存储的一致性,并保证分布式程序有一致的分表命名逻辑,分表按照固定的UTC时间间隔进行。程序入库的数据也会同时创建一份缓存数据,供故障诊断模块跳过数据库直接访问使用。缓存数据应按照入库时间戳进行组织,根据实际诊断需求,缓存多个不同时间点的数据。通常进行故障判断时,需要对相邻多个时间点的数据进行分析计算。

图2 入库程序功能框图

报警程序首先读取数据缓存中的数据进行分析,判断是否满足报警条件。如果数据不存在,再尝试到数据库中查询。通常报警分析都需要利用近期采集的多个数据进行判断,而其中某些部分在下次分析中也需要用到。缓存可以减少对数据库的访问压力,也可以保证当数据库不可用时,仅依赖近期数据的简单报警分析便可正常进行。

报警程序的规则配置接口直接面向用户,其设计的关键是如何使用户能高效便捷地创建自定义报警规则,输出自定义的报警通知信息。为了给用户最大的规则定制空间,需要接口支持数学计算、字符串处理、条件判断、循环控制等功能[1]。接口中,提供用户获取指定时间点采集数据的能力。基于以上考虑,系统选取字符串模板引擎作为报警功能判断分析过程实现的核心。

最后,发现系统报警后需要对历史数据进行分析、明确问题原因,所以采集数据的图形化展示是必不可少的功能。因为数据存储部分依赖时序数据库实现,因此该功能可简单地通过数据库支持的数据可视化工具实现。

2 平台实现

本研究针对平台架构中涉及的关键部分实现进行详细介绍。

2.1 数据采集

数据采集部分侧重轻量化和可扩展性。基于主机状态监控的基本需求,对CPU、内存、硬盘、网络、IPMI等硬件运行状态的采集是必要功能。通过对现有解决方案的筛选,找到符合平台需求的开源项目Collectd。

Collectd程序本身以C语言编写,运行时占用的CPU和内存资源都很少。其通过模块扩展的方式,默认支持对常见硬件数据、关键进程数据、常用服务器组件数据、虚拟机和容器数据的采集功能[5]。同时以Python脚本形式,可以方便地编写自定义扩展模块。程序还提供了网络协议、AQMP队列协议、服务器文件输出等多种采集数据输出方式。基于其UDP网络传输协议,甚至可以将多个Collectd采集程序的实例级联,实现分级的数据收集,也可以直接将数据输出到InfluxDB时序数据库。此处,基于系统横向扩展和数据可靠性的考虑,我们选择用RabbitMQ消息队列作为数据处理的中间件。因此,Collectd在平台中将利用AQMP协议的输出方式连接到中心消息队列。程序的功能框图如图3所示。

图3 Collectd功能框图

采集数据具有如下属性:采样时间、主机名、采集模块、模块实例、数据名称、数据值,分别表示数据采样的实际时间、采样发生的主机名称、执行采样的功能模块、采样的目标对象和采样参数的名称。因此,采集到的数据都可用五元组(时间,主机,模块,实例,名称)唯一标识。例如在时间点1000对主机H1的CPU状态采样,得到的结果为各个CPU核心的空闲时间、等待时间等数据。因此,表示核心2 IDLE比例的数据可用五元组(1000,H1,CPU,2,IDLE)进行标识。

应用中,发现Collectd自带的AQMP队列协议输出模块每收到一条输入数据即发送一条MQ消息。此举可能导致网络中有大量短TCP报文传送,影响网络性能。因此对模块进行修正,实现单条MQ消息中批量发送采集数据。

2.2 数据存储

因为持续监控产生的数据量很大,而对其查询的条件主要为数据产生时间,因此适合使用时序数据库进行保存。常见的开源选择包括Elasticsearch、InfluxDB等。

因为不同种类采集数据的内容相差很大,而同类数据基本有相同的数据项,实践中选择将来自不同采集模块的数据单独保存到不同的数据表中。不考虑定期分表的影响,每个采集模块的数据存到同一表中。表中除时间列外,另有主机名、采集模块名、数据实例名等索引字段,而每个数据的名称作为表的数据列,与采集数据唯一标识的五元组对应。同时,为了便于数据查询,规定所有数据时间需整理到规定的整数倍采样时间的间隔时点。

为了便于后续进行数据展示和报警规则编写,入库程序同时还会对入库数据进行摘要计算,将摘要结果同样写入数据库。对于一种原始数据表,根据需要可设置多个不同等级的摘要表。摘要表中,每个原始数据对应其最大值、最小值、累加和、平方和、有效数据个数等5个摘要数据。实际期望得到的统计数据是原始数据在摘要时间间隔中的最大值、最小值、平均值和标准差,设置摘要数据是为了屏蔽摘要过程意外中断、数据丢失、进程重启等意外情况对摘要结果精度的影响。

如图4所示为摘要过程的计算原理,展示了两个低等级摘要数据如何计算对应的高等级摘要数据。对于原始采样数据,可认为其最大值、最小值、累加和都是其自身,平方和是自身平方。后续摘要时,下一摘要等级应记录的最大值、最小值、累加和、平方和,则分别是上一摘要等级中对应时间范围内所有数据的最大值、最小值、累加和、平方和。可以认为每个采样间隔中各个摘要结果的数量级大致相同,因此该摘要过程不会导致数值误差积累。最终,摘要等级的一个时间间隔,记录了对应所有原始采样点数据的摘要值。根据记录中的有效数据数量、累加和、平方和,即可获得摘要时间区间内精确的平均值和标准差。

图4 摘要计算图示

数据库中保存的数据除原始数据外,还有各级摘要。因此访问数据库的数据时,需使用六元组(时间,主机,模块,摘要等级,实例,名称),且名称中需以后缀的方式表示期望数据的摘要类型。

2.3 报警规则

报警规则设置应当灵活、便捷,用户可对特定范围内的设备进行指定报警监控,报警规则编写时能便捷地获取监控数据,并有编写复杂逻辑的能力。

获取监控数据的便捷性体现为以下几点。第一,用户报警规则中获取监控数据时,可便捷地指定数据六元组的内容,以精确地获取数据。第二,六元组中的部分内容,如主机名、实例名,可指定通配符,或者给定预定义列表。第三,六元组中的各项应当具有合理的默认值,常规数据访问必须提供的项只有时间和名称。第四,时间参数应采用相对值,且具有容错性,指定时间应自动取整到相应数据摘要间隔的整数倍时点。第五,规则定义参数化,普通用户不需要修改规则脚本,直接改变规则参数即可变更规则行为。

为实现以上目标,为报警规则脚本提供get函数原型如下:

def get(tsOffset: float, itemName: string,metric: string = None, summary: string = None,host: string = None, inst: string = None)

其中只有相对时间tsOffset和变量名称itemName为必选项;其他参数中模块名称metric和摘要等级summary在规则编写时提供了默认值,因此可以省略;主机名host和模块实例inst提供了通配符和列表语法。对于一条报警规则,在实际运行前会根据通配符到系统中确认实际可能的主机名和模块实例列表,或者直接使用用户给定的列表,然后对所有可能的组合都执行一次规则判断。因此,每次规则执行,主机名和模块实例的默认值都不相同,实现了模板化报警规则的功能,可指定规则执行的目标列表,也实现了对特定范围内的设备进行指定报警的功能。

编写复杂报警逻辑,指用户在编写报警规则时,可进行变量定义、数学计算、字符串处理、条件判断、循环控制等操作。同时,基于安全考虑,用户编写的脚本还需要在沙箱环境中隔离运行。Python作为一种使用简单的脚本语言,且较多运维人员都有应用经验,适合作为报警规则脚本的基础。Python环境下,Jinja模板语言具有类似Python的语法,且可以利用Python本身的函数功能,运行环境也有沙箱保证,适用于本平台报警规则脚本编写的基本需求。通过模板语言语法编写报警规则,还可便利地格式化输出报警提示信息[6]。实践中,我们是基于Jinja模板语言提供的功能实现报警规则执行。将定义的get函数映射到模板语言函数中,供用户获取数据。

为了使用户在报警规则执行、报警消息生成时可以获取更完整的信息,也将get函数使用的默认参数和规则定义时填写的规则名称等作为附加信息映射到模板语言环境中,供用户使用。

2.4 数据展示

对于常见的时序数据库,有Grafana作为开箱可用的数据展示组件[7]。因为所有数据保存到数据库,也可便捷地集成到现有的应用环境界面中。

如图5所示为平台数据展示示例。Grafana提供了基础的数据源连接、变量配置、时间缩放功能。平台配置了4个变量,分别为模块名称列表、主机列表、模块实例列表和变量名称列表,分别表示在选定的展示时间区间内,可用的数据采集模块名称、选定采集模块收集的主机名称、选定主机上该模块的实例列表和模块的采集变量列表。其中,除模块名称外均支持多选。选择完成后,将对每个采集参数显示一个独立图表,图表中对每个主机名称和模块实例名称的组合均显示一条折线,表征变化趋势。图中选定的采集模块是CPU模块,它采集了每个CPU核心的系统使用率、用户使用率、中断使用率、等待时间比例等数据。根据配置,显示了某主机上第0、第1核心的系统使用率和用户使用率变化。

图5 Grafana数据展示

3 报警配置实例

3.1 CPU占用报警

现通过实例展示系统中如何配置检查特定CPU核心的使用情况,如果负荷持续超标则进行报警。

系统监控的主机中有若干名称以“ZS-”开头,其CPU核心20-29运行特定负载,如果CPU空闲时间持续半小时低于10%,则应报警。对于该场景,可按照表1内容配置报警规则。规则指出,该规则会使用CPU模块采集到的5分钟等级摘要数据,监控的主机名称可用通配符“HOST-*”进行匹配,监控的CPU实例可用正则表达式“/2[0-9]{1}/”进行匹配。对于匹配到的CPU核心,连续获取其最近30分钟idle_avg数据,判断是否低于阈值。如果所有时点都低于阈值,则说明CPU空闲时间持续偏低,应进行报警。这里用到两个用户定义的参数var.low和var.cnt,分别表示idle的检测阈值和连续获取的5分钟摘要数据时点数量。表中定义idle的低阈值为10%,采样时点数量是6,对应30分钟时长。报警规则的最后一行是判断语句,如果结果是真,则应当报警,报警内容由输出模板格式化后给定。

由表1的配置样例可以看出,平台规则配置非常灵活,输出内容也可根据设定清晰地指出报警来源。编写规则脚本需要一定的编程基础,但通过用户参数的形式,使普通用户也能够安全地按需修订规则行为。

表1 报警配置实例

3.2 进程重启报警

关键进程重启也是服务器监控平台的一项重要工作内容。通常的服务重启监控基于指定名称进程的数量变化,或者进程启动时间变化进行判断。对于具有多实例的服务,常见监控平台往往难以有效定义报警规则。基于本平台的扩展能力,可通过插入数据预处理模块的方式直接获得监控进程的重启事件,统计进程重启次数。

如图2所示,数据入库程序具有数据预处理功能模块。对于CPU、内存、关键进程等系统已知的数据类别,均可注册专用的数据处理模块,进行数据预处理。预处理框架中,可实现对输入数据的通用处理,如字段名改写、单位转换、有效性检查等。之后将收到的数据缓存在临时结构中,等待模块接收到完整的数据再统一进行后续处理,包括数据处理回调和实际入库动作。

如图6所示,针对进程重启检测功能,可在关键进程监控模块进行数据预处理时,插入数据处理回调函数。函数接收进程数据处理模块缓存的进程名称、进程PID等数据,与自身状态字典保存的内容进行对比,即可发现特定进程是否重启。发现进程重启后,重启统计模块将产生重启数据,标记过去时间间隔内某进程发生1次重启。重启统计模块产生的数据与其他从主机输入的模块数据具有同等地位,在平台中同等进行数据摘要、保存、展示、报警等后续访问。期望的预处理数据复杂时,平台也可以支持利用多个模块数据进行分析生成[8]。

图6 进程重启统计实现框图

此方案充分利用了平台易于扩展的优势,高效完成进程重启监控任务。且进程重启数据也被入库、摘要,可随时查看历史记录。

4 结语

本文针对大规模服务器集群和虚拟主机的应用场景,给出了一种高度可配置的分布式状态监控和报警系统的基本架构,包括数据采集、消息队列、入库程序、报警程序、数据展示等组成部分。平台可适应不同规模主机集群的监控报警需求,报警规则支持模板化,编写简单,并可设置用户自定义规则参数。

平台功能目前都已实现,在实际工作场景中运行良好,规则脚本提供的灵活性完全可以满足日常监控报警功能扩展的需求。

猜你喜欢
入库实例报警
2021年山西省6591家科技型中小企业入库
重磅!广东省“三旧”改造标图入库标准正式发布!
中国食品品牌库入库企业信息公示②
中国食品品牌库入库企业信息公示①
小心,墙纸在报警
鞋子摆放透露的信息
死于密室的租住者
基于Wonderware平台的分布式报警系统的设计与实现
完形填空Ⅱ
完形填空Ⅰ