Uber的软件架构由成千上万的微服务组成,有赖于此,我们的团队可以快速的自主迭代并支撑公司的全球扩张。这一架构支撑了大量的上层解决方案,如移动应用,内部基础设施服务,以及拥有复杂配置的产品,相关配置会对产品在一、二线城市的表现产生不同的影响。
为了保障对业务扩张的支撑,以及维持架构的稳定性,Uber的可见性团队构建了一个健壮、可扩展的指标系统以及告警管道。这一系统可以监测相关服务, 以便在故障发生的第一时间延缓产生的影响并通知相关的工程师。
如图中所示,uMonitor和Neris利用一个共有的管道来发送通知并去重。稍后我们会深入了解这些系统,并探讨如何推动建立更多的缓冲措施,和我们新的告警去重平台Origami,以及在建立高“信噪比”的告警系统方面如何应对挑战。信噪比,英文名称叫做SNR或S/N(SIGNAL-NOISE RATIO),又称为讯噪比。是指一个电子设备或者电子系统中信号与噪声的比例。
此外,我们还建立了一个黑盒系统,用于侦测内部系统失败或者数据中心整体当机所引发的更高一级的系统中断。后续的文章会有讨论。
1.Uber的告警系统
图表1:在我们的告警体系中,相关服务向M3发送指标数据,uMonitor会负责检查M3中的数据并产生基于指标的告警信息。主机检测信息会发送到Neris并产生聚合和告警信息。Uber外部可以对基础设施API进行黑盒测试。
在Uber的体量下,传统的现成解决方案无法满足监控和告警的要求。我们采用开源的Nagios,结合Graphite的阈值检测,以及后端的Carbon指标系统 ,辅以源码控制脚本来解决这个问题。基于对Carbon指标系统伸缩性的考量,我们决定建立一个自有的大规模度量平台,即M3。为了提升告警系统的可用性,我们自主研发了时序告警系统uMonitor,用于处理M3中存储的指标数据。对于M3以外存储的指标数据,我们建立了Neris来进行主机一级的告警检测。
在uMonitor的开发过程中,灵活性和用例差异性是两个重要的考虑因素。有些告警信息是基于标准指标自动生成的,如端点错误或者CPU/内存占用率过高等。还有些告警信息是由某个团队根据具体的需要所建立的指标生成的。uMonitor作为一个平台系统,会对这些不同种类的用例所产生的指标进行处理,诸如:
- 告警的易管理性:迭代产生适用于告警信息的功能和阈值。
- 弹性措施:利用寻呼、邮件和聊天系统发送通知。支持自动化的缓解措施,如部署和配置变更的回滚等。
- 处理海量信息:既可以响应小范围的关键事件,又不至于在大范围的中断情况下让工程团队被报警信息淹没。
2.基于指标的告警系统:uMonitor
uMonitor由三个独立组件组成:一个拥有告警管理API的存储服务,可以对Cassandra告警和状态信息进行打包存储;一个调度器,负责跟踪所有的告警信息,并时刻将报警检查任务分发到workers;一组workers用来基于告警信息自定义的指标执行检查任务。
workers会将告警检查的状态信息保存在Cassandra存储中,并通过激进的重试机制来确保相关的通知确实发送成功。只要告警信息持续产生,workers会负责进行不时的(通常是每小时1次的)重试告警。目前,uMonitor可以在1秒内使用125,000个告警配置来对140万笔时序数据的7亿个数据节点进行检查。
图表2:相关服务向M3发送指标数据,uMonitor的调度器安排相关的workers进行相关指标检查,如果检查结果超过一定阈值,就发送通知。
一条告警信息由M3查询(Graphite 或者M3QL)语句和阈值组成。阈值将决定告警是否触发。查询语句从M3返回时序数据,阈值会应用于对应的时序数据。一旦查询的结果超过了阈值,告警就会触发。借助Cassandra存储的状态信息,相关worker会维持一个状态机,以确保告警触发的状态下相关的通知成功发送,并在告警持续触发的情况下不时的重发通知,以及在事态缓解的情况下将相关通知标记为解决。
阈值一般分为两种:静态阈值和反常阈值。对于一些具备特定的、稳定状态的指标,或者我们可以构造查询来通过数值计算返回常量值的指标(如成功/失败比),通常使用静态阈值。对于一些周期性的指标,如客户在某市的行程次数或其他的业务指标,uMonitor使用Argos这个反常监测平台来生成动态的阈值,以表征基于历史数据的反常数值。
3.主机告警组件:Neris
Neris是一个基于主机的内部告警系统,用于解决M3指标系统以外的高精度的海量指标数据。将主机指标系统设置在M3之外,是基于两个原因。首先,要对每个数据中心的40,000个主机节点每分钟所产生的150万条主机指标数据进行检查,基于主机的机制相对于从中心指标存储库查询来说更加高效,严格意义上讲,相关指标的提取和存储是毫无意义的开销。其次,当前M3的保留策略是,10秒的指标数据会存储48小时,1分钟的指标数据会存储30天,对于主机指标来说,以如此的精度和保留策略存储相关数据并没无必要。开源的Nagios是以检查为单位来编码和部署的,这意味着基础设施扩张时,主机指标系统无法自动伸缩,因此我们决定自己开发一个系统来应付需要。
Neris的机制,是在数据中心的每个主机上部署一个代理,并基于单主机每分钟定时执行告警检测。随后,相关的检查结果会发送到一个聚合层,聚合层将聚合结果发送给Origami。Origami负责决定发送哪些告警信息,发送的优先级将视告警的失败次数以及潜在告警危急程度而定。基于Origami,Neris可以在每分钟对我们每一个数据中心的主机集团进行150万次检测。
主机上的代理启动时,Neris从一个名为Object Config的中心配置存储拉取主机的告警定义信息。Object Config这一机制广泛的应用于Uber的底层基础设施服务。哪些告警会被触发取决于其角色。例如,运行Cassandra的主机会运行与Cassandra状态、磁盘使用情况等指标相关的检查。绝大多数主机级别的检查由基础设施平台团队负责建立和维护。
图表3:在Neris的机制中,主机检查基于数据中心的每个主机进行,并通过Neris聚合器实现聚合,并由Origami发送告警通知。
4.处理规模数据
我们的告警平台在处理海量数据方面一直面临着巨大的挑战。传统的解决方案是,通过一条告警查询返回多条时序数据,并且只有在一定比例的数据超过阈值的时候,才使用简单的规则来触发告警通知。uMonitor同样允许用户基于告警来设置告警。如果一条告警依赖于更大范畴的告警,则一旦上一级告警触发的情况下,下级告警将被阻塞。
当查询结果返回的是既定数量的时序数据,且依赖关系可清晰定义的时候,上述方法可以工作的很好。然而,急速扩张中的Uber需要在数以百计的城市运营多条产品线,数量级的挑战需要更通用的解决方案。我们使用Origami来处理海量的任务。Neris将Origami作为主要的去重器和通知引擎,从而,uMonitor告警系统有了稳固的通知系统。
对于业务指标来说,Origami对于单城市/单产品/单应用版本的告警是用处巨大的。Origami允许用户基于城市、产品和应用版本的组合来建立潜在的告警和检查,并基于聚合策略来触发告警,来接收某个城市、产品或者应用的通知。在更大范围的系统中断的情形下(如多个城市同时发生故障),Origami会发送累积通知,用以表征已触发的告警列表。
在主机告警的场景下,Origami使我们可以基于告警的聚合状态发送不同严重程度的通知。以Cassandra集群的磁盘使用率为例,此情形下的Origami通知策略如下:
- 当磁盘利用率超过70%的主机数小于3,则发送邮件通知。
- 当磁盘利用率超过70%的主机数大于3,则发送寻呼通知。
- 当磁盘利用率超过90%的主机数大于1,也发送寻呼通知。
5.告警通知
处理告警系统的伸缩问题,最主要的挑战来自于如何产生有用的告警通知。对于高优先级的事件,告警行为一般采用的通知方式是寻呼待命的工程师,而对于一般的告知类事件,是通过邮件或者聊天工具来进行通知。我们关注的重点在于构建一些缓解行为来减轻事件的影响。绝大多数的系统中断或者其他问题来源于配置变更或者部署问题。有些团队需要处理非常复杂的缓解行为运行手册,对此我们支持以webhook的方式发送POST调用,并附加告警信息完整的上下文信息,来自动化对运行手册的落地。此外,在更大范围的系统问题发生时,利用Origami的去重管道,我们可以阻塞一些细粒度的通知,以免工程团队被信息也淹没。
除了上述的手段以外,我们也致力于让通知的相关性更高,并且匹配到正确的处理者。最新的成果是,当某个服务发生变更并产生告警时,我们可以定位到配置或部署变更的所有者,并直接通知他们相关事项。并且,通过把Jaeger的追踪信息与告警信息进行结合绑定,我们可以为相关的服务失败提供更多的上下文信息。
6.告警管理
上面也讲到,之所以花大力气将uMonitor平台化,是为了让不同的团队可以基于这个平台,来处理特有的用例场景。对于不同的团队,尤其对于需要维护专有硬件的团队,以及需要为公司构建基础设施平台的团队来说,在处理诸如存储、指标管理、计算解决方案等场景的告警问题时,相关的设置和管理往往是特定的和专业化的。相关的告警设置存储在团队自有的Git库中,并向Object Config进行同步。
从更宏观的视角,uMonitor有三类告警:
– 针对所有服务来说,CPU、磁盘利用率和RPC状态这些标准的指标,会自动生成告警信息。
– 针对特定事件,经由UI产生一次性的告警信息。
– 在uMonitor之上的一层,告警信息的生成和管理通过脚本和外部配置系统完成。
当团队致力于侦测尽可能细粒度的告警事件的时候,一些初级的告警信息就会产生爆发式增长。随着Uber的全球扩张,如此细粒度的告警信息的重要性随之下降。对于支撑Uber移动应用的相关服务来说,相关的代码变更可以在几小时内,就覆盖到一部分城市的某些特定群体。在城市一级对平台的健康度进行监测,发现问题并避免问题扩散,对我们来说尤其重要。此外,工程团队和本地的运维团队所需要管理的配置参数,也因城市而异。例如,某个城市的某条街道的游行队伍,或者其他事件导致的交通情况的变化,都会影响Uber骑手的匹配。
很多的团队已经基于uMonitor构建了告警信息的发生方案,以处理类似上述的这种场景。已经解决的挑战包括:
– 迭代和生成多维告警信息
– 基于特定的业务信息(如某个国家和城市的节日)调度告警任务,并在uMonitor中存储相关的配置,以避免产生错误的告警信息
– 当静态或者反常的阈值失效的时候,可以基于历史数据,或者基于特定的业务线的潜在指标进行的复杂查询,来生成新的阈值。
此外,上述的解决方案可以生成仪表盘。相关的信息与产生的告警信息同步。
uMonitor还提供了一个强有力的编辑界面,可以展示相关的因果联系。UI的编辑和验证的功能十分重要,因为差异性以及峰值的存在,大部分的指标并不能用于告警。对于如何为告警建立更理想的查询,可见性团队会给出一些指导建议。
7.告警查询
为了允许更加定制化的解决方案,Graphite查询以及M3QL查询语言所提供的功能很多,甚至有些过犹不及。下我们举了一些示例,来展示如何让查询返回更多的常量,以使得相关指标更可用于告警:
– 使用一段时间内的移动均线指标,可以平滑掉指标中的峰值
– 在上一点的基础上,结合采用维持策略,仅当超过阈值的状况持续了一段时间之后,才发送告警通知。
– 对于一些遵循升降模型的指标,采用导数函数确保无论是上升或者下降,相关指标不会太突兀。
– 使用比率或者百分比来进行告警,以使得指标不会因绝对值的变化而受到影响。8.未来计划
如何让系统扩展的同时具备分钟级的问题侦测能力,并且仅暴露合适的信息给到用户,避免不必要的告警信息,在这方面的工作我们还只是刚刚起步。为了达成这样的目标,告警管道的方方面面都进行着大量的工作,包括:更有效的指标收集,扩展和提升告警执行基础设施的效能,构建更有效的UI和接口以处理不同来源信息的相关性等等。
关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享。
本文由公众号EAWorld翻译发表,转载需注明出处。
作者:Shreyas Srivatsan
译者:白小白
原题:Observability at Scale: Building Uber’s Alerting Ecosystem