由于业务的多样性,平台和系统变得异常复杂。如何监控和维护它是我们IT人需要面对的一个重要问题。在如此复杂的环境下,监控系统就派上用场了。今天,我们就来介绍一下IT监控系统,包括它的功能、分类、分层;我们还将介绍几个流行的监控平台。在IT运维过程中,监控系统的功能经常会遇到这样的情况:某个业务模块出现问题,而运维人员却不知道。发现问题的时候,问题已经很严重了。系统出现瓶颈,CPU使用率持续上升,内存不足,磁盘满;网络请求激增,超过了网关的压力。一旦出现上述问题,将对我们的业务产生巨大的影响。因此,每个公司或IT团队都会针对此类情况构建自己的IT监控系统。监控系统工作流程图功能包括:实时监控服务、系统、平台的运行状态。收集服务、系统和平台运行信息。通过收集信息的分析结果,预测存在的故障风险并采取措施。根据风险评估,进行故障预警。一旦发生故障,将立即发出报警信息。通过监控数据,定位故障,辅助生成解决方案。最终保证系统的连续、稳定、安全运行。监控数据可视化、统计方便,按一定周期导出归档,用于数据分析和问题回顾。监控系统的分类由于监控系统对我们来说意义重大,所以针对不同的场景,将监控系统分为三类,分别是:日志类型调用链类型度量类型日志类型通常我们在系统和业务处添加一些日志代码level来记录一些日志信息,方便我们发现问题的时候查找。这些信息会和事件相关,比如:用户登录、下单、用户浏览商品、一小时内网关流量、用户平均响应时间等。这种日志记录和查询有很多解决方案。比如ELK方案(Elasticsearch+Logstash+Kibana),使用ELK(Elasticsearch、Logstash、Kibana)+Kafka/Redis/RabbitMQ搭建日志系统。ELK结合Redis/Kafka/RabbitMQ实现日志监控程序通过SpringAOP在内部记录日志,Beats收集日志文件,然后使用Kafka/Redis/RabbitMQ发送给Logstash,Logstash再将日志写入Elasticsearch。最后使用Kibana将存储在Elasticsearch中的日志数据以实时数据图表的形式展示出来。调用链类适用于服务较多的系统,尤其是微服务系统。一个服务调用可能涉及多个服务。A调用B,B调用C,就像一个链条,形成一个服务调用链。调用链是记录一个请求经过所有服务的过程。请求从一开始就进入服务,经过不同的服务节点,然后返回到客户端,通过调用链参数跟踪整个链路的行为。以便知道请求在哪里失败,系统的瓶颈在哪里。调用链监控的实现原理如下:①Java探针,字节码增强Java代码运行原理图在介绍这个方法之前,我们先来回顾一下Java代码运行的原理。通常我们会通过“Java编译器”将Java源代码编译成Class文件。然后将这个Class的字节码文件加载到“类加载器”中进行字节码校验。最后将验证后的字节码发送给“JavaInterpreter”和“Just-in-TimeCompiler”,由“JavaRuntimeSystem”运行。对于Java探测器,增强字节码的方法是使用Java代理,它是运行方法之前的拦截器。JVM加载Class二进制文件时,使用ASM动态修改加载的Class文件,在被监控方法前后添加需要监控的内容。例如:添加一条计时语句,记录方法的耗时。将耗时的方法存放在处理器中,利用栈优先的特性(先进后出)来处理方法调用的顺序。每当请求处理结束时,将耗时方法和入参map输出到文件中,然后根据map中对应的参数来区分耗时业务。最后去掉相应的耗时文件,转成xml格式解析,通过浏览器显示代码层级。Java探测工具示意图注:ASM是一个Java字节码操作框架,可以动态生成类或增强已有类的功能。ASM可以直接生成二进制Class文件,并且可以在类加载到Java虚拟机之前改变类的行为。Java类存储在.class文件中,该文件具有解析类元素的元数据:类名、方法、属性和Java字节码(指令)。ASM从类文件中读取信息后,可以改变类行为,分析类信息,甚至生成新的类。②拦截请求,获取每个请求服务中的信息,实现跟踪。这里我们以Zipkin+Slueth为例来说明其原理。Sleuth提供链接跟踪。由于一个请求涉及到多个服务的相互调用,而这个调用往往是链式结构,需要经过多层调用才会返回请求。Sleuth常用于跟踪整个调用过程,便于理清服务间的调用关系。Sleuth服务调用跟踪图例将为每个请求生成一个TraceID。如上图所示,这个TraceID在整个Request和Response过程中都会保持一致,不管经过了多少个服务。这是为了方便记录一次调用的整个生命周期。查看每一个请求,都会有一个SpanID。这里的Span是Sleuth服务跟踪的最小单位。每传递一个服务,Request和Response的值每次都会不同,这是为了区分不同的调用动作。对于每个调用动作,Sleuth都做了如下标记:ServerReceived表示服务器接受,即服务器收到请求。ClientSent是由客户端发送的,即服务本身不提供响应,需要调用其他服务来提供响应,所以这时候作为客户端发起请求。ServerSent由服务器发送。见上图。SERVICE3收到请求后需要将请求发送给调用者,因为他是最终的服务提供者。ClientReceived是客户端接收的,因为发起调用的客户端接收到服务器返回的请求。实际上,Sleuth通过上述方式为每个请求记录了一个统一的TraceID,每个请求的详细步骤记录为SpanID。每次发起或接受请求的状态记录为ServerReceived、ClientSent、ServerSent、ClientReceived,完成对服务调用链路的跟踪。Sleuth服务调用跟踪图例调用服务链路上的每个被调用服务节点都会通过ParentID记录发起调用服务的SpanID。由于SpanID是唯一确认最小服务单元的,因此ParentSpanID是已知的。然后你就知道是谁给你打电话了。metric类实现了时序数据库(TimeSeriesData,TSD)的监控方案。其实就是记录一系列以时间为维度的数据,然后通过聚合操作查看指标数据和指标趋势。说白了,就是描述一段时间内某个被测者的测量值的变化(metric)。由于IT基础设施、运维监控和互联网监控的特点,这种方式被广泛使用。通常,时间序列数据的建模分为主题、时间点和测量值三个部分。我们来看这个例子,时序数据库的数学模型,例如:需要监控服务器的平均In/Out流量:整个被监控的数据库叫做“Metric”,里面包含了所有被监控的数据。类似于关系数据库中的表。每一条监控数据称为“Point”,类似于关系数据库中Row的概念。每个“Point”都定义了一个时间戳“Timestamp”,作为索引来表示数据采集的时间。“Tag”是维度列,代表监控数据的属性。“字段”作为指示列,作为测量值,即测量的结果。时序数据库数据模型图例时序数据库的存储原理,关系型数据库存储采用B树,虽然减少了数据查询的磁盘寻道时间,但无法解决写入大量数据时的磁盘效率问题。由于监控系统的应用场景,往往会写入大量的数据,所以我们会选择LSMtree(LogStructuredMergeTree)来存储时序数据库。LSMtree(LogStructuredMergeTree),按字面理解,将记录的数据按照日志结构(LogStructured)追加到系统中,然后通过合并树(MergeTree)的方式进行合并。下面我们来看一个LevelDB的例子,以方便我们的理解。LSM-tree分为三类文件:接收写请求的memtable文件(在内存中)不可修改的不可变memtable文件(在内存中)磁盘上的SStable文件(SortedStringTable),一个有序的字符串表,这个有序的字符串就是数据的关键。SSTable有七层(L0到L6)。下一层的总大小限制是上一层的10倍。LSMtreeLevelDB存储示意图LSMtree写入过程:将数据追加到日志WAL(WriteAheadLog)中。写日志的目的是防止内存数据丢失,及时恢复。将数据写入memtable。当memtable已满(超过某个阈值)时,memtable被转移到不可变memtable,新的memtable用于接收新的数据请求。一旦Immutablememtable已满,它就会写入磁盘。并且先存放L0层的SSTable磁盘文件,此时不需要合并文件。每层所有文件的总大小是有限的(8MB、10MB、100MB...1TB)。从L1层开始,每一层的容量都会增加十倍。如果某一层的数据文件总数超过阈值,则选择该层的一个文件与下一层的文件合并。这样上层的数据都是比较新的数据,查询可以从上层开始依次往下走,这些数据是按时间序列存储的。监控系统的分层说完监控系统的分类,我们再来说说监控系统的分层。从用户的请求到数据的返回,他在系统中经过层层关卡。分层监控系统示意图一般我们将监控系统分为五层来考虑。当然也有人把它分为三层。大致含义类似,仅供参考:客户端监控,用户行为信息,业务返回码,客户端性能,Carrier,版本,OS等业务层监控,核心业务监控,如:登录,注册,下单,payment等应用层监控,相关技术参数,如:URL请求数、Service请求数、SQL执行结果、Cache利用率、QPS等系统级监控,物理主机、虚拟主机参数主机和操作系统。例如:CPU利用率、内存利用率、磁盘空间。网络层监控,网络状态参数。例如:网关流量情况、丢包率、误包率、连接数等。通俗的监控系统都讲过监控系统的功能、分类、分层。相信大家对IT监控系统都有一定的了解。接下来,让我们看看一些好的做法。下面介绍两款比较流行的监控系统:ZabbixPrometheusZabbixZabbix是一个企业级的分布式开源监控解决方案。它由AlexeiVladishev创建,并由ZabbixSIA持续开发和支持。Zabbix能够监控网络参数、服务器健康和软件完整性。它提供了一种通知机制,允许用户配置警报以快速反馈问题。Zabbix基于存储的数据,提供报表和数据可视化,支持主动轮询和被动抓取。它的所有报告、统计数据和配置参数都可以通过网页访问。Zabbix的API功能非常完善,大部分操作都提供API接口,方便与现有系统集成。例如:通过历史数据查询API,获取在线服务器使用情况,生成报表;设置条件,过滤问题服务器和问题服务,添加告警。使用ZabbixGraph的API生成关键指标的趋势图,方便运维人员实时了解系统状态。使用告警添加API,链接监控系统和部署系统。例如,如果部署了一个新的实例,会自动添加需要的监控策略;否则,如果实例离线,则关联的监控策略将被删除。Zabbix由Server、Agent、Proxy(可选)组成:Agent负责收集数据并传输给Server。Server负责接受Agent的数据,保存或报警。Proxy负责代理Server收集Agent传输的数据并转发给Server。Proxy安装在被监控的服务器上,用于与服务器通信传输数据。Zabbix的部署方式Zabbix的数据采集主要有两种方式:Server主动拉取数据和Agent主动上报数据。以服务器拉取数据为例,用户在Web-portal中设置需要监控的机器,配置监控项,告警策略。Zabbix-Server会根据策略主动获取Agent数据,然后存储到MySQL中。同时根据用户配置的策略,判断是否需要告警。用户可以在网页上以图表的形式查看各项指标的历史趋势。在Zabbix中,Server主动拉取数据的方式称为ActiveCheck。这种方式配置起来比较方便,但是会影响Zabbix-Server的性能。所以在生产环境中,一般会选择主动向Zabbix-Server推送数据的方式,称为Trapper。即用户可以定时生成数据,然后按照Zabbix定义的数据格式,批量发送给Zabbix-Server,可以大大提高Server的处理能力。Proxy作为一个选项,起到收集Agent数据并转发给Server的作用。当Server和Agent不在同一个网络时,需要使用Proxy进行远程监控,尤其是远程网络有防火墙的时候。同时也可以分担服务器的压力,减少服务器处理连接数的开销。普罗米修斯(Prometheus)随着近年来云环境的发展,普罗米修斯被广泛认可。它的本质是一个时序数据库,Zabbix使用MySQL进行数据存储。从我们上面对时序数据库的分析来看,Prometheus可以很好的支持大数据量的写入。它采用拉取方式(Pull)从应用中拉取数据,通过Alert模块实现监控和预警。据说单台机器可以消费数百万个时间序列。我们来看看Prometheus的几大组件:PrometheusServer,用于收集和存储时序数据,负责监控数据的采集、存储和查询。监控目标配置,PrometheusServer可以通过静态配置管理监控目标,也可以配合ServiceDiscovery(K8s、DNS、Consul)实现动态管理和监控目标。监控目标存储,PrometheusServer本身是一个时序数据库,将采集到的监控数据按时序存储在本地磁盘中。针对监控数据的查询,PrometheusServer提供了自定义的PromQL语言来实现数据的查询和分析。ClientLibrary,客户端库。为需要监控的服务生成相应的Metrics,暴露给PrometheusServer。PrometheusServer来Pull时,直接返回实时状态Metrics。通常与乔布一起工作。PushGateway主要用于短期工作。由于这类Jobs存在的时间很短,可能在Prometheus来Pull之前就消失了。为此,这些Jobs可以将他们的Metrics直接推送到PrometheusServer。出口商,第三方服务接口。将Metrics(数据收集)发送到Prometheus。Exporter通过HTTP将监控数据采集端点暴露给PrometheusServer,使其可以通过Endpoint端点获取监控数据。Alertmanager在收到来自PrometheusServer的Alerts后,将对数据进行处理。比如:去重,分组,然后根据规则,发出告警。WebUI,PrometheusServer内置的ExpressBrowserUI,通过PromQL实现数据查询和可视化。Prometheus架构图说完Prometheus的组件,我们来看看Prometheus的架构:PrometheusServer定时从Jobs/Exporters中拉取Metrics。同时也可以接收Pushgateway发来的Metrics。PrometheusServer将接收到的数据存储在本地时序数据库中,并运行定义的alert.rules(告警规则),一旦满足告警规则就向Alertmanager推送告警。Alertmanager根据配置文件对接收到的告警进行处理,例如:发送邮件告警,或者使用第三方组件告警。WebUI/Grafana/APIclients可以使用PromQL查询监控数据。最后将两款工具进行对比如下:Zabbix和Prometheus对比图从上面的对比可以看出Zabbix更加成熟,上手速度也更快。高度集成导致灵活性差,监控复杂度增加后,定制化难度会增加。而且,使用的关系型数据库对于大规模监控数据的插入和查询也是一个问题。Prometheus上手难,定制化灵活性高,数据聚合有更多可能性,有时序数据库支持。Zabbix在监控物理机或者监控环境比较稳定的情况下优势明显。如果监控场景多为云环境,推荐使用Prometheus。总结监控系统思维导图监控系统对IT系统运维具有重要意义,从状态监控到数据采集/分析,再到故障报警、问题解决,最后归档报表,辅助运维回顾。监控系统分为三类,日志、调用链、度量。它们各有特点,应用场景也不同。因为需要对整个IT系统进行监控,所以分为五层,即客户端、业务层、应用层、系统层、网络层。Zabbix和Prometheus是目前比较流行的监控系统,可以根据各自的特点进行选择。
