去哪儿网企业级监控平台-Watcher

2023-04-24 00:00:00 自己的 指标 告警 监控 报警

一、背景

目前开源的监控系统越来越多,不同的系统针对的侧重点和特性也不同,像 Zabbix/Nagios 这种老牌的监控系统侧重于主机系统层监控和告警,比如 Zabbix 和 Nagios 都自带有一套完善的系统层面监控插件,而且还允许运维很方便的利用 Shell 脚本或任何其他脚本语言来扩展自己想要的插件,同时 Zabbix 还提供了比较便利的 Discovery 功能,创建一套模板后,便能自动发现和检测相应主机状态,省掉了繁琐的配置过程。而 Graphite/Prometheus 这样的则更兼顾业务应用层监控,它们提供了一套机制,应用可以在代码里记录自己在运行时的状态数据,然后通过 Exporter 或者 Push 的方式将状态数据暴露或推送到 Server 端,Server 存储在时序 DB 中用于之后的分析、查看和告警等。

很多企业在用开源软件的一个路径大概都是这样的,纯开源使用 → 少量的定制化开发或外层封装 → 深度的二次开发 → 自研。 

去哪儿网的监控平台早期的时候用的也是用的纯原生方式,但随着之后的发展这种形式已经不能满足我们的需求,因此我们开始设计自己的监控系统,从用户角度看我们要提供统一入口的一站式的监控平台,避免开发在各个系统间跳来跳去,要更友好的支持应用监控,要有更便捷的指标查看和快速定位,要更方便的让用户自己配置告警以及告警升级之类的告警操作等。基于此我们开发了 Watcher 监控系统。

Watcher 是去哪儿网内部的一站式监控平台,它的开发方式是大部分自研组件加上小部分二开组件的方式完成的。目前每分钟收集存储的指标总量在亿级,检测和处理的报警量是百万级的。因为考虑到数据量比较大,所以我们要求监控体系中任何组件都能够很好的水平扩展。

二、打造符合需求的企业级监控平台

由于早期使用的开源监控已经不能满足我们的需求了,因此我们需要考虑建设自己的监控平台。这个平台要能解决几个问题:

  1. 提供一站式监控告警的能力

  2. 提供更友好的应用层面或应用维度的监控能力

  3. 统一监控资源,让用户自己管理,同时提供足够方便的快速排障能力。

  4. 使用简单,因为用户是面对全公司的,其中有技术同学和非技术同学,所以要避免过高的学习和使用成本。


1. 平台核心功能设计

Grafana 本身就提供了很的监控绘图能力和多数据源的支持,并且是非常的灵活,允许用户从各种数据源选择指标数据绘制各种类型的图表并保存下来。但 Grafana 在企业的使用中也是会有一些不便的,比如:

  • 查看指标不够便捷,早期的 Grafana 是没有 Explore 功能的,用户在 Grafana 中查看指标必须要先新建一个 Panel,然后在 Panel 中输入对应的查询表达式才能看到自己的指标,这对于有很多指标,并且只是临时性的查看一次的这种场景来说就极为不便了。

  • 面板管理不方便,新版的 Grafana 给面板增加了目录和标签功能,但是对于面板比较多组织架构比较深的时候管理仍然不够便捷。

  • 没有模板功能,比如在一些主机监控的场景中,我们要查看主机的监控内容基本是一样的,比如主机的 CPU、内存、Load、网络、磁盘等等,在这种场景如果每台机器都要手工的配置出来一个面板,那工作量还是很大的,即便是使用 Variables 能力(早期叫 Templating),在主机量很多时,在下拉框里去搜索使用也很困难。

  • 报警功能无法满足企业需求


基于这些原因我们的控制面选择对 Grafana 进行二次开发。

Watcher 整体上分为应用空间、公共空间、用户空间、报警空间、全局配置、系统配置等6个功能模块,其中

  • 应用空间:以应用为维度管理所有的监控资源,包括用户自己上报的指标数据和当前应用下的主机、Pod、DB、redis、负载均衡等监控信息。

  • 公共空间:公共空间提供了用户自定义面板的能力,以及多元的函数分析能力,用户可以在公共空间创建自己的面板进行多指标联合分。

  • 用户空间:类似公共空间,只不过属私人空间,其他人无权查看。

  • 报警空间:管理所有的报警,可以快速基于 appCode、指标、联系人等检索报警,以及修改和配置报警。

  • 全局配置:顾名思义提供了一些个人全局属性上的配置修改,如 主题、图上是否关联故障事件、用户组管理以及其他便捷的工具。

  • 系统配置:这部分控制监控平台的一些展示行为和全局的插件配置,只有管理员有权限。


下面介绍下我们平台的部分核心功能设计:

1.1. 应用维度的监控管理

去哪儿网是以应用维度来管理各种资源的包括监控资源,我们给每一个应用会起一个标识叫做 AppCode,抽象出 AppCode 后,我们可以对这个 AppCode 可以在多个系统进行连通,多系统可以数据共享,而且在各系统设计时统一基于 AppCode 的概念来设计,这样对于所有人在使用这个系统时候也能降低很多理解成本。

因此我们在 Watcher 上创建了应用空间,应用空间管理了一个应用所有的监控资源,并且与服务树打通,可以快速检索或浏览自己的 appCode 。

多环境指标查看

Watcher 打通了环境管理,可以采集不同环境的指标如 prod、beta,并且能够自动列出当前应用的所有环境,用户可以快捷的找到自己对应环境指标。

指标检索和指标浏览

默认情况下,用户可以输入关键字或者正则来快速检索自己的指标,如上图,但如果实在忘记了自己的指标名,也是点击搜索框后面的指标树来浏览自己当前应用当前环境下的所有指标的。 如下图:

没错,指标也会被组装成一棵树形,不同于现在的 Prometheus 的 Tag 指标的扁平化形式,在 Qunar 指标命名也是层级化的,是以 "metic.name.xxx" 这种形式组合成一个 Metric,每一个点便是 Tree 的一级,树形结构天然带有目录作用,因此以树形结构组织一组指标可读性比较好。

单机维度指标

Watcher 在采集指标的时候除了记录每台主机上报的指标数据之外,还会自动聚合应用维度的指标,比如应用有3台主机上报了"myapi.qps"指标,那么每台主机都有自己的 myapi.qps 指标,同时会聚合出一个总的 myapi.qps 指标,而通常我们添加监控也是监控应用维度的 myapi.qps 指标,如果指标有波动想要继续排查问题,就需要看每台主机的 qps 是否有波动,这个时候就可以如下图点击指标上的 “单机数” 就会列出每台主机的 qps 趋势,方便用户定位根因。

应用主机资源监控

Watcher 打通了 CMDB,可以即时动态的的在应用空间中快速列出自己应用的主机/Pod 资源,以及这些资源的监控趋势,如 CPU、Load、内存、网络等等,无须任何手动的配置操作。

DB监控

同样的在应用空间,用户可以选择自己的 DB,这样就能自动列出当前 DB 的所有状态指标监控,方便用户快速定位 DB 问题。

域名监控

如果你的应用以域名的形式对外提供服务,那你只要输入自己的域名就能看到自己域名当前的一些 QPS 和网络流量等监控趋势。

1.2. 公共空间自定义面板管理

树形结构管理面板

我们将 Grafana 扁平化的面板管理改造成了目录树结构的面板管理,这在面板比较多的时候非常有用,而且层级分明对于人记忆和查找都比较友好,同时也提供了搜索功能,可以针对关键字快速搜索自己的面板。同时可以给目录树做更细致的权限管理,比如是否仅查看,查看和编辑,还是无权限访问等,这些权限也可以从父节点继承到子节点。

权限管理

树形结构上的权限很管理,由于实现了继承特性,用户想要在一定范围内添加或删除权限时不必一个一个节点去操作,只需要在父节点上设置对应的权限即可,比如在父节点设置了Owner权限那么也可以查看子节点的面板。

报警联动

在公共空间的面板上配置的报警,可以与面板状态联动,当报警发生异常时,面板上能立即感知到。

1.3. 报警管理

报警管理模块,解决了两个问题:

  1. 统一了告警配置和告警查看,用户不在需要到多个系统查看自己告警,告警依然支持根据 AppCode 来搜索自己配置过的告警

  2. 丰富告警周边组件,方便用户在发生告警时快速定位问题。比如 ①告警与 Trace 进行关联,当告警时可以检索到与当前异常指标有关的 trace id ;②与根因分析系统关联,当发生异常告警时,利用根因分析系统辅助定位。

告警管理分为业务告警和主机告警:

  1. 业务告警是指用户应用埋点监控的Metrics添加的告警,用户可以任意增加、删除、修改、设置通知联系人等。

  2. 主机告警这块我们实现了类似Zabbix的主机模板和Discovery功能,用户可以配置一类主机监控模板,同时设置Discovery规则,一旦当有匹配类别的主机上线,则自动应用这些监控和告警。

2. 告警治理

2.1. 报警升级

报警升级分为提醒升级和联系人升级,我们的报警升级没有强制联系人向上升级,但用户可以方便的在树节点上设置联系人(一般在树节点上设置相关负责人),树节点上设置的联系人,其子节点上的告警都会接收到,而且是前面的联系人都没人处理告警的时候(比如没有接听告警电话),才会通知树节点联系人, 因此利用这种形式做联系人升级。

提醒升级是当一个报警开始发送告警通知时,一开始我们只会发送 Qtalk 提醒,Qtalk 属于弱提醒,但如果过了一段时间这个报警仍然没有人处理,就会升级成电话提醒,电话提醒则是属于强提醒。

升级模板配置

2.2. 报警降噪

当配置的告警越来越多,很多告警都不是重要的告警,经过几轮人员更替后,这些告警都会成为极大的噪音,当它报警后,新来的同学不清楚这个告警是监控的什么东西,也不敢随便处理比如关闭告警,于是放任不管,那这些报警就会一直报着,长时间的没有人来出来。时间长了很容易引起相关人麻痹,导致错失重要告警的处理。针对这种情况,我们开发了降噪算法,算法只根据报警开始时间和设置的报警间隔,来计算出当前是否处于发送窗口,只有在发送窗口期,告警通知才能真的发送出去,否则不发送通知。以此达到的效果是 比如:当一个告警设置通知间隔是5分钟,但是持续了30分钟还没有人处理,那么我们会动态拉伸他的通知间隔,逻辑上将通知间隔变成了10分钟,1个小时没人处理则变成20分钟等等依次类推,这个告警持续时间越长,那么通知窗口也会被拉的越来越长,通知的频率就会越来越低,即便是他处在告警中。

2.3. 闪报抑制

在 Qunar,一个报警持续时间小于5分钟的报警我们称为闪报。很多时候我们刚开始配置报警时,尤其是一个新的报警,大家可能对阈值估算不准,或者由于很早之前配置的报警,之前设置的阈值已经跟现在的业务波动不太匹配了,就会导致报警波动、闪报。这种闪报通常来说不影响业务,但是频繁打扰会导致报警接收人麻木。因此抑制的目的就是减少无意义的打扰,尽可能提升报警的精准性。

当前报警抑制的实现方式是观察一个报警一段时间内报警状态改变的频率,如果频率高于某一个点(这个阈值点是系统根据算法算出并默认提供的,用户可以自己修改)则会进入抑制状态,频率低于某一个点则会退出抑制状态。其中半个小时内的状态多次改变则状态权重递增。

闪报抑制配置:

2.4. 报警收敛

当某一个时刻突然出现了大量告警,这会导致告警刷屏,在去看 Qtalk 告警消息时,根本就看不过来,一些重点的告警会被淹没掉,或者根本无法确定哪个告警有可能是需要重点关注的。在这些告警里一定会有一些告警是因为其他告警造成的,比如一台宿主宕机,主机上的 load、disk 等告警都会报出来,甚至可能影响到业务指标,导致某个业务指标告警。所以报警之间会有一个隐形的依赖,通常主机或机房层面的告警依赖非常清晰,属于物理依赖,而应用之间也有依赖,应用之间的告警就是逻辑依赖。

所以在做告警收敛时,依赖拓扑是很重要的,物理依赖可以很简单的计算或者定义出来,而多应用间依赖在 Qunar 可以通过 Qtrace 来拿到依赖拓扑,因此目前在 Qunar 当某一时刻出现大量告警时,会触发告警收敛,告警收敛会先在 Appcode 内收敛,根据依赖拓扑一层层收敛,AppCode 内收敛完成之后会进行 AppCode 间收敛,终只会将叶子告警发送通知,其他的只在详情页展示,并不真实发送通知。

这里面有一个难点,就是 AppCode 内配置的多个业务告警怎么拿到依赖关系(依赖树),目前 Qunar 将 Metrics 和 Qtrace 进行了结合,Qtrace 在记录方法间调用时如果经过的方法内有记录 Metric,那么会将这个 Metric 信息带入到 Trace 信息里,后经过洗数分析就能拿到指标间的依赖关系,根据指标间的依赖关系就能拿到告警的依赖关系。比如 一个 http 的入口方法  foo,此方法里记录了一个指标就是  foo.access.time,foo 调用了 bar 业务层方法,bar 业务层方法内记录了一个指标 bar.exec.time,那么指标  foo.access.time 就可以认为依赖 bar.exec.time,如果foo.access.time 和 bar.exec.time 同时告警,那么只有bar.exec.time 的告警会通知出去。

3. Trace结合

Qtracer 是 Qunar 自研的 Trace 系统, Qtracer 首先是一个全链路追踪系统,可以用来定位跨系统的各种问题;另外,通过收集链路中的各种数据达到应用性能管理(APM)的目的。而监控就是通过 Qtracer 收集链路数据的特性来做到跟 Qtracer 结合的。

首先 Qtracer 提供了 QTracer.mark() 方法,此方法能够将自己想要的信息关联进当前 trace 的 context 中, 然后在我们自研的 Qmonitor agent 中,在记录指标数据时调用  mark 方法,将当前指标标记进当前的 Trace 信息里面(如果当前有 Trace 信息的话),以此能达到的效果就是一个带着 Trace 信息的请求从入口进来(如果没有携带 Trace 信息,可以生成 Trace),经过了 foo() 方法,而 foo 方法中记录了指标 foo.access.time,那么 foo.access.time 指标会被 mark 到当前 Trace 信息中。

数据被 mark 进来后,当前会以日志的形式落盘,然后经过洗数,后会将 Trace 的 Trace Id 和当时经过的 Metric Name 的关联信息存入到 ElasticSearch 中便于后期检索使用。

当这些数据信息都没有问题的时候,此时比如我们在  foo.access.time 指标上加了一个告警,一旦指标告警,我们就可以检索出告警的这一段时间内所有的 Trace 信息,通过 Trace 信息能够快速的反应出当时请求的状态,以此来协助开发或应用 Owner 快速定位问题。

下图是在 Watcher 上拉取当前告警时间段的 Trace Id 信息:

点击 Trace Id 可以查看具体的 Trace 信息,以及调用拓扑等。

三、云原生时代监控平台的演进

2021年时,去哪儿网在公司内部进行了大规模容器化部署,到目前为止去哪儿网大部分的应用都已经运行在内部的多个 Kubernetes 集群上。在这样一个背景下早期我们许多根据 kvm 特性的相关设计也要跟着变化,比如容器跟 kvm 大的一个变化便是动态 IP 问题,kvm 的主机一旦申请后IP 是固定的,且 kvm 主机的生命周期远远长于容器,通常是跟 AppCode 同生命周期,而容器生命周期则非常短,每一次变更发布都会导致容器 IP 变化,这种频繁变化给周边系统带来了许多问题,因此周边系统也需要进行改造以应对这种变化。

1. 业务指标数据采集

Qmonitor 是 Watcher 的数据采集模块,虽然 Prometheus 有自己的 Client,但是想要让全公司的应用从Qmonitor 改成 Prometheus Client 显然不现实。而Qmonitor 早期设计是针对 kvm 的流程设计的,比如用户在通过 Qmonitor 监控时我们自动拿到对应的需要监控的主机名或 IP,然后通过 Pull 当前主机对应的 url 才能拿到监控数据。而容器的 IP 是经常变化的,因此我们修改流程,增加了 Discovery 的功能。

首先我们增加了事件监听器,用来监听和收集所有 k8s 集群的事件,然后将这些事件存储到 DB 的同时发送到 mq中,其他应用可以监听 mq 来拿到自己想要的事件。然后在 qmonitor 增加 client-discovery 模块,此模块可以监听对应的消息事件,然后动态的更替对应的 ip 和 meta 信息,更新的数据提供给 qmonitor server来使用。这样便能动态的发现和变更对应的 client 地址,而且对业务无感知。

2. 基础设施层监控

云原生时代,我们的基础设施层由 kvm 云变成了容器云, kvm 时我们使用的 collectd 来收集基础设施相关的监控指标,比如 cpu、磁盘数据。collectd 是一个 agent 需要安装在 kvm server 上,但是容器内通常只有一个进程,agent 的形式是不友好的。而 k8s 层的相关监控我们使用  prometheus+cAdvisor,k8s 自身便是使用 prometheus client 来 export 内部的状态数据再配合使用 cAdvisor 监控容器运行时的状态数据比如 cpu、内存。

2.1 融合Prometheus

我们的 Dashboard 是根据 Grafana 做的二次开发,而 Grafana 本身就支持很多的数据源插件,其中便包括 Prometheus,因此能够很方便的将 Prometheus 跟 Watcher 进行融合,集成后依然提供对用的 Pod 模板查看,允许用户直接通过自己的 AppCode 就能查看到自身应用下当前的 pod 状态,以及应用级的 pod 状态。

2.2 容器告警

容器的告警像 kvm 一样,也支持模板化,容器通过监听事件来将模板应用到对应 AppCode 上实现动态添加告警,模板包括了检测指标、检测规则、告警阈值等信息。由于 Prometheus 自身支持异常检测,因此可直接将告警规则通过 prometheus crd 同步到 prometheus,通过配置, Prometheus 检测到异常后,会将异常信息 Push 到 我们自研的 Alert-API 模块,Alert-API 可以说是 prometheus  到 icinga 的一个转换器,Icinga 是我们真正的告警管理模块,支持开关报警、告警升级等策略,Icinga 类似 Nagios,但是 icinga 提供了更友好的 API 操作入口。

四、未来规划

Metrics 的数据是比较简洁和标准的,所以我们很容易从宏观层面上观测分析和判断它正常与否,断言 Metrics 的成本也相对较低,但是想要定位真正的根因,还要借助 Trace、Log 的数据,比如通过 metrics 你只能发现现在系统处于一种异常状态,但到底是代码 Bug 还是什么原因造成的,就需要更详细的信息输入,而这些信息是 Trarce 和 Log 或者其他维度的数据提供的。因此接下来 Watcher 系统也会尝试融合 Trace、Log 以及更多维度的数据比如事件,其实从上面可以看到,Watcher 已经开始与 Trace 进行了融合,我们目前的方式是通过报警的 metrics 关联到 trace,如果指标发生异常了就能的检索出跟这个异常指标相关的 trace 信息,就能定位到哪些 trace 可能是有问题的,而更多的场景还需要我们去挖掘,目前业界也都在向这个方向演进。

关于智能监控部分,2022年底 Qunar 内部落地了根因分析系统,目前与 Watcher 的报警系统进行了联动,当出现告警时根因分析自动监听到告警事件,尝试从链路 Trace、日志、事件、中间件、运行时、物理拓扑探索等维度进行关联分析终将报告推送给用户,以此辅助用户快速定位问题。而动态异常检测雷达也还在落地中,用于弥补部分不易使用静态阈值断言的指标的异常检测。

相关文章