在分布式系统中,多个服务之间的交互涉及到复杂的网络通信和数据传输,其中每个服务可能由不同的团队或组织负责维护和开发。因此,在这样的环境下,当一个请求被发出并经过多个服务的处理后,如果出现了问题或错误,很难快速定位到根因。分布式全链路追踪技术则可以帮助我们解决这个问题,它能够跟踪和记录请求在系统中的传输过程,并提供详细的性能和日志信息,使得开发人员能够快速诊断和定位问题。对于分布式系统的可靠性、性能和可维护性起到了非常重要的作用。
RocketMQ 5.0 与分布式全链路追踪
Apache RocketMQ 5.0 版本作为近几年来最大的一次迭代,在整个可观测性上也进行了诸多改进。其中,支持标准化的分布式全链路追踪就是一个重要的特性。
RocketMQ 5.0 可观测
而由 Google、Microsoft、Uber 和 LightStep 联合发起的 CNCF OpenTelemetry 作为 OpenTracing 和 OpenCensus 的官方继任者,已经成为可观测领域的事实标准,RocketMQ 的分布式全链路追踪也围绕 OpenTelemetry 进行展开。
分布式链路追踪系统的起源可以追溯到 2007 年 Google 发布的《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》[1]论文。这篇论文详细介绍了 Google 内部使用的链路追踪系统 Dapper,其中使用的 span 概念被广泛采用,并成为后来开源链路追踪系统中的基础概念之一。
Dapper Trace Tree
在 Dapper 中,每个请求或事务被追踪时都会创建一个 span,记录整个请求或事务处理过程中的各个组件和操作的时间和状态信息。这些 span 可以嵌套,形成一个树形结构,用于表示整个请求或事务处理过程中各个组件之间的依赖关系和调用关系。后来,很多开源链路追踪系统,如 Zipkin 和 OpenTracing,也采用了类似的 span 概念来描述分布式系统中的链路追踪信息。现在,合并了 OpenTracing 和 OpenCensus 的 CNCF OpenTelemetry 自然也一样采用了 span 概念,并在此基础上进行了进一步发展。
OpenTelemetry 为 messaging 相关的 span 定义了一组语义约定(semantic convention)[2],旨在制定一套与特定消息系统无关的 specification,而 OpenTelmetry 自身的开发其实也都是由 specification 驱动进行展开。
Specification Driven Development
Messaging Span 定义
Specifaition 中描述了 messaging span 的拓扑关系,包括代表消息发送、接收和处理的不同 span 之间的父子和链接关系。关于具体的定义可以参考:Semantic Conventions of Messaging[3]。对应到 RocketMQ 中,有三种不同的 span:
Span | Description |
send | 消息的发送过程。span 以一次发送行为开始,成功或者失败/抛异常结束。消息发送的内部重试会被记录成多条 span。 |
receive | 消费者中接收消息的长轮询过程,与长轮询的生命周期保持一致。 |
process | 对应 PushConsumer 里 MessageListener 中对消息的处理过程,span 以进入 MessageListener 为开始,离开 MessageListener 为结束。 |
特别地,默认情况下,receive span 是不启用的。在 receive span 启用和不启用的两种情况下,span 之间的组织关系是不同的:
启用 receive span 前后的 span 关系
在没有启用 receive span 的情况下,process span 会作为 send span 的 child;而当 receive span 启用的情况下,process span 会作为 receive span 的 child,同时 link 到 send span。
Messaging Attributes 定义
语义约定中规定了随 span 携带的通用属性的统一名称,这包括但不限于:
- messaging.message.id: 消息的唯一标识符。
- messaging.destination:消息发送的目的地,通常是一个队列或主题名称。
- messaging.operation:对消息的操作类型,例如发送、接收、确认等。
具体可以查看 Messaging Attributes 的部分[4]。
特别地,不同的消息系统可能会有自己特定的行为和属性,RocketMQ 也和 Kafka 以及 RabbitMQ 一起,将自己特有的属性推进了社区规范中[5],这包括:
Attribute | Type | Description |
messaging.rocketmq.namespace | string | RocketMQ 资源命名空间,暂未启用 |