基本概念
Message消息
消息是指,消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个Topic(主题) 。
特点:
-
不可变性:
- 消息一旦产生内容就不会被修改,只有读权限
-
持久性:
- RocketMQ默认对消息持久化,消息主要持久化存储在磁盘上的 CommitLog 文件和 ConsumeQueue 文件中,这两类文件共同构成了 RocketMQ 的存储体系。
消息标识
RocketMQ每个信息拥有MessageID,同时可以拥有带有业务标识的Key
MessageID有两个:
- 消费者send()生成
- 到达Broker也会自动生成
生成规则:
- msgId:由producer端生成,其生成规则为: producerIp + 进程pid + MessageClientIDSetter类的ClassLoader的hashCode + 当前时间 + AutomicInteger自增计数器
- offsetMsgId:由broker端生成,其生成规则为:brokerIp + 物理分区的offset(Queue中的 偏移量)
- key:由用户指定的业务相关的唯一标识
Topic主题
Topic是一类消息的集合,每条消息只能属于一个主题,并且也是RocketMQ对消息订阅的基本单位。 但主题是一个逻辑概念 ,并不是实际的消息容器。其内部包含Queue(队列),消息实际存储在各队列内。
特点:
-
分类隔离数据(隔离性):
- 官方建议将不同业务类型的数据拆分到不同的主题进行管理,实现数据和订阅的隔离性 (在RocketMQ5.0中,系统会对发送的消息类型和主题定的消息类型进行强制校验,若校验不通过,则消息发送请求会被拒绝,并返回类型不匹配异常。)
-
无状态:
- Topic 本身是一个逻辑概念,不存储具体消息数据
-
动态性:
- 运行时可通过命令或控制台增加 Topic 的队列数,提升并行处理能力。
- Topic 的队列可分布在多个 Broker 节点上,实现消息存储和处理的分布式扩展。
MessageQueue队列
存储消息的物理实体, 是 RocketMQ 消息的最小存储单元 。一个Topic中可以包含多个Queue,每个Queue中存放的就是该Topic的消息,以此实现队列数量的水平拆分和队列内部的流式存储。Queue类似于Kafka的分区。
特点:
-
存储顺序性
- 单个 MessageQueue 内的消息严格遵循 "先进先出"(FIFO) 原则,消息的写入和消费顺序完全一致。消息在队列中的位置和消息之间的顺序通过消费偏移量(Offset) 进行标记管理。
-
流式操作语义
- RocketMQ 基于队列的存储模型可确保消息从任意位点读取任意数量的消息,以此实现类似聚合读取、回溯读取等特性
-
负载均衡
- 生产者通过 Queue 分发消息,避免单 Queue 写入压力过大。消费组内的消费者通过分配 Queue 实现负载均衡
-
故障隔离
- 单个 Queue 异常(如磁盘损坏)仅影响该 Queue 的消息,不会导致整个 Topic 不可用
系统架构
Producer生产者
RocketMQ 系统中用来构建并传输消息到服务端的运行实体。
消息生产者,负责生产消息。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
RocketMQ中的消息生产者都是以生产者组(Producer Group) 的形式出现的。生产者组是同一类生产者的集合。
生产者和主题的关系为多对多关系。
特点:
-
失败重试:
- 发送失败时可自动重试,默认 2 次
-
事务:
- 通过事务机制保证消息发送与本地业务的最终一致性
-
多种发送方式:
- 同步发送(Sync Send):发送消息后等待 Broker 确认,直到收到响应才返回
- 异步发送(Async Send):发送消息后立即返回,Broker 处理完成后通过回调通知结果
- 单向发送(Oneway Send):仅发送消息不等待确认,也无回调
-
扩展性和容灾:
- 同一个生产者可以向多个主题发送消息,同一个主题也可以接收多个生产者的消息。可以动态调整,并且一个生产者或者主题挂了可以有别的生产者或者主题接上工作(即容灾)
Consumer消费者
负责消费消息。消费者从Broker中获得消息并处理
以消费者组的形式,消费的是同一个Topic类型的消息。方便负载均衡(将一个Topic中的queue平均分配给一个消费者组里的不同的消费者。Queue的负载均衡而不是消息的负载均衡)和容错(消费者组里要有挂掉的消费者,其他消费者可以接着消费)
消费者组中Consumer的数量应该小于等于订阅Topic的Queue数量。如果超出Queue数量,则多出的 Consumer将不能消费消息。
不过,一个Topic类型的消息可以被多个消费者组同时消费。
特点:
-
投递顺序性
- 消费者消费消息时,RocketMQ 向消费者客户端投递消息的顺序
-
失败重试
-
消费者消费消息失败时,系统会按照重试策略,将指定消息投递给消费者重新消费。
-
重试策略包括:
- 最大重试次数:表示消息可以重新被投递的最大次数,超过最大重试次数还没被成功消费,消息将被投递至死信队列或丢弃。
- 重试间隔( 仅在PushConsumer消费类型下有效 ) :RocketMQ 服务端重新投递消息的间隔时间。 最大重试次数和重试间隔的取值范围及默认值
-
NameServer
Broker与Topic的注册中心。支持Broker的动态注册与发现
Broker管理: 接受Broker集群的注册信息并且保存下来作为路由信息的基本数据;提供心跳检测机制,检查Broker是否还存活。
路由信息管理: 每个NameServer中都保存着Broker集群的整个路由信息和用于客户端查询的队列 信息。Producer和Conumser通过NameServer可以获取整个Broker集群的路由信息,从而进行消 息的投递和消费。
通常以集群部署,无状态,各个节点无差异,不进行信息通信。
在 Broker节点启动时,轮询NameServer列表,与每个NameServer节点建立长连接,发起注册请求。
在 NameServer内部维护着⼀个Broker列表,用来动态存储Broker的信息。
特点:
-
路由发现
- Pull模型。NameServer不会主动推送给客户端变化的Topic路由信息,而是由客户端定时拉取最新的路由。默认每30s拉取一次。
-
路由剔除
- meServer每十秒扫描一次Broker表,如果Broker最新心跳时间戳距离当前时间超过120s,则将Broker剔除
-
客户端选择策略
- 客户端首先生成一个随机数,再与NameServer节点数量取模,取模后的结果就是要连接的NameServer,即随机连接。若失败,采用轮询
Broker
Broker充当着消息中转角色,负责存储消息、转发消息。Broker在RocketMQ系统中负责接收并存储从生产者发送来的消息,同时为消费者的拉取请求作准备。Broker同时也存储着消息相关的元数据,包括消费者组消费进度偏移offset、主题、队列等。
主从集群,Master处理读写,slave处理读
数据复制与刷盘策略
复制策略
Broker的Master与Slave的数据同步方式分为同步复制与异步复制:
- 同步复制:消息写入master,master等待slave同步数据成功再向生产者返回成功ack
- 异步复制:消息写入master直接返回ack
异步复制策略会降低系统的写入延迟,提高了系统的吞吐量
刷盘策略
指的是broker中消息的落盘 方式,即消息从broker内存持久化到磁盘的方式,即上文的消息写入master的具体方式。分为同步刷盘与异步刷盘:
- 同步刷盘:消息持久化到broker的磁盘中才算消息写入成功
- 异步刷盘:写入到broker内存中就算消息写入成功
异步刷盘策略会降低系统的写入延迟,提高了系统的吞吐量
消息写入内存一般是写入PageCache。对于异步刷盘,不会在写入PageCache后立刻落盘,而是PageCache达到一定量时自动进行落盘。
Broker集群模式
多Master
broker集群仅由多个master构成,不存在slave
优点:
- 配置简单
- 单个master宕机或重启维护对应用无影响。
-
- 在磁盘配置为RAD10时,即使机器宕机不可恢复,消息在同步刷盘的策略下也不会丢(异步刷盘会丢失少量消息)
缺点:
- 单台宕机,这个机器上未被消费的消息在机器恢复之前不可以消费
多Master多Slave模式(异步复制)
broker集群由多个master构成,每个master又配置了多个slave(在配置了RAID磁盘阵列的情况下,一 个master一般配置一个slave即可)。
使用的是异步复制策略,master宕机后能够自动将slave切换为master。不过存在延迟问题导致消息丢失。
RAID磁盘阵列用的也是异步复制的策略,但延迟是微秒级的,所以其丢失的数据量较少。
多Master多Slave模式(同步双写)
该模式是多Master多Slave模式的同步复制实现。所谓同步双写,指的是消息写入master成功后, master会等待slave同步数据成功后才向producer返回成功ACK,即master与slave都要写入成功后才会返回成功ACK。
优点:
消息的安全性更高,不存在消息丢失的情况。但单个消息的RT略高,从而导致性能要略低(大约低10%)。
缺点:
当 Master 节点挂掉后,Slave 节点不会自动转为 Master ,需要依赖 NameServer 的故障检测 和 手动或自动的主从切换机制 来完成角色转换。
最佳实践
为Master配置RAID磁盘阵列+单slave。
master+RAID磁盘阵列与多master多slave对比:
- RAID效率更高,搭建成本更高
- 多Master+RAID阵列,其仅仅可以保证数据不丢失,但其可能会影响到消息的订阅。但其执行效率要远高于多Master多Slave集群
- 多Master多Slave集群,其不仅可以保证数据不丢失。其运行效率要低于多Master+RAID阵列
RAID磁盘阵列
关键技术
镜像技术:
- 对于 RAID 而言,采用镜像技术最典型地的用法就是同时在磁盘阵列中产生两个完全相同的数据副本,并且分布在两个不同的磁盘上。
- 当一个数据副本失效不可用时,外部系统仍可正常访问另一副本,不会对应用系统运行和性能产生影响。失效的副本直接复制有效副本即可完成故障修复。
- 并发读,但不能并行写
- 需要双倍存储空间
数据条带技术
- 将一块连续的数据分成很多小部分并把它们分别存储到不同磁盘上。这就能使多个进程可以并发访问数据的多个不同部分,从而极大地提升I/O性能。
数据校验技术
- RAID 要在写入数据的同时进行校验计算,并将得到的校验数据存储在 RAID 成员磁盘中。当数据出错时,根据存入的校验数据重建出错的数据。
- 相比于镜像技术,需要空间小,但计算量大,要求计算机运算速度,且必须使用硬件RAID控制器。检验技术复杂。
分类
- 软RAID: 所有功能均有操作系统和 CPU 来完成。
- 硬RAID: 配备了专门的 RAID 控制处理芯片和 I/O 处理芯片以及阵列缓冲,不占用 CPU 资源。
- 混合RAID: 具备 RAID 控制处理芯片,但没有专门的I/O 处理芯片,需要 CPU 和驱动程序来完成 。
等级
JBOD
JBOD将多个磁盘串联起来,形成一个巨大的逻辑磁盘
JBOD 的数据存放机制是由第一块磁盘开始按顺序往后存储,当前磁盘存储空间用完后,再依次往后面的磁盘存储数据。JBOD 存储性能完全等同于单块磁盘,而且也不提供数据安全保护。
RAID0

RAID0是一种简单的、无数据校验的数据条带化技术。
实际上不是一种真正的 RAID ,因为它并不提供任何形式的冗余策略。
RAID0 将所在磁盘条带化后组成大容量的存储空间,将数据分散存储在所有磁盘中,以独立访问方式实现多块磁盘的并读访问。
RAID1

RAID1 就是一种镜像技术,它将数据完全一致地分别写到工作磁盘和镜像磁盘。
一旦工作磁盘发生故障,系统将自动切换到镜像磁盘
RAID10

RAID10是一个RAID1与RAID0的组合体,所以它继承了RAID0的快速和RAID1的安全。
先做条带,再做镜像。把即将进来的数据先分散到不同的磁盘,再将磁盘中的数据做镜像。
RAID01
先做镜像再做条带。即将进来的数据先做镜像,再将镜像数据写入到与之前数据不同的磁盘,即再做条带。