大型互联网公司海量监控系统设计
(一)背景近些年来,随着互联网的迅猛发展,各大互联网公司的服务器数量不断膨胀,如今十万级别的服务器规模,已经不再罕见。再加上虚拟化技术的成熟,每台物理服务器可以虚拟出多台虚拟子机,虚拟子机也会当成物理服务器进行监控,因此监控的机器数将是一个更庞大的数字。海量运营,监控先行,设计一个能支撑百万级海量服务器监控的系统,提升每人运营机器数,将成为海量服务器运营的关键。(二)需求2.1基础性能数据采集如同厨师做菜必须有食材一样,监控系统首先也需要拿到原材料——基础性能数据。服务器的基础性能数据包括如CPU使用率、CPU负载、内存、磁盘容量、网络IO、磁盘IO、ping探测状态等周期性上报数据,还包括在服务器上检测进程端口存活性、系统重启、硬盘只读等产生的原始告警数据。采集到的数据,汇聚到中央,进行数据的存储与告警分析,再通过多种维度的图形化界面展示,让运维人员可以对服务器的基本运行情况了如指掌。2.2自定义监控项上报通道基础性能数据可以覆盖常见的监控场景,但对于业务运维人员来说,经常需要进行一些自定义监控项的采集。一种是数值型数据,例如运维人员想监控某个进程的一个内部变量值,如用户在线数。作为公司统一的基础架构监控系统,显然无法直接支持这种自定义监控项的采集,但可以向业务开放自定义监控项的上报通道。业务侧可以在进程里调用上报通道的接口,把用户在线数上报到监控系统,这样监控系统就可以对用户在线数进行图形化展示以及告警检测。另一种是字符型数据,例如有时业务运维人员会写脚本进行一些异常监控,当出现异常时可以调用上报通道的接口直接上报告警。监控系统的上报通道屏蔽上报细节、屏蔽与短信网关、自动语音系统等的交互细节,把简单的接口提供给业务人员实现上报。运维人员首先在监控系统为上报的数据申请一个唯一的ID,然后在进程或监控脚本中调用接口,使用这个ID来上报数据。这样,业务运维就可以在监控系统查看该ID的曲线图或字符型数据。同时,还可以为这个ID设置一些告警策略,当符合某个告警规则时发出告警通知。
2.3告警假设我们需要对某个进程的存活性进行监控告警,如何实现呢?运维人员可以写一个脚本,定期扫描进程,一旦某个进程不存在,则调用短信接口进行通知。但这种刀耕火种的方式,存在很多问题:
1、一旦进程不存在,每个扫描周期都会产生告警短信,大量的短信降低了告警短信的价值,而且可能淹没其它重要告警。
2、如果需要临时停止监控,只能逐台机器停掉脚本;继续启用监控时,又需要逐台机器启动脚本。
3、有时需要过滤掉抖动类的告警,例如希望在进程持续一段时间不存在的情况下才告警,对进程停止但很快又自拉起成功的告警希望忽略。
……
如果服务器数量少,这种方式可能还扛得住,但对于海量服务器,是无法接受的。因此海量服务器的监控,需要有一个统一的告警平台,可以根据各种告警策略进行检测,对原始的告警进行屏蔽、去重、合并、收敛等处理后,最终只发出最有价值的根因告警。
2.4数据分析作为海量服务器的监控系统,每天可以收到大量的基础运营数据,这些数据蕴含着巨大的商业价值,对这些数据深度挖掘,可作为一些决策的参考依据,如机型选型、资源匹配、故障预判、流量计费等,这对于降低成本、提升可靠性有着重要意义。
监控系统的基础运营数据,也会通过数据转发、API调用等方式开放给公司各个业务的运营团队,结合业务自身工具与运维体系,将能最大程度发挥数据价值。
(三)实现难点与解决方案3.1采集层3.1.1 实现难点采集层是整个监控系统的根基。为支持数据采集,并向业务开放上报通道,保持最大的灵活性,我们通过开发一个运行在服务器上的agent来实现。而海量的服务器带来的海量agent,使采集层面临如下挑战:1.稳定与安全agent运行于公司赖以生存的海量服务器之上,若因agent异常而导致大量业务服务器故障,将造成严重事故。因此稳定与安全永远是第一优先级2.海量agent接入对于百万级的agent,显然无法通过一台服务器来支撑所有agent的接入。一方面,我们希望能利用尽可能少的服务器完成海量agent的接入,另一方面,接入层需要可以支持平行扩展,即使支撑千万级agent,只需要扩容接入点即可,无须对整个架构做大的修改3.海量agent管理海量的agent显然不能依靠人工来进行管理。需要有一套完善的系统来实现海量agent的自动化管理4.非扁平网络理想的网络世界是扁平的,但现实中,经常会出现因为某些网络限制,或是安全上的考虑,或是业务的特殊需求等,导致网络不可能扁平。采集层需要适应各种特殊情况来支撑监控。
下面来看看如何应对这些挑战3.1.2 agent设计如何设计一个稳定安全的agent?Unix的一个哲学,便是一个程序只做一件事,保持简单。当程序保持简单,足够的内聚,便可将复杂度降至最低,易于维护,最大可能地避免BUG。基于这个原则,我们对agent基于功能进行拆分,把agent拆分成一组高内聚,低耦合的进程,包括:
1、主控进程:提供上报通道,负责数据上报,升级管理。
2、采集进程:负责性能数据采集与原始告警检测。
3、调度进程:负责对agent插件的调度。
进程之间通过共享内存解除耦合。主控进程生成一块共享内存,并提供共享内存操作接口,采集进程采集到数据后,只需要调用共享内存操作接口,把数据扔到共享内存即可,无须理解数据上报到服务端的细节。数据的上报完全交给主控进程来完成。通过共享内存操作接口,实际上也是向业务开放了数据上报通道。业务进程需要上报一个性能数据,或是上报一个告警,只需要调用共享内存操作接口即可。有时候运维人员需要自己写脚本,实现一些自定义监控项的采集。但这会涉及到一个脚本部署的问题。如果这个脚本需要部署在大量服务器上,没有自动化运维工具支持的话,将是一个繁琐的过程。因此agent还实现了插件机制,运维人员的自定义监控项采集脚本可以作为agent的一个插件来实现,提供了良好的可扩展性。
3.1.3 agent接入为实现大量agent的接入,服务端进程接入collector尽可能保持简单,只做数据转发,不负责数据处理。而agent只是周期性做数据上报,连接大多数时间是空闲的,因此这种场景非常适合使用epoll来实现。接入collector内部使用内存消息队列将数据接收和数据转发解耦,可达极高的吞吐量。单台接入collector可支撑10W agent的接入。
尽管接入collector性能极高,但对于百万级的agent,需要实现分布式接入。一般会按地域搭建接入点,每个地域的接入点负责收集该地域所有agent的数据,再转发到下一级模块。这种分而治之的思想,使得agent接入可以平行扩展,任何时需要扩容,搭建新的接入点即可。
因为接入collector只做数据转发,不做数据处理,使得collector支持级联。通过级联,可以适应非扁平化网络。假设某个网络区域出于安全性的考虑,只允许少量机器对外通讯,这种限制会导致大多数机器的agent无法连接collector。针对这种场景,可以在允许对外通讯的机器上搭建collector,让该网络区域所有agent都上报到这个collector,再利用collector的级联能力,把数据转发到普通网络区域的collector,达到数据上报穿透的目的。
3.1.4 agent管理程序总是需要增加新功能,或是修复BUG,agent也一样不可避免需要发布新版本。而对于百万级的agent,显然不可能人工进行版本发布,必须有一套自动、高效、安全的方法来实现agent版本的管理。agent的版本管理需要具备如下功能:1.版本记录记录每个agent的版本,知道哪台服务器运行着哪个版本的agent,这是我们进行版本升级的决策基础
2.自动升级需要进行升级的时候,只需要配置升级规则,就可以在短时间内无须人工介入地自动完成版本更新
3. 灰度部署agent运行在至关重要的服务器上,每次发布都必须严格控制风险,因此必须具备灰度能力。升级时,支持先小范围对非重要服务器进行更新,稳定运行后再逐步更新到其它服务器
4. 版本回退如灰度过程发现BUG,需要很方便地支持agent版本的回退
5. 安全性为保证下发文件的完整性与安全性,升级进程和agent需要对版本文件进行严格的校验
3.2存储层agent上报的数据分两种,一种是数值型数据,如当前的CPU使用率、流量值等,这是一种时间序列的数据;另一种是字符型数据,即异常时上报的告警。字符型数据会经过告警平台的去重、合并等,最终存储下来的数据量并不大,直接使用关系数据库存储即可。而数值型的数据则会大得多。agent会周期性上报服务器的各种基础性能数据,再加上业务自定义监控项的采集,平均每个agent上报的指标个数可达50-100左右,上报频率在1分钟-5分钟之间,每秒需存储的指标个数在50W以上,百万级的agent每天可以产生的100G以上的数据。告警系统、各个业务系统会频繁访问agent最新上报的数据,进行大量的告警分析和统计,因此还需要提供高性能的查询能力。
传统关系数据库如MySQL很难支撑如此大量的数据的读写。因此,我们需要设计一个分布式的时间序列数据存储系统。在存储机上,使用共享内存+文件的方式来保存数据,共享内存提供热点数据的快速查询、更新能力,文件则提供数据的持久化。文件的存储上,基于时间序列数据的访问特点,合理设计索引,并将索引数据内存化,使得能以最少的随机读盘读写次数来得到数据。分布式设计上,设计了高效、分布均匀,易于扩容,具备容灾能力的路由规则,数据写入和查询时,根据路由规则命中到对应的存储机上。这样设计的分布式时间序列数据存储系统,达到了高可用、高性能,并具备良好的平行扩展能力的要求,得以支撑海量agent数据存储。
3.3告警层3.3.1 实现难点告警平台作为整个监控系统最核心的部分,直接关系到监控的可靠性、稳定性。如何对海量告警进行去重、合并、相关性收敛,做到不误告警,不漏告警,还不能多告警,并具备高可用、易扩容、易扩展特点,是一个巨大的挑战。
在功能需求上,告警平台需要具备如下功能:首先,告警平台需要支持各种各样不同类型的告警,例如针对服务器的Ping不可达告警、磁盘容量告警、流量告警、进程端口告警等,针对业务的自定义监控项的告警,还有针对网络的各种流量、质量告警等。告警平台需要进行这些告警检测,产生原始告警。
其次,海量的服务器每时每刻都有大量原始告警产生,显然不能每出来一条告警就发出一次通知。因此除了原始告警检测,告警平台至少还需要具备下面的功能:
1) 屏蔽:日常运营中不可避免需要对某些可预知的告警进行屏蔽。
2) 去重:当一个告警通知负责人后,在这个告警恢复之前,负责人不会希望继续收到相同的告警。
3) 抑制:为了减少由于系统抖动带来的骚扰,还需要实现抑制,例如服务器瞬间高负载,可能是正常的,我们可以不关注,只有持续一段时间的高负载才需要重视。
4) 恢复:运营人员不仅需要知道告警的产生,还需要知道告警什么时候恢复。
5) 合并:有时需要对同一时刻产生的多条告警进行合并,例如某个服务器同一时刻出现多个不同进程的告警,需要把这多个进程告警合并成为一条进程告警。
6) 相关性收敛:有时某个告警产生时,往往会伴随着其它告警。例如某个服务端进程不存在而产生进程告警时,会伴随着一些端口告警,对于一个智能的告警系统,应该只需要通知进程告警,而剩下的端口告警则会被收敛,作为该进程告警的子告警。当某个机架所有服务器都Ping不可达时,应该只需要发出一个机架掉电告警,机架上服务器的Ping不可达告警作为该机架掉电告警的子告警。
在质量需求如下,告警平台还需要具备如下特点1)高可用:作为海量服务器监控的核心,告警平台的关键功能必须达到5个9的可用性,做到不误告警、不漏告警,不多告警,只有这样,才能让运维人员对告警平台产生信心,保持对告警的警惕性。因此,告警平台每个子模块都必须有完备的容灾、容错能力,单机故障时可平滑切换到备机。甚至当出现地震、海啸等不可抗拒自然灾害时,也可平滑实现异地容灾。
2) 易扩容:告警系统每时每刻都会有大量的原始告警产生,还需要进行各种屏蔽、去重、恢复等的判断,单机无法支撑如此海量的告警分析,支持平行扩展的分布式系统是必经之路。
3)易扩展: 随运营精细化需求,随时都可能需要支持新的告警类型,因此当有新的告警类型时,需要能非常快速方便地接入,复用整个告警屏蔽、收敛、去重、合并的通道。
3.3.2 架构设计在架构上如何设计整个告警系统呢?因为整个告警环节多,链条长,为降低系统复杂度,提升可维护性,可以将整个告警流程进行多个维度的拆分:
1) 对告警流程纵向拆分,形成流水线。每个告警子模块接收上一个流程过来的数据,处理后,发送给下一个流程的告警子模块处理。
2)对每个流程环节的告警子模块横向拆分,每个流程环节都可以运行多个告警子模块,模块之间互相负载均衡。
3)对告警逻辑的拆分,每个告警子模块只做一件事,单一职责。例如,告警屏蔽模块,只处理屏蔽的处理,告警恢复模块,只做恢复的判断。
同时,引入消息队列,使告警子模块之间的通讯异步化,解除告警子模块之间的耦合。
最后,引入全局高可用Cache,所有内存数据均放到全局Cache,使每个告警子模块不带状态,形成无共享架构(Share Nothing Architecture)。
这样的设计带来很多好处:首先,每个告警子模块高内聚,低耦合,非常方便维护。其次,这种搭积木式构建的系统,功能易扩展,即使需要在告警流程中增加一个环节,只需要增加新的告警子模块,整个系统架构无须改造。而且,带个告警子模块都是无状态、负载均衡,可平行扩展的。某个环节出现性能瓶颈,多运行几个告警子模块即可,达到了监控海量服务器的能力。
3.3.3 相关性收敛设计告警平台设计的另一个难点是告警的相关性收敛。假设某个机房掉电,必定出现大量的Ping不可达告警。相关性收敛需要对这种情况做出识别,收敛成一条大规模故障告警,而所有的Ping告警则作为该大规模故障告警的子告警。如果没有相关性收敛逻辑,运维人员将被淹没在大量告警中,根本无从判断故障。相关性收敛对于快速得到根因告警,提升告警处理效率具有重要意义。
实际运营中存在大量的相关性收敛逻辑,如端口告警可以被进程告警收敛,交换机下服务器Ping不可达告警可以被交换机Ping不可达告警收敛等。如果直接把这些收敛逻辑加入到告警流程,告警流程将非常复杂庞大,且难以维护。因此,告警相关性收敛可以采用“旁路反馈机制”,它的原理是由单独的模块分析相关性,再将结果反馈给收敛模块。收敛模块仅仅是一个收敛处理引擎,不负责分析相关性。这样避免了收敛分析串行化的性能和功能扩展的难题。要增加新的相关性规则,只需开发和平行部署新的分析模块即可,不会影响到当前的收敛策略。随运营经验的沉淀积累,以及业务的发展、监控手段的增加,可以逐渐加入新的相关性分析模块,使告警平台更加智能化。
(四)腾讯实践基于上面的思路,腾讯网络平台部实现了针对海量服务器监控的系统Tencent Monitor Platform(简称TMP),具备支撑百万级服务器运营监控的能力。
采集层,通过Agent进行数据采集,打造跨越非扁平网络的数据上报通道,实现百万级Agent的自动化运营管理。
存储层,通过自研的分布式时间序列数据存储系统,实现海量监控数据的存储与快速查询。
告警层,基于无共享架构,纵向拆分告警流水线,使用消息队列异步通信,逻辑链解耦,实现了各种告警的合并、去重、相关性收敛,打造出一个高可用、易扩容、易扩展的告警平台。
页:
[1]