RocketMQ 内容详解【二、RocketMQ 机制篇(核心特性与原理)】
第二章 · RocketMQ 机制篇(核心特性与原理)
2.1 消息存储机制
2.1.1 存储架构概览
RocketMQ 的消息存储是统高吞吐和可靠性的核心。存储架构主要由三部分组成:CommitLog、ConsumeQueue 和 IndexFile。
| 模块 | 功能 |
|---|---|
| CommitLog | 消息的物理存储,顺序写磁盘,保证高吞吐 |
| ConsumeQueue | 消息逻辑索引,用于 Consumer 快速定位消息 |
| IndexFile | Key 索引文件,用于根据消息 key 快速检索消息 |
整体架构如下:

每个模块的设计目标都是 高性能、高可靠和可扩展。
2.1.2 CommitLog 设计
CommitLog 消息写入流程

源码解析:
DefaultMQProducer.send()调用sendKernelImpl()sendKernelImpl()会查询 Topic 路由信息 (tryToFindTopicPublishInfo)- Broker 的
CommitLog.appendMessage()顺序写入文件 ConsumeQueue使用 逻辑队列映射 CommitLog 物理偏移IndexFile根据消息 Key 建立倒排索引- Producer 收到 ACK 后完成发送流程
顺序写磁盘
- CommitLog 使用
MappedFile映射磁盘文件,每个文件默认 1G - 消息顺序追加写入,避免随机磁盘 I/O
- 每条消息使用
AppendMessageCallback进行序列化后写入
零拷贝机制
- 使用
FileChannel.transferTo()实现从内存映射文件到网络缓冲区的零拷贝 - 数据在内存和网络之间无需多次复制,提高发送吞吐
消息结构(源码 MessageExtEncoder)
int totalSize; // 消息总长度
int magicCode; // 魔数校验
int bodyCRC; // 消息体CRC校验
int queueId; // 队列ID
long queueOffset; // 队列偏移
long physicalOffset; // 物理偏移
long sysFlag; // 系统标记
long bornTimestamp; // 消息生成时间
long storeTimestamp; // 存储时间
int bodyLength; // 消息体长度
byte[] body; // 消息体
刷盘策略
- 同步刷盘(SYNC_FLUSH):Producer 等待 Broker 写入磁盘确认
- 异步刷盘(ASYNC_FLUSH):Broker 异步写磁盘,提高吞吐,但可能丢失最后几条消息
2.1.3 ConsumeQueue 设计
- 逻辑队列:每个 Topic + Queue 对应一个 ConsumeQueue 文件
- 索引结构:每条索引 20 字节,包括物理偏移、消息长度和 tagCode
- 作用:Consumer 通过 ConsumeQueue 查找消息在 CommitLog 的偏移,然后拉取消息
- 文件结构:顺序追加,每条索引固定长度,支持快速二分查找
源码解析:
- Consumer 可以是 Push 模式或 Pull 模式,本质仍是 Pull 拉取
- Broker 通过
ConsumeQueue快速找到消息物理偏移 - 然后从
CommitLog中读取消息内容 - 消费成功后,Consumer 调用
ackMessage更新消费进度
源码片段(存储索引)示意:
public boolean putMessagePositionInfoWrapper(final long offset, final int size, final long tagsCode, final long storeTimestamp, final long bitMap) {
// 生成索引条目
// 写入逻辑队列文件
}
2.1.4 IndexFile 设计
- Key 索引:支持根据业务 key 快速检索消息
- 文件结构:Hash(key) → 链表 → CommitLog 偏移
- 索引更新:每条消息写入 CommitLog 时同步更新 IndexFile
源码关键类:IndexService,提供查询接口 queryOffset(topic, key)
2.2 消息发送与消费流程
2.2.1 消息发送方式
RocketMQ 支持三种发送模式:
| 模式 | 特点 | 使用场景 |
|---|---|---|
| 同步发送 | Producer 等待 Broker ACK | 高可靠场景,如支付消息 |
| 异步发送 | Producer 通过回调接收 ACK | 高吞吐场景,如日志收集 |
| 单向发送 | Producer 不等待 ACK | 高性能但不可靠,如统计数据 |
源码调用链:
public SendResult send(final Message msg) throws MQClientException, RemotingException {
TopicPublishInfo publishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
MessageQueue mq = selectOneMessageQueue(publishInfo);
sendKernelImpl(msg, mq, communicationMode, sendCallback);
}
2.2.2 消费模式:Push / Pull
- Pull 模式:Consumer 主动拉取消息,可以控制消费速率和并发
- Push 模式:Broker 将消息“推送”给 Consumer,本质上仍是 Pull + 长轮询
消息流序列图:
2.2.3 消息重试与幂等性
- 重试机制:消费失败消息进入重试队列,消费端需要幂等处理
- 重试次数配置:
maxReconsumeTimes - 延迟队列:重试消息根据延迟等级延迟重新投递
2.3 消息顺序与事务消息
2.3.1 顺序消息实现原理
- 局部顺序:Queue 级别顺序保证
- 线程绑定:Consumer 每个线程消费一个 Queue
源码解析:
-
Producer 通过业务 Key 计算 QueueId,保证同一业务 Key 消息发送到同一队列
-
Broker 保证顺序写 CommitLog 与 ConsumeQueue
-
Consumer 同线程顺序消费队列消息
-
源码示意:
int queueId = Math.abs(key.hashCode()) % topicPublishInfo.getMessageQueueList().size();
send(msg, queueId);
2.3.2 事务消息(半消息机制)
- 半消息:Producer 发送事务消息到 Broker,消费者不可见
- 事务回查:Broker 定期检查未提交的事务消息,调用 Producer 回查接口
- 源码流程:
源码解析:
sendMessageInTransaction()发送半消息到 Broker- Broker 将消息标记为
HALF,暂不对 Consumer 可见 - Producer 执行本地事务逻辑
- TransactionManager 根据执行结果通知 Broker 提交或回滚
- Broker 定期回查未提交事务,确保消息最终一致性
sendMessage(MessageType.HALF_MSG)
checkTransactionState(HALF_MSG)
- 提交或回滚:Producer 根据业务执行结果调用 commit 或 rollback
2.4 消息过滤与路由机制
源码解析:
- Consumer 通过 NameServer 获取路由信息
- Broker 根据 ConsumeQueue 中 tagsCode 或 SQL92 表达式过滤消息
- Consumer 只接收匹配的消息
2.4.1 Tag 与 SQL92 过滤
- Tag:轻量级过滤,可在 Broker 端快速匹配
- SQL92:复杂过滤,支持消息属性表达式
- Broker 可在 ConsumeQueue 先做 Tag 过滤,再在 Consumer 做 SQL92 过滤
2.4.2 NameServer 与路由发现
- 轻量级服务发现,维护 Topic 与 Broker 的映射
- Producer / Consumer 查询路由:
public TopicRouteData getRouteInfoFromNameServer(String topic)
- 支持 Broker 动态上下线,Producer 路由自动更新
2.5 消息重试与死信队列(DLQ)
源码解析:
- Broker 内部维护多个延迟队列
- 消费失败消息根据
delayLevel放入相应队列 - Consumer 重试拉取
- 超过
maxReconsumeTimes的消息进入 DLQ,便于人工处理或补偿
2.5.1 重试策略
-
消费失败消息进入重试队列,延迟投递
-
延迟队列:
- 延迟等级 1~18 对应不同时间间隔
- Broker 根据 delayLevel 调整消息投递时间
-
源码逻辑:
int delayLevel = computeDelayLevel(reconsumeTimes);
putMessageToDelayQueue(msg, delayLevel);
2.5.2 DLQ 存储与处理
- 超过最大重试次数消息进入死信队列(DLQ)
- Consumer 可定期扫描 DLQ 进行补偿处理
2.6 总结
- RocketMQ 存储机制:CommitLog 顺序写 + 零拷贝、ConsumeQueue 逻辑索引、IndexFile Key 索引
- 消息发送与消费:同步/异步/单向发送,Push/Pull 消费模式,重试与幂等性
- 顺序与事务消息:Queue 级顺序保证,半消息 + 回查机制实现事务消息
- 消息过滤与路由:Tag/SQL92 过滤,NameServer 路由发现
- 重试与死信队列:延迟队列 + DLQ 保障可靠性
本章内容为源码级、机制原理级全面解析,为深入理解 RocketMQ 消息传输、存储和消费流程奠定基础。
本文来自博客园,作者:NeoLshu,转载请注明原文链接:https://www.cnblogs.com/neolshu/p/19120315

浙公网安备 33010602011771号