一、背景
伴随着大众井喷的出游住宿需求,去哪儿旅行酒店订单激增。watcher作为公司级的监控系统,承载着越来越重要的故障预警能力。但watcher当前给业务流量提供的数据精度都是分钟级的,以分钟级为精度的数据虽然也可以反映业务流量的情况,但对订单报警来说,其精度是有限的,因为分钟级的指标数据精度,带来的必然是分钟级的故障预警。因此每当故障发生时,故障的发现时间都要比故障开始时间晚几分钟。尤其是随着业务的增长,订单交易相关的故障还伴随着用户的订单赔付行为。
按照故障"1分钟发现-5分钟定位-10分钟恢复"宗旨,借助自身强大的研发能力和产品化能力,我们实现了订单监控精度提升到秒级。借助秒级监控预警,我们可以实时掌控瞬息万变的业务流量波动情况,及时发现业务中存在的问题,及时发现,及时解决,尽可能的减少订单损失,提升公司品牌信任度。
二、整体架构介绍
1、监控现状
上图为watcher业务监控的整体架构图,从图中可以看出,整体架构包括四个部分,分别为数据采集、数据查询、dashboard查看和报警。
数据采集:主要负责业务指标数据的收集和存储,在存储方面,watcher使用的是时序数据库Graphite;数据采集使用的是自研的采集器qmonitor,包括server、client、manager三个部分,其中manager为采集配置中心,client负责收集业务侧指标数据并上报server,server负责聚合数据并将数据存入时序数据库。
数据查询:API层,主要负责查询指标数据,包括简单指标查询和复杂聚合指标查询。查询api是在Graphite api的基础上进行了二次开发,并新增了指标源信息数据库,以满足分集群查询以及多种复杂条件查询。
dashboard:可视化层,用户可以通过dashboard进行指标数据查看、面板配置、报警编辑等操作,基于grafana深度开发。
报警:报警服务,报警状态检测负责对用户所配报警进行规则判定,若满足报警条件,则将此报警置为critical或warning状态;报警通知服务则使用了icinga服务,支持电话、qtalk通知(qtalk为去哪儿旅行自研办公软件)、短信通知,支持开关报警、downtime等。
以上四个部分,无论是qmonitor、数据存储、查询以及报警,数据点都是分钟维度的,若想支持秒级监控,便涉及到了全链路的修改和变更。而在秒级监控项目启动之前,基于以上架构,我们对watcher监控平台进行了摸排梳理,在此过程中,我们发现要想支持秒级监控,需要解决以下三方面挑战:
挑战一:存储IO过高和占用空间过大的问题
当前分钟级监控的时间序列数据库(TSDB)使用的是Graphite的Carbon和Whisper。由于Whisper的空间预分配策略和写放大问题,导致了磁盘IO压力过大,同时也占用了过多的存储空间。秒级监控带来的是精度的提升,但也同时会导致存储和写入的激增,因此解决监控数据存储的问题成为了首要任务。
挑战二:对Graphite协议的兼容性问题
目前分钟级监控的存储使用的是Graphite,监控数据的采集和查询协议都是基于Graphite的。为了尽可能在使用秒级监控时让用户无感,在构建秒级监控系统时,必须要考虑到对Graphite协议的兼容性问题。
挑战三:需要对整个监控链路进行修改以适应秒级监控的挑战
watcher现有的数据采集、数据存储和告警系统都是基于分钟级别设计的。如果要实现秒级监控,就需要对从数据采集到存储,再到告警的整个链路进行大规模的修改。
接下来,我们将会从存储改造、qmonitor客户端、服务端指标采集优化等几个部分进行重点阐述。
2、存储改造
1) 存储方案选型
由于当前存储Graphite不能支持秒级监控更大的并发,因此我们探索了新的存储方案。在综合了所有限制条件后,我们在选取存储方案时重点对M3DB和VictoriaMetrics(以下简称“VM”)两种解决方案进行了评估。选择它们是因为它们都支持Graphite协议。
在经过详细的比较后,我们发现无论是M3DB还是VM,都具有较高的压缩率和出色的存储和查询性能,都能够满足我们的需求。而考虑到M3DB的部署和维护相对复杂,而VM的每个组件都可以任意伸缩,部署较为简单,且社区活跃度也比较高。另一方面,VM在压力测试后展现出了较高的读写性能:单机读写可以支持高达1000万级的指标。因此最终我们选择了VM作为我们的时序数据库。
2)VM存在的问题:聚合读场景下性能下降严重
我们在对VM进行压力测试的过程中,发现其在进行单一指标查询时,性能表现出色,完全满足我们的查询需求。
压测表现:
服务器配置:32核CPU,64GB内存,以及3.2TB的SSD存储。
服务部署:vmstorage、vminsert、vmselec。
设定每分钟写入的指标数量1000万,查询QPS 2000。
压测发现,平均响应时间为100ms,写入一天的数据后,磁盘使用量约为40GB,而主机Load保持在5到6之间。
但是在进行复杂指标查询时,比如涉及到函数查询和聚合指标查询,性能会显著下降,甚至有时会超时。
3)改造方案:存算分离改造
为了解决这个性能问题,我们进行了一些改造探索。依据上文中的压测结果,VM在单一指标的查询上表现优秀,因此我们决定让VM专注于单一指标的查询,而复杂指标的查询和聚合由CarbonAPI来承担。选择VM并进行存储和计算分离改造后,成功解决了秒级监控的存储、查询和写入问题。
为什么是CarbonAPI
CarbonAPI是一套开源工具,不仅支持Graphite协议,还支持Graphite中大部分的聚合计算和聚合指标解析查询,但它对聚合指标解析查询的实现并不完整。
由于CarbonAPI是无状态的,可以任意扩展,研发团队就可以定制化一些功能,如监控处理、数据剪裁等。经过改造后,实现了存储和计算的分离,以支持非常高的查询QPS。
做了哪些改造
添加一个指标名元数据DB,每当一个指标写入VM时,会将指标名称和查询URL等信息存入元数据DB。然后,CarbonAPI在解析时,会将带有多个标签或函数的指标解析为单一指标,再放入VM进行查询。这样做有效地提升了VM的查询性能。
3、客户端指标采集优化
1)当前架构
上图所示为watcher当前数据采集架构,若想支持秒级监控,其存在的问题是:指标仓库和调度器不满足需求。watcher现有的分钟级监控主要依赖公司自主研发的SDK来进行数据采集,并未采用诸如开源的Prometheus SDK之类的工具。若想支持秒级监控,我们发现客户端存在一些问题:
问题一:调度器问题
Counter在完成一个指标计数后,会将指标及其相关数据存储在本地的Metric仓库中。调度器会在每分钟的固定时间从指标仓库中提取数据,生成一个快照并将其存储起来。当服务端需要采集客户端的数据时,它将提取这个快照,而不是直接从仓库中获取实时数据。这种做法与开源社区的实践有所不同。我们选择使用快照而非实时数据,主要是为了按分钟级别对齐数据,以便于服务端的处理。无论何时,无论服务端进行几次数据拉取,获取的都是同样的前一分钟的数据,且这些数据是固定的,不会再发生改变。
问题二:指标仓库问题
指标仓库只支持分钟级的数据存储,这是因为我们之前的设计都是基于分钟级别的。
2)解决方案:客户端进行多份数据计算和存储,生成多个快照
①方案选型
在对客户端进行改造的过程中,我们设计了两种方案。
方案一:参考了Prometheus的模式,即不生成快照,而是直接获取仓库的实时数据,仅进行数据累加或记录。当客户端拉取数据时,可以选择将原始数据存入TSDB,或自行进行增量计算。
优点:客户端节省内存。
缺点:
如果客户端自行进行增量计算,它需要获取前一分钟或者前一段拉取间隔的数据,然后才能进行增量计算。如果直接将原始数据存入TSDB,每次用户查看数据时,需要自行进行增量计算,这将影响用户体验。
尽管这种模式可以节省客户端内存,但它将引发我们的采集架构发生巨大变化,并可能存在数据精度问题。
方案二:仍然依赖客户端生成快照,但是会进行多份数据计算和存储,并生成多个快照。
优点:采集架构改动小,没有数据精度问题,server压力小。
缺点:存储秒级的数据会占用更多的内存。
由上面对比可以看出,方案二相比方案一来说现有采集架构改动小,不会存在数据精度问题,数据聚合计算分布在client端,server压力小。虽然会占用更多的内存,但我们也对这一问题进行了优化,对于Counter类的数据,由于它本身就是一个Int或者Float64的数据,其本身占的内存就不多。而Timer类型的数据我们采用了Tdigest数据采样算法进行数据压缩,将原本可能有1000个数据点的数据,缩减到100个数据点。通过这样的优化,我们发现对内存的占用是可以接受的。
因此,综合以上考虑,我们最终选择了方案二。
②改造后的架构
选定方案二后,我们对客户端进行了改造:
改造一:引入一个新的计算层,这个计算层实现了两个功能
功能一:数据采样。
功能二:判断指标是否需要进行秒级采集。
目前我们只对核心的订单类和系统的P1级指标进行秒级采集,因为如果对所有指标都进行采集,资源消耗将非常大。在计算时,它会同时计算秒级和分钟级的数据。
改造二:调度器的改造,增加了一个快照管理器,用于管理多个快照。
服务端在拉取数据时,会根据参数选择拉取不同的快照。配置管理服务则作为服务端和客户端交互的接口,可以将秒级的配置实时推送给客户端。
经过这样的改造,我们的客户端现在能够满足我们的需求,可以进行秒级的计数。
4、服务端指标采集优化
1)当前架构
当前架构存在问题:数据断点和高资源消耗
问题一:秒级数据采集出现断点
在我们的原始架构中,我们采用了Master-Worker模式,这是一个相对简单但功能强大的设计。在这个架构中,Master充当一个全局调度器,定期从数据库拉取所有任务,并通过消息队列将任务分发给各个Worker。这是一个经典的生产者消费者模式,其优势在于Worker可以轻易地进行扩展,因为它们是无状态的,如果任务过多,可以简单地增加Worker以满足需求。
然而,当我们尝试进行秒级采集时,我们遇到了一些问题。我们有数以十万计的任务,通过消息队列发送任务时,有时需要长达12秒的时间。这与我们的秒级采集需求不符,因为如果任务的发送就需要12秒,而我们的采集间隔只有10秒,那么秒级数据采集就会出现断点。
问题二:高资源消耗
系统是使用Python开发的,使用了多进程/多线程的模型。当需要拉取大量的节点数据并进行聚合计算时,CPU的消耗过高。需要一个合理的解决方案,既能满足秒级采集的需求,又能有效地管理资源消耗。
2)解决方案:将任务调度的功能转移到Worker节点
将任务调度的功能转移到了Worker节点上,尽管使得Worker变成了有状态的服务,但是如果一个Worker出现故障,Master会监听到这个变化并将该Worker的任务重新分配给其他节点。
3)改造后架构
该架构仍然可以方便地进行扩展,同时我们选择了Go + Goroutine这样的开发模式,因为它更适合高并发的场景。经过改造后,系统现在可以支持分钟级和秒级的数据采集。
架构介绍:
①去掉了消息队列,依然保持了Master-Worker的模式。
②增加了任务分区的功能到Master节点中。
例如,我们有数以十万计的任务,通过任务分区,可以清楚地知道有多少个Worker节点,然后将不同的任务分配给不同的Worker,这是通过Etcd进行分区设置实现的。
③Worker节点会监听etcd的事件,一旦检测到事件,它就会知道需要执行哪些任务,比如ID为1到1000的任务。
④Worker会获取这些任务,并将任务缓存到内存中,然后开始执行。
5、最终架构
三、与分钟级监控的区别
四、秒级使用场景
秒级监控的核心目的,是更快的发现核心业务的问题,非核心业务引入秒级监控,一方面会形成报警风暴,造成打扰,另一方面也会造成资源的浪费。因此我们主要监测核心业务与核心指标变化。
五、秒级使用
1、编排秒级面板,明确核心业务监控以及核心应用
在已经明确了秒级监控主要监测核心业务与核心指标变化的前提下,该如何编排秒级面板?
不管是面向整个业务,还是仅面向一个项目,不同的业务体量差异,都可以根据各自特点梳理出对应的核心监控面板。譬如只关注业务最核心的指标,又或者是业务的关键过程指标。单个监控面板上可以包含一个监控指标,也可以包含多个监控指标,通过不同纬度来综合反应业务/项目情况。
在避免报警风暴和不必要的资源浪费的同时,提前编排秒级面板,可以依据核心监控指标推导出受影响的应用范围,从而评估大概的sdk升级成本,人力投入成本,方便下一步工作的开展。
2、应用sdk版本升级,添加秒级指标白名单
秒级监控的实现涉及到了指标采集sdk的修改,因此若想要使用秒级能力,需要升级对应应用的sdk,而我们借助tc同学配套的组件升级机制,可以实现修改版本、beta测试、灰度验证到线上全量上线的全流程自动化。
为了方便大家的接入和使用,我们主要做了以下两点策略:
1)秒级指标采用白名单的方式添加
watcher指标的采集使用的是pull的方式,对于业务类指标,需要开发同学在代码里调用打点方法,并在监控平台配置应用拉取的参数包括环境、端口号、路径等,为了减少开发同学在使用秒级监控时额外增加代码修改成本和配置成本,我们使用了白名单机制。具体实现如下图,新增一个秒级监控metadb,保存指标白名单,并推送到应用sdk,对于配置了白名单的指标,sdk在记录分钟级打点的同时,也会记录秒级的打点,无需改动代码和拉去配置,做到了秒级指标的一键添加。
2)dashboard新增秒级监控数据源,并在panel加以区分
我们在watcher新增了秒级数据源,提供了快速切换数据源的配套工具,以便于大家快速配置秒级监控面板和报警。并且在watcher的panel维度增加了数据源标识以区分分钟级和秒级监控面板。
3、配置秒级报警
1)通知模版
watcher报警通知服务使用的是icinga集群,为了实现报警通知的秒级触达,我们新增了秒级的通知检测模版SL1、SL2,两类模版的检测频率和秒级指标数据的采样频率保持一致。其中SL1在报警状态改变后会立即同时电话通知和qtalk通知(qtalk是去哪儿旅行自研办公协作平台),SL2在报警状态改变后会立即进行qtalk通知,3分钟后进行电话通知。业务线同学可以根据报警级别配置不同通知模版。
2)报警规则配置策略
如下图所示,相同指标在分钟级和秒级的监控表现,可以直观的看出,秒级监控指标的数据趋势更加陡峭。
分钟级监控指标:
秒级监控指标:
报警规则配置会直接影响秒级报警的准确和有效。在分钟级报警规则配置方式的基础上,秒级还要:
①精细化设置报警规则,避免报警未报问题。譬如:观察指标趋势,根据实际情况尽可能的细化时间间隔,在流量高峰期间,设置不同时间间隔的报警规则。
为什么要精细化设置报警规则?
如上如所示,秒级监控指标的数据趋势更加陡峭,如果参考分钟级来设置报警规则,流量在高峰期间掉了一个坑,指标累计下降造成的损失,秒级并不能更快地发现并预警。
②区分工作日与周末节假日,避免因流量降低造成的误报问题
六、运营推广成果
1、影响力
公司内多业务线推广落地使用。
2、优势对比
与分钟级监控对比,故障发现时长从4分钟降低到了1分钟内。
3、运营监测范围
核心业务指标:订单量、交易失败率、顺畅度等;
业务全链路:进订、下单、支付、确认、取消等;
4、秒级监控经过一段时间的运营,ATP故障1min发现率和预警准确率两个指标稳步提升
七、后续规划
采用算法实时监测趋势主动发现问题,无论是显著有别于其他点的异常,还是连续性异常,实现指标异常下降智能分析检测,指标跌零智能分析预警。