本文作者:郭雨杰,阿里云智能技术专家。
Prometheus 集成的 50 多款云产品中,RocketMQ 在可观测方面实现了非常完善的功能,是一个特别具有代表性的云产品。
01 RocketMQ如何接入Prometheus
RocketMQ 诞生于阿里内部的核心电商系统,是业务消息的首选 MQ 平台。上图是 RocketMQ 5.0 的系统全貌,在接入层、核心组件和底层运维方面做了非常大的改进,具有功能多样、高性能、高可靠、可观测、易运维等众多优势。
Metrics、Tracing、Logging 是可观测能力的三大支柱。
-
Metrics:RocketMQ 以 Prometheus+Grafana 这种在开源领域广泛使用的产品组合为用户提供了开箱即用的 Dashboard。指标涵盖了消息量、堆积量、各阶段耗时等,该大盘结合 RocketMQ 团队在消息领域多年的研发和运维经验打磨的最佳实践模板,并提供了持续的迭代更新能力。
-
Tracing:RocketMQ 首次引入了 OpenTelemetry tracing 的开源标准,按照消息的维度,重新组织了抽象的 span 拓扑。
-
Logging:Logging 方面主要进行了一些客户端日志的标准化处理,能够更简单方便地利用日志定位问题。
RocketMQ 的所有可观测性数据都是围绕一条消息在生产端、服务端处理、消费阶段展开。从消息的生命周期图上,可以看到一条消息从 Producer 开始发送到 MQ server 接收到的耗时;如果是定时消息根据 Ready time 可以知道定时的时间;从 Consumer 的角度上看,可以知道消息从开始拉取到抵达客户端的网络耗时;从抵达客户端的时间到开始处理消息的等待处理资源耗时;从开始处理消息到最后返回的 ACK 的处理耗时。消息在生命周期的任何一个阶段,都可以清晰地被定义并且被观测到,这就是 RocketMQ 可观测的核心理念。
RocketMQ 团队贡献的 RocketMQ exporter 已被 Prometheus 官方的开源 Exporter 生态所收录,提供了 Broker、Producer、Consumer 各个阶段丰富的监控指标。Exporter 基本逻辑是通过在内部启动多个定时任务周期性地从 MQ 的集群上拉取数据,然后将数据规范化后通过端点暴露给Prometheus。MQAdminExt 类封装了 MQAdmin 暴露的各种接口逻辑。从结构上看,RocketMQ 的 Exporter 是站在第三方视角的观察者角色,而所有的指标来自于MQ 集群的内部。
Prometheus 在应用程序中暴露监控指标的过程需要注意以下两点:
①Exporter 部署模式的选择分为将 Prometheus client 内嵌到应用程序的直接观测模式以及应用程序之外的独立 Exporter 模式。直接观测模式具有主流语言支持、性能更优、免运维的优势,劣势为代码耦合。Exporter 模式具有解耦合、开源生态丰富的优势,最大的缺点是需要单独的运维 Exporter 组件,在云原生微服务的应用架构模式下需要部署多个 Exporter 对运维带来不小的负担。对于部署模式的选择没有优劣之分,一般建议对应用代码有掌控权限的条件下,选择直接观测模式,对应用代码无掌控权限的条件下选择 Exporter 模式。
②尽量避免指标维度发散而引起的高基数问题。由于 Prometheus 的指标模型扩展维度只需要添加一个 label非常的方便,很多用户将需要的尽可能多的维度都添加到指标中,这就必然会引入一些不可枚举的维度,比如常见的 userid、url、email、ip 等。Prometheus总体的时间线数量按照指标以及维度的组合乘积关系来计算,因此高基数问题不仅带来了巨大的存储成本,而且会由于瞬时返回的数据过多,对查询侧带来不小的性能挑战,并且严重的维度发散使得指标本身失去了统计上的意义。因此,在使用过程中,应尽量避免指标维度发散问题。
我们在使用 Prometheus Client 时也会遇到高基数问题,尤其是 RocketMQ 的指标,提供了账号、实例、 topic、 消费者Group ID 等多个维度的组合使得整体的时间线数量处于一个很高的量级。实践过程中我们针对 Prometheus 原生的 Client 做了两点针对性的优化,目的是有效地控制 Exporter 的高基数问题带来的内存隐患。
RocketMQ 的生产环境中,需要做到对售卖租户的客户级监控。每个客户的 RocketMQ 资源都按照租户进行严格隔离。如果为每一个租户部署一套 Exporter ,则会对产品的架构、运维等方面都带来非常大的挑战。因此在生产环境中,RocketMQ 选择了另一种接入 Prometheus 的方式。
RocketMQ 5.0 的架构方面做出了较大的改进。多语言瘦弱客户端底层统一使用了 gRPC 协议将数据发送到服务端,同时 MQ server 也拆分为了可拆可合的 CBroker(proxy)和 SBroker 两个角色。架构变更的同时,RocketMQ 5.0 在客户端和服务端同时引入了 OpenTelemetry tracing 标准埋点的规范。
全链路Tracing
-
客户端嵌入了OpenTelemetry Exporter,将 Tracing 的数据批量发送到 proxy。
-
proxy 本身作为一个 collector 整合了客户端上报的以及自身的 tracing 数据。
-
tracing 的存储支持用户自定义 collector,商业版托管存储,开源版本存储上报到自己的平台。
-
针对消息的生命周期,重新设计了 span 的拓扑模型。
准确多样的Metrics
-
在服务端对收到的 tracing 数据进行二次聚合计算,得到的计算后的指标符合OpenMetrics 规范。
-
可以无缝地集成到 Prometheus 存储和 Grafana 的大盘展示。
RocketMQ span 拓扑模型。该拓扑模型针对 Prod、Recv、Await、Proc、ACK/Nack 阶段分别做了重新规范化的埋点处理,同时将 OpenTelemetry的 tracing 模型中的 attributes 部分规范提交到 OpenTelemetry specification 标准组织并得到收录。
以上的改进使得消息轨迹功能得到了极大的增强,不仅可以根据消息的基本信息查询相关轨迹,还能对消息的生命周期的各个阶段一目了然。点开 trace ID ,还可以看到详细的追踪信息,并且可以关联看到生产者、消费者以及相关资源,比如机器信息的展示。
RocketMQ 的指标数据为什么要接入到 Prometheus ?因为 Prometheus 天然契合了云原生的架构,在开源领域 Prometheus 处于 metrics 事实规范地位。Prometheus 为云原生架构而生,与 Kubernetes 天然集成,具有自动发现、多层次采集的能力、强大的生态、通用的多模指标模型、以及强大的 PromQL 的查询语法等特点。
RocketMQ 是基于 trace 数据进行二次计算为 metric 来对接 Prometheus 的。前文讲到了 RocketMQ 5.0 引入了 OpenTelemetry tracing 埋点,我们将客户端和服务端上报的 tracing 数据统一存储到阿里云日志系统中,基于 tracing 数据根据多个维度进行二次聚合,产生了符合 Prometheus 指标规范的时序数据。在 ARMS 团队内部,通过实时 ETL 工具将日志数据转化为指标按租户存储到 Prometheus 系统中。RocketMQ 控制台深度集成了 Grafana 的大盘和 Alarm 告警模块,用户只需要在 RocketMQ 的实例监控页面中开通 Prometheus 即可一键获取自己名下的大盘和告警信息。
ARMS Prometheus 集成了众多的云产品监控指标,针对云产品的多租需求提供了一套完整的解决方案。阿里云的云产品除了需要对产品自身的指标进行监控外,同时需要对产品售卖的租户指标进行监控。
云产品针对租户资源划分,主要分为租户独占资源模式和租户共享资源模式。租户独占资源模式具有租户单独占用部署资源,隔离性好的特点,识别指标的租户信息只需要打上租户指标即可;租户共享资源模式指租户之间会共享部署资源,识别指标的租户信息需要云产品自行添加租户信息。
ARMS Prometheus 监控相对于开源的 Prometheus 采用了采集和存储分离的架构,采集端具有多租识别和分发能力,存储端内置了多租能力,租户之间的资源完全隔离。
ARMS Prometheus 会为每个阿里云用户创建一个 Prometheus 云服务的实例,来存储用户对应的阿里云的云产品指标,真正地解决了以往监控系统数据分散形成的数据孤岛问题,同时为每个云产品提供了深度定制、开箱即用的大盘和告警能力。
上图为 RocketMQ 默认集成的 Grafana 大盘示例。大盘提供 Overview 概览、Topic 消息发送、Group ID 消息消费等细粒度的监控数据支撑。相较于开源实现,该大盘提供了更多更准确的指标数据,同时结合了 RocketMQ 团队在消息领域的多年运维经验打磨的最佳实践模板,并提供了持续迭代更新的能力。
02 RocketMQ可观测最佳实践
单纯地关注消息系统提供的可观测数据只能发现一部分的问题,在一个真实的微服务系统中,用户需要关注整个技术栈全局中的接入层、业务应用、中间件、容器、底层 IaaS的可观测数据才能准确地定位问题。上图是一个非常典型的消息系统上下游的应用结构。上游订单系统发送消息,下游库存系统、营销系统订阅消息,实现上下游的解耦。如何在这样一个复杂的业务系统中发现问题、解决问题,需要对整个系统的可观测性做全面梳理。
首先需要对系统中的各个组成部分可观测数据进行收集,Metric、Trace、Log 的三大支柱必不可少。Metric 衡量了应用状态,通过指标告警可以快速地发现问题;Trace 数据可以做到请求级别的全周期的跟踪路径,通过排查调用链路可以快速地定位问题;Log 数据详细记录了系统产生的事件,通过日志分析可以快速地排查故障。
上图为 ARMS Kubernetes 监控沉淀的诊断经验。通过在应用的技术栈端到端、自顶向下的全栈关联方式,为我们在横向、纵向将可观测问题诊断定位提供了实践思路参考。对于跟业务相关的组件而言,需要更多地关注影响用户体验的RED指标,在资源层应该更多地关注资源饱和度相关的指标。同时需要横向地关注日志、事件、调用链关联,只有多方位、全视角的可观测才可以更加清晰地排查定位问题。
上图为一个消息堆积场景的例子。
首先需要理解消息堆积的指标含义。一条消息在 Producer 发送后,在消息队列中的处理以及 Consumer 消费的三个阶段分别处于 Ready、inFlight、Acked 状态。需要重点关注两个指标,已就绪消息量(Ready message)表示已就绪的消息条数,该消息量的大小反映了还未被消费的消息规模,在消费者异常的情况下,就绪消息的数据量会变多;消息排队时间(Queue time)表示最早一条就绪消息的就绪时间和当前的时间差,该时间大小反映了还未被处理消息的时间延迟情况,对于时间敏感的业务而言是一个非常重要的度量指标。
消息堆积的原因主要有两点,消费端故障或消费能力不足导致,或者上游生产端消息量过大,下游消费能力不足导致。
对于生产端更应该关注消息的发送健康度,可以针对发送成功率进行告警。出现告警时,需要关注 load、发送耗时、消息量等指标,判断是否有消息量的突然变化;对于消费端应该关注消费是否及时的消费健康度,可针对就绪消息的排队时间进行告警。当出现告警时,需要关联地关注消息的处理耗时、消费的成功率、消息量、load等相关指标,判断消息的消息量、消费处理的耗时的变化,并查询是否有 ERROR 日志、trace 等相关信息。
用户可以使用阿里云 ARMS 产品,能够更方便快捷地处理以上排查过程。
收到告警信息之后,通过查询业务拓扑、异常标注以及业务指标的变化,一键地查看关联的调用链信息,在调用链上可以获得业务处理各个阶段的处理时长、是否存在异常等相关信息。调用链的每个 span 节点可以下钻实时查询调用堆栈和耗时分占比,将问题定位到业务代码级别。如果用户接入的日志中按照 ARMS 规范关联到调用链的 traceID ,还可一键关联查看对应的日志详情,最终定位问题的根因。
当问题出现时,除了方便快捷的问题定位过程,还需要针对告警提供相对完善的告警处理和应急响应机制。ARMS 告警为用户提供了告警配置、告警排班、告警处理的全流程功能,方便客户建立应急处理、事后复盘和机制优化。
同时 ARMS 的智能告警平台支持10+监控数据源的集成以及多渠道数据推送。基于钉钉的 CHARTOPS 让告警可协作、可追溯、可统计,并且能够提供异常检查、智能降噪等算法能力,有效减少无效告警,并且可以在告警中基于应用的上下文得到告警的根因分析。
阿里云 ARMS 监控从上到下云涵盖了用户的终端、应用、云服务/三方组件、容器、基础设施的全方位、立体化、统一监控和统一告警能力,是企业构建一站式可观测的最佳实践平台。