它来了!它来了!它来了!
就在前不久, RocketMQ 5.0 终于发布了 Release 版本。从 2017 年发布 4.0 版本之后,历经了五年之久,经过社区不断地演进和实践。今天,RocketMQ 正式迈入 5.0 的新时代。
记得小年当时作为公司第一个引入 RocketMQ 第一个吃螃蟹的人,对它可谓是有非常深的渊源。期间踩过不少坑,也手撕过源码,可以看一下小年的几篇精髓文章:
既然小年作为忠实粉丝,新版本的发布,当然是满怀期待的。今天就让小年带大家来看看,这次 RocketMQ 5.0 究竟带来了什么令人眼前一亮的新特性!
生于云、长于云的云原生消息、事件、流超融合平台
这是本次 RocketMQ 5.0 的特性概括。这里我们可以看到几个关键词:云原生、消息、事件、流。消息的话本身就是 RocketMQ 的最基础的功能。而我们从其余的关键词就可以看出来,本次 5.0 的建设目标,肯定不仅仅于此。
我们主要从这三点来出发:
- 基础架构的云原生演进
- API 与 SDK 的演进
- 事件、流集成场景的拓宽
基础架构的云原生演进
随着如今企业全面上云,以及云原生技术趋势的不断发展,用户和开发者的要求会越来越高。
对于以往来说,在 RocketMQ 4.x 阶段,他们的着重点是在丰富的功能性和便捷的使用性上,而随着功能和基础设备的不断完善,现今开发者们更看重的可能是是稳定性与扩展性。
所以为了能够满足开发者的需求,和贴合云原生技术的发展,RocketMQ 5.0 对原来的基础架构进行了比较大的升级。
第一 Part,无状态代理模式
RocketMQ 5.0 的架构中,在客户端和broker之间增加了一个 Proxy(代理层)。简单来说,就是对外屏蔽了NameServer、Broker 的概念和调用,统一收敛由 Proxy 来负责提供消息发送、接收、调度控制等功能。
而无状态的 Proxy ,其实也是将客户端(Client)和 Broker 侧的无状态的功能都抽取出来。比如,客户端原有的负载均衡机制、故障隔离、push/pop 消费模型; Broker 的访问控制、多协议适配、客户端治理以及NameServer 的消息路由能力等这些。
当然,必须确保一个宗旨的是:Proxy 所提供的必须都是无状态。这样子才能结合云原生技术,方便扩缩容部署。
小年觉得 Proxy 的这一个设计,其实很像我们微服务体系架构里的网关层,可以对流量的统一治理和分发,权限访问控制等。不过,Proxy 的能力不仅如此,它还具备解析和适配不同协议的能力,能够支持 Remoting 、gRPC、HTTP 以及后续可能衍生出来的 MQTT 和 AMQP 等协议。
第二 Part,POP 消费模式
在 4.x 的版本中,使用的都是 Push Consumer 消费模式,这是基于队列模型的消费模式。
一个消费集群中的每个消费实例,会被平均分配不同的 Queue 进行消息消费。这种模式在理解和实现行比较简单和实用,一般也能满足各种业务场景,但是它同时也会存在一些问题。
比如说:
- 单个 Consumer 消费出现问题 hang 住了,就会导致它所分配的 Queue 中的消息消费出现问题,从而影响整个 Topic 的消息堆积。
- 横向扩展 Consumer 并不一定能提高消费能力,因为队列的数量是有限的,客户端数量一旦达到 Queue 数量,再扩容新节点无法提升消费能力,因为会有节点分配不到 Queue 而无法消费。
基于这些问题,RocketMQ 5.0 所推出的新的消费模式, POP Consumer 能够很好的解决上述这些问题和痛点。
在 POP Consumer 模式中,不再是基于队列模型,即客户端不需要 Rebalance 去分配 Queue。取而代之的是,它们都会使用 POP 请求所有的 Broker 获取消息进行消费。即使 Consumer-2 出现 hang,其内部消息也会让 Consumer-1 和 Consumer-3 进行消费,从而解决单个 Consumer 机器 hang 问题可能造成的消费堆积问题。
当然,还有一个好处就是,通过这种模式可以横向扩展提高消费速率,突破原先队列模式的数量限制。
这里简述一下 POP 模式的实现原理,客户端拉取消息分为两步:
- POP
- ACK
Pop 请求到 Broker 后,会基于 Queue 维度上加锁,保证同一个时刻只有一个客户端对同一个 Queue 拉取消息。获取到消息后,会保存到 Buffer 当中,等待 Ack 消息,这段时间这条消息是不可见的。客户端消费成功后返回 Ack 消息,Broker 会将消息从 Buffer 中移除,并且更新消费进度,标识消息消费成功。
当然,聪明的同学可能会问,如果在 Ack 阶段之前,客户端挂了会怎么办?
这一层 RocketMQ 当然也会考虑到这个问题,Ack 对超时的消息会放到延时队列,在对 Queue 获取消息前,会先去延时队列获取消息,先消费这部分超时未确认的消息。具体的代码实现逻辑的话,小年后面再出手撕源码文章。
不过,无论是 Pop 模式还是 Push 模式,在 Broker 层面其实都是基于 Pop 来实现的,由 Proxy 层对这两者做兼容处理。所以对于旧版本的SDK,也是可以无缝接入的新版本的消息服务。
API 与 SDK 全面升级
轻量级 SDK
在 RocketMQ 4.x 中,SDK 可以说是一个比较重的富客户端模式,因为它提供很多重要而又不可或缺的功能特性。
比如:消息的路由选址、顺序消费、事务消息、消费负载均衡、消息重试、点位管理、故障隔离等。小年就曾经在 SDK 中的消费负载均衡踩过坑:消息疯狂堆积!RocketMQ出Bug了?
而这一次 5.0 的升级,目的就是轻量化 SDK。
一方面其实上文也提到的,就是将客户端的一些无状的态功能抽取出来,下层到 Proxy。比如:负载均衡、流量治理、Push/Pop 消费模式。
另一方面,采用云原生的 gRPC 框架作为通信层的实现,能够更容易与 Service Mesh 等云原生能力集成。而且 gRPC 能非常友好的支持多种语言,所以也能同时 SDK 多语言的演进。
全新统一的 API
在 API 层面上,RocketMQ 5.0 对此做了统一和精简化,完善的错误处理,各语言 SDK API 在本地语言层面对齐,新的API 化繁为简,更易被使用和集成。
全面异步化。在 4.x 中存在异步和同步两套 API 提供给用户,但是这种方式不利于迭代,所以新的架构中将此统一起来。
并且对很多重 IO 操作也做了全面的异步化,比如:SDK 从服务端获取 topic 信息,这是一个重 IO 的操作,使用异步 Future 之后可以,非常方便地通过控制 Future 的超时时间来提供给用户自定义的超时控制。
观测性增强
Tracing 消息整个生命周期,包括发送、拉取、消费、ACK/NACK、存储等过程进行全生命周期的监控记录。其实在 RocketMQ 4.x 就已经提供消息轨迹这一功能了。
在 RocketMQ 5.0 新的实现中,拥抱了最新的 CNCF OpenTelemetry 社区协议规范,在客户端中嵌入了一个 OTLP exporter 将 tracing 数据批量发送至 proxy
OpenTelemetry 是什么呢?小年也是第一次听,于是就简单搜了一下资料。
OpenTelemetry 是 CNCF 的一个可观测性项目,提供观测性领域的标准化方案,解决观测性数据的模型、收集、处理等统一标准。
就好比我们常见的日志方案有:
- filebeats -> elasticsearch -> kibana
- fluentd -> elasticsearch -> kibana
这里就包括了数据的整个周期,从数据模型、数据采集、数据处理、数据分析等。市面上分布式链路跟踪框架五花八门,接口及协议字段及定义各不相同,只不过 OpenTelemetry 对整个周期提供了统一的接口、数据模型等。小年这里就不展开说了,有兴趣的同学自己去研究研究。
那么接入 OpenTelemetry 后的优势,一个是对消息全生命周期更为具体和具象化,能够跟踪和定位到任何一个阶段。第二个是可以更加方便开发者的自定义接入,对消息轨迹的自定义化和处理。
事件、流处理场景集成
除了主力服务于业务消息领域,RocketMQ 5.0 在其他领域也做了一些努力和尝试。比如上面所说的一个不可阻挡的云原生改造趋势,另外一个就是流计算。所以在 5.0 这个版本中,还提供了 RocketMQ Streams 这一套实时流计算框架。
那么与我们常见的 Flink、Spark 相比,RocketMQ Streams 主要优势在于轻量级的计算引擎,低部署成本和使用成本,除了消息队列,无额外依赖。
当然,RocketMQ Streams 也全面兼容 Flink,开发者可以将 Flink/Blink 已有 SQL 计算任务迁移到 RocketMQ,同样也可以将 RocketMQ 的实时计算任务迁移到 Flink。
在事件驱动领域上,RocketMQ 5.0 也开放了兼容标准CloudEvents协议的 RocketMQ-EventBridge 组件。
至于什么是事件驱动,RocketMQ-EventBridge 是如何工作的,有兴趣的同学可以自行研究,小年看了好一些资料也没明白个所以然,看来这个领域的学习还是需要一些学习成本的。
小结
总的来说,这次 RocketMQ 5.0 带来的变化确实让人很惊喜。
可以看得出来,不管是架构的全新升级、还是亮眼的新特性功能,RocketMQ 的发展已经不仅局限于业务消息领域这一块,而是从长远的角度考虑,如何贴近当前的技术潮流发展,如何为开发者提供更健全更丰富的功能的角度出发。
参考: