技术开发 频道

百万级报警平台的架构设计与实现

  【IT168 技术】本文根据肖双2018年10月19日在【第十届中国系统架构师大会】上的演讲内容整理而成。

  讲师介绍:

  肖双,去哪儿网高级运维开发,目前负责去哪儿网监控系统的设计、开发和运维工作,对DevOps理念有深入理解,深入实践自动化运维。

  文章摘要:

  监控是每个公司基础架构中不可缺少的一部分,如何构建适用于公司不同阶段不同需求的监控系统需要技术团队不停的探索和尝试。本次分享主要以去哪儿网百万级监控报警设计与实现为核心,讨论去哪儿网Ops团队在建设监控系统期间遇到的问题和解决的方法。

  演讲大纲:

  ·Watcher监控系统的介绍及架构展示;

  ·报警系统的设计和演进;

  ·报警遇到的痛点和解决办法。

  正文演讲:

  一.Watcher监控系统的介绍以及架构展示

  去哪儿网早期用的是Cacti+Nagios的监控方式,同时这也是当时比较常用的一种监控架构,Cacti用作展示,Nagios用作报警。

  我们早期的架构和上图类似,当时每个部门做了一套Cacti+Nagios,这样做的好处是分散了压力,每个部门之间的报警互不影响。但是随着业务量和报警量的增长,这种架构的缺点就被愈加放大了。

  当时存在很多问题,首先就是Cacti的单机部署不能横向扩展,性能差,非高可用。其次,各部门都需要维护一套甚至多套的Cacti+Nagios,随着报警量的增加,我们不得不不断增加Cacti+Nagios的部署,这样一来,运维成本也在不断增高。第三,报警配置由专人负责,不能由开发人员定制,效率低。如果开发人员想要加一个报警,那么它就需要去和专门负责报警的同事沟通,沟通成本非常高。最后是各个监控系统之间的数据不通,数据不通会给之后的自动化以及报警统计分析等等带来障碍。

  为了解决上述问题,2014年,去哪儿网开始自主研发监控系统,也就是我们现在一直在用的监控系统— Watcher,它是企业级统一的监控报警平台。

  Watcher是基于开源项目Graphite+Grafana深度开发,支持主机基础监控报警和业务监控报警,并提供了统一的管理展示界面,即统一的入口,所有报警都通过入口进行展示、查看和配置。

  当前Watcher在去哪儿网的应用规模是这样一个量级:监控的应用有1500+,监控的指标数是4000万+,每周的报警量是100万+。

  Watcher有四大特性,首先是用户自定义报警以及个性化报警。用户自定义报警指的是当数据打入到Watcher之后,Watcher会给这个数据直接生成指标图,点击指标图进行报警配置。个性化报警指的是在报警时只显示自己想要展示的内容,这是通过Watcher提供自定义的字段支持来实现的。

  自定义报警级别、报警升级和值班排班。服务肯定是有不同级别的,比如内网共享服务挂了和线上下不了单的重要级别肯定是不一样的。目前,我们支持P1到P4 4个级别,其中P1是较高级别,P4是最低级别。如果P1级别服务出现故障,直接打电话,而P4级别出现故障,他只会发短信进行报警通知。报警升级,目前我们P2和P3级别的报警比较多,这一类服务故障之后,首先会发短信进行通知,如果一段时间没有人去处理,就会升级为打电话通知,如果还没有人处理,就会通知更高级别的负责人。排班值班,当一个报警设置了很多联系人时,如果服务发生故障,可能所有的人都会在同一时间收到报警并进行处理,这样无形之中就增加了人力时间成本。而值班排班可以将这一组人定为一个组,设置每周或每天由一个人去值班,服务发生故障只会通知当前的值班人员。

  树形结构的指标和视图展示,树形结构对于指标的展示和管理是非常方便的。

  横向扩展能力强,数据高可用,理论上来讲,Watcher任意一层,比如展示层、报警层和存储层等都是可以很平滑地进行横向扩展,并且数据是高可用的,每一个指标的数据在每个集群中都会至少存两份,如果有任何一台机器挂了,不会影响当前的使用。

  这是Watcher的Web页面截图,即数据打入到Watcher之后,生成的指标图,直接点击编辑这个图就可以添加报警,比如设置报警名称、报警联系人等等。如果想要设置个性化报警,可以直接使用字段,而且还支持对报警做操作,例如设置Downtime或者添加回调等等。

  如图所示,我们可以把多个指标融合在一张图中,也可以把多个图放在一起,这样方便对比。

  上图是Watcher的逻辑架构,当然只是一个机房的。目前我们的数据打入方式分为两种,主机技术监控和业务监控。技术监控其实就是在远程主机上换一个agent,业务打入是在代码里面埋点,数据会首先打入Relay中,Relay起到的是路由负载均衡的作用,然后根据一致性哈希将指标数据汇入到后端存储层,同时Relay会利用Mirror去更新指标DB,指标DB中存储的是这个指标的元数据信息,例如指标当前存储在哪个集群的机器上。另外,指标DB是提供给Graphite-api使用的,Graphite-api取数据的时候会首先会去查询指标DB的元数据信息,拿元数据信息之后,去存储集群获取相应的数据。

  存储用的是Graphite的一个原生组件—Carbon+whisper。Graphite-api拿到数据直接提供给Dashboard和报警使用。

  上图是主机收集数据的流程,主机部署了一个agent即Collected,硬件管理平台会同步Collected配置文件,Collected定时收集数据,然后将这些信息打入到Watcher当中提供给Dashboard和报警来使用。

  上图是业务层收集数据的逻辑,我们用的是Qmonitor组件。Qmonitor分为server端和client端,client端就是在代码里埋点,server端会定期以Appcode为单位去拉取数据,并在自己的server端进行聚合,同时将聚合之后的数据打到Watcher当中。这样,Dashboard和报警都可以使用这个数据。

  二.报警系统的设计和演进

  去哪儿网早期的报警系统是根据Nagios开发的。熟悉Nagios的人都知道它是一个开源的监控软件,我们主要用的功能是状态检查,根据不同的状态及策略去发送报警。Nagios目前支持的监控方式比较多,我们使用的是NRPE。

  这是当时使用NRPE的基本原理,它分为nrpe daemon和check_nrpe插件。nrpe其实就相当于一个agent,部署在远程主机上。Nagios通过check_nrpe插件和NRPE进行通信,获取到远端主机的信息。

  早期单台Nagios支撑的报警数量是30万+,监控服务10万+。

  这是当时单台Nagios的架构,监控系统会下发配置到Nagios,Nagios定期检测所负责的主机上的服务状态。一旦状态发生改变,就立马发送通知,并且Watcher系统会通过NagiosAPI组件对Nagios做一些简单的操作,比如开关报警、设置Dowmtime等等。

  因为Nagios是单点,所以当报警量上来之后,会引发很多问题,例如单台Nagios Load非常高,长期处于一个高负载状态,而且响应慢,各个API耗时比较长。Nagios底层的操作实现其实是通过追加状态文件,如果这个文件比较大的话,那么它的操作时间就会越来越长。

  基于此,我们当时做了一次改进,改进方式非常简单就是直接加机器。然后,监控系统在下发配置的时候会进行一个哈希操作,将不同的配置哈希到不同的Nagios机器上,相当于达到了负载均衡的作用。

  在这种架构下,报警的支持达到了一个新的量级,报警数量达到了100万,监控服务达到了70万+。当时的通知方式包括短信、电话和qtalk。

  上述方式解决了前面提到的单点问题,但是还有很多其它问题等着我们解决。

  首先是无高可用,恢复时间长。如果任何一台Nagios挂掉的话,那么这个集群中的Nagios是没有办法平滑的去接管这台Nagios的配置,而且也无法去接管它的服务检测。

  其次是横向扩展难。因为我们做了一些哈希操作,所以如果你要想加一台机器的话,首先要改代码,然后配置肯定会有一个重新哈希的过程,比如本来被Nagios 1控制的服务,哈希之后可能就跑到了Nagios 3机器上。如果当时你对服务做了一些类似设置Downtime的操作,那么是没有办法平移到Nagios 3上的。

  第三是Web管理界面多。当时每台机器都有一个自己的管理界面,很多时候你根本不知道这个服务是被哈希到了哪台机器,所以在查找时需要一个一个去Nagios机器中找,很麻烦。

  最后是Reload时间长,不实时。因为当时Nagios没有提供相应的API去增删配置,所以我们做了一个简单的操作就是直接刷配置。但是刷配置会有Reload的过程,所以我们就做了一个硬限制——每次Reload的时间不能低于五分钟。在硬限制的情况下,就导致了一个报警可能要等5分钟之后才能生效。

  后来我们调研了Icinga服务,它也是一个开源的监控系统,而且还是Nagios开发者开发的,这也是我们决定用Icinga替换Nagios的重要原因,Icinga完全兼容Nagios配置,且兼容NRPE监控方式。

  上图是Nagios和Icinga的对比情况。Icinga是分布式高可用的,天生就是集群形式,横向扩展能力比较强。这样在集群当中下线或者上线一台机器,代码是完全无感知的。web管理界面统一,一个Icinga集群只有一个web管理界面。丰富的API,所有的操作几乎都可以通过API来进行完成,而且无需Reload,操作基本上都是实时的。最重要的一点是兼容Nagios和NRPE,这样我们的切换成本就会非常低。

  这是我们当前一个机房的Icinga逻辑架构。最上面一层是HA,对外暴露接口; HA下面是两个Master和Checker,在这个集群中,假如Master1挂掉了会自动平滑切换到Master2,如果Checker1挂了也会切换到Checker2。

  另外,集群中不同的区域也可以有不同的分工,比如Master区域只做报警通知, Checker区域只做状态检查。

  这是我们当时在测试Icinga和Nagios时的负载对比,在同等量级下的监控报警,Icinga比Nagios表现得更好。

  上图是操作对比,当报警比较多时,Nagios平均开关报警操作时间为15秒左右,而且如果Reload的话,我们有一个五分钟的限制。而Icinga的操作都是毫秒级,且是实时的。

  三. 报警遇到的痛点和解决办法

  第一个痛点就是报警细节太分散,历史记录晦涩难查。当你收到一个报警时,这个报警之前发给过谁、都有谁查看了报警或对报警做了操作……这些信息我们都是不知道的,如果开发人员想要知道,那么就只能求助于运维人员,然后运维人员登录报警平台去查看log,且我们的log也是有时效性的,隔段时间就自动归档了,所以查日志这个操作是非常耗时的,无形之中增加了开发人员和运维人员的工作成本。

  我们的解决方式是将所有的报警通知收集在一起做一条时间线。时间线是什么?就是从一开始故障到服务恢复这期间,它都发了哪些通知,通知给了谁,谁在什么时间对报警做了哪些操作…..这个时间线其实和快递系统很类似,记录了服务从故障到恢复各个时间点的操作。

  报警分为事件和通知两个部分。于Icinga来说,如果服务从OK状态变成了Error状态,就是一个报警事件。一旦报警事件发生了,就会进行报警通知,且通知可能会有很多次。所以事件和通知是一对多的关系,但是它俩太分散了,如果能够把它们串联起来,那么时间线就比较清晰了。

  所以我们做了一个全局的事件ID。当服务发生状态改变时,会出现改变时间,记录下这个时间,再根据监控项目的哈希和当前报警状态,生成全局唯一的事件ID。

  有了事件ID之后,我们就可以把这些东西都串联在一起。因为我们有多个机房,所有需要把所有机房的事件和通知都收集在一起。

  上图是当时时间线的架构,一旦发生状态改变,Icinga会生成一个事件ID,直接到达消息队列里,然后存储到DB当中。而且在发通知时会带着事件ID到各个通知平台,然后通过平台到达用户。这时如果通知平台收到了返回的消息也会进入到队列中,并存储到DB当中。

  这样的话,用户端就有了事件ID,可以直接点击事件ID看到当前事件处于什么状态。

  这是Web端截图,表格当中的每一条都是一个事件,记录了这个事件当前的状态或者最终状态以及报警开始的时间。另外,我们还可以对它进行一些操作,比如说直接点击跳到Watcher系统上查看报警当时的设置配置或者进入到详情页。

  这是详情页,这里可以看到报警的开始时间,几分几秒拨打了电话,电话打给了谁,谁接到了电话并关闭了报警,之后通知了谁,报警何时恢复了……一眼看过去就可以全部了解到,而且还可以在这里做一些报警操作。

  这是我们手机版APP的截图,如果你在qtalk上收到了报警之后,可以直接点开看到报警的详细信息。

  第二个痛点是重要报警被淹没。基于部门业务性能的不同,每天可能会收到很多报警,尤其是在早期没有进行分级的时候,可能所有的报警就一下子全都涌进来了,很难去分辨哪些是重要的,哪些是可以等待的,而且重要信息很容易就被其它信息刷屏过去了。

  基于此,我们做了报警分级,即将不同的服务分成不同的级别,很重要的服务就设成P1级别,其它服务按照重要程度设置成其它级别。一旦发生故障,你只需优先处理电话通知的故障,而qtalk或短信通知的故障可以延迟再去查看。

  第三是收报警体验差。有时一个报警设置了很多接收人,一旦报警来了,大家的手机都在不停响,浪费开发人员的时间。

  针对这个痛点,我们做了报警排班的优化,我们可以给开发组设置一个组,每周设一个值班人员,一旦有了报警先发给值班人员去处理查看,假设值班人员没有处理报警,过一段时间报警还会继续发送给开发B,依次循环直至有人去处理报警。

  第四个痛点是无主服务,持续报警。这是我们最近遇到的一个问题。由于一些历史原因,报警或服务可能处于无人管的状态,又或者是原来添加报警的员工离职之后,新来的员工并不了解该报警,不敢随便去关报警。这样就可能造成报警不停的去发,形成了报警骚扰或者淹没掉重要信息。

  我们做的优化就是报警下沉,如果报警持续了一段时间还没有人处理,那我们就会降低报警间隔。比如刚开始服务故障,它会一分钟发一次报警,如果持续了一个小时还没有人去处理,那就会变成五分钟发一次, 如果两小时了没人处理就变成十分钟……报警间隔越来越大,大大降低了无效报警的情况。

  分享到这里,其实基础的报警系统已经完成了,但我认为这只是完成了报警的初期功能,未来报警中应该具有更多智能化的模块或元素,承担更多的责任。

  分类降噪,如果发生了稍微大的故障,可能会一下子涌进来大堆的故障,信息看不过来,电话也接不过来,很容易遗漏重要信息。分类降噪就是在出现这种情况时,将报警做聚类、聚合、收敛等操作。再根据报警的不同类别和重要程度以及不同的策略去进行发送。

  多维关联,就是当服务故障时,它会自动的去触达到其他周边,比如上下游的服务或者日志信息,并反馈给用户,帮助开发人员或运维人员快速定位问题。

  智能分级,刚才的报警下沉其实也算智能分级的一个尝试,报警下沉是针对不怎么重要的服务,而智能分级是针对比较重要、优先级比较高的服务,这时我们要做的不是下沉,而是报警扩散,在联系到了联系人之后还没有去处理报警的话,我们就应该对报警进行扩散,让更多的人或资源参与进来,快速解决问题。

0
相关文章