从基础功能拆解RocketMQ的架构设计与实现

176 阅读4分钟

RocketMQ 系统架构

image.png

RocketMQ 由 Producer、NameServer、Broker、Consumer 四大模块组成。其中,NameServer 是 RocketMQ 的元数据存储组件。另外,在 RocketMQ 5.0 后,还增加了 Proxy 模块,用来支持 gRPC 协议,并为后续的计算存储分离架构做准备。

RocketMQ 有 Topic、MessageQueue、Group 的概念,一个 Topic 可以包含一个或多个 MessageQueue,一个 Group 可以订阅一个或多个 Topic。MessageQueue 是具体消息数据的存储单元,订阅的时候通过 Group 来管理消费订阅关系。

协议和网络模块

RocketMQ 5.0 之前支持自定义的 Remoting 协议,在 5.0 之后,增加了 gRPC 协议的支持。

image.png

Remoting主要缺点是私有协议客户端的重复开发成本,以及与第三方服务集成的不便捷。

数据存储

数据存储模块分为元数据存储和消息数据存储两部分。

元数据存储

RocketMQ 的元数据信息实际是存储在 Broker 上的,Broker 启动时将数据上报到 NameServer 模块中汇总缓存。

image.png

NameServer 是多节点部署的,是一个集群。 但是不同节点之间是没有相互通信的,所以本质上多个 NameServer 节点间数据没有一致性的概念,是各自维护自己的数据,由每台 Broker 上报元数据来维护每台 NameServer 节点上数据的准确性。

消息数据

Topic 可以包含一个或多个 MessageQueue,数据写入到 Topic 后,最终消息会分发到对应的 MessageQueue 中存储。

一个节点对应一个总的存储文件,单个 Broker 节点下所有的队列共用一个日志数据文件(CommitLog)来存储,和 RabbitMQ 采用的是同一种存储结构。

ConsumeQueue 是逻辑消费队列,是消息消费的索引,不存储具体的消息数据。引入的目的主要是提高消息消费的性能,ConsumeQueue 文件可以看成是基于 Topic 的 CommitLog 索引文件。

IndexFile 是索引文件,它在文件系统中是以 HashMap 结构存储的。在 RocketMQ 中,通过 Key 或时间区间来查询消息的功能就是由它实现的。

我们会对 CommitLog 进行分段存储。CommitLog 底层默认单个文件大小为 1G,消息是顺序写入到文件中,当文件满了,就会写入下一个文件。对于 ConsumeQueue 和 IndexFile,则不需要分段存储,因为它们存储的是索引数据,数据量一般很小。

RocketMQ 不是按照主题或队列维度来清理数据的,而是按照节点的维度来清理的。

生产者和消费者

生产端

从生产端来看,生产者是将数据发送到 Topic 或者 Queue 里面的。如果是发送到 Topic,则数据要经历生产数据分区分配的过程。即决定消息要发送到哪个目标分区。

由于 RocketMQ 在协议层不支持批量发送消息的协议,所以在 SDK 底层是没有等待、聚合发送逻辑的。所以如果需要批量发送数据,就需要在生产的时候进行聚合,然后发送。

RocketMQ 支持单向发送、同步发送、异步发送三种发送形式。单向发送(Oneway)指发送消息后立即返回,不处理响应,不关心是否发送成功。同步发送(Sync)指发送消息后等待响应。异步发送(Async)指发送消息后立即返回,在提供的回调方法中处理响应。

消费端

RocketMQ 同时支持 Pull、Push、Pop 三种消费模型。

消息粒度负载均衡是指同一消费者分组内的多个消费者,将按照消息粒度平均分摊主题中的所有消息。即同一个队列中的消息,会被平均分配给多个消费者共同消费。

队列粒度负载均衡是指同一消费者分组内的多个消费者,将按照队列粒度消费消息,即每个队列仅被一个消费者消费。

HTTP 协议支持和管控操作

RocketMQ 的管控操作都是通过 Remoting 协议支持的,在 gRPC 协议中也不支持管控操作。即在 Broker 中,通过 Remoting 协议暴露不同的接口或者在 NameServer 中暴露 TCP 的接口,来实现一些对应的管控操作。


此文章为11月Day11学习笔记,内容来源于极客时间《深入拆解消息队列 47 讲》