以下是对 RocketMQ 4.x 版本的 CommitLog、ConsumeQueue 和 IndexFile 设计的详细分析,以及消息存储和查找过程的实际实现。
1. CommitLog 设计详解
结构
- CommitLog 文件:CommitLog 是一个顺序写入的
日志文件
,消息以字节流的形式顺序追加到文件末尾。 - 文件切分:每个 CommitLog 文件的默认大小是
1GB
,当文件写满时,会创建新的文件。
写入流程
- 消息接收:Broker 接收来自生产者的消息。
- 消息编码:将消息编码为字节流,包含消息的元数据(Topic、QueueId、消息体等)。
- 顺序写入:消息被追加到 CommitLog 文件的末尾。
- 刷盘策略:
- 异步刷盘:消息写入内存后立即返回,由后台线程异步刷盘。
- 同步刷盘:消息写入内存后需要等待数据被刷写到磁盘才返回。
2. ConsumeQueue 设计详解
结构
- ConsumeQueue 文件:ConsumeQueue 是
每个 Topic
的每个 Queue
的逻辑队列文件
,用于存储消息索引
。 - 索引记录:每条记录
固定 20 字节
,包含消息在 CommitLog 中的物理偏移量
、消息大小
和Tag hashcode
。
创建流程
- 定位 ConsumeQueue:根据 Topic 和 QueueId 定位对应的 ConsumeQueue 文件。
- 记录索引:将消息在 CommitLog 中的物理偏移量、消息大小和 Tag hashcode 写入 ConsumeQueue。
- 顺序写入:ConsumeQueue 文件是顺序写入的,便于快速定位和读取。
3. IndexFile 设计详解
结构
- IndexFile 文件:IndexFile 是基于
哈希表的索引文件
,用于根据消息 key 快速查找消息。 - 哈希桶(bucket):IndexFile 使用
哈希桶存储索引
,每个哈希桶记录消息的 CommitLog 偏移量和时间戳。
创建流程
- 计算哈希:计算消息 key 的哈希值。
- 定位哈希桶:根据哈希值找到对应的哈希桶。
- 记录索引:将消息在 CommitLog 中的物理偏移量和时间戳写入哈希桶。
消息存储和查找过程
消息存储过程
假设消息 msg 被发送到 TopicA 的 Queue0,带有 key1,存储过程如下:
-
写入 CommitLog:
- 将 msg 编码为字节流。
- 将编码后的消息顺序写入到 CommitLog 文件末尾。
-
创建 ConsumeQueue 索引:
- 定位 TopicA 的 Queue0 对应的 ConsumeQueue 文件。
- 记录 msg 在 CommitLog 中的物理偏移量、消息大小和 Tag hashcode。
-
创建 IndexFile 索引:
- 计算 key1 的哈希值。
- 将 key1 的哈希值对应的哈希桶中记录 msg 在 CommitLog 中的偏移量和时间戳。
消息查找过程
基于 ConsumeQueue 查找
- 定位 ConsumeQueue:
根据 Topic 和 QueueId
定位对应的ConsumeQueue 文件
。 - 读取索引:根据消费者的消费进度,从 ConsumeQueue 中
读取消息索引
。 - 读取 CommitLog:根据索引中的 CommitLog 偏移量,从 CommitLog 文件中
读取消息数据
。 - 返回消息:将读取到的消息返回给消费者。
基于 IndexFile 查找
- 计算哈希:计算 key1 的哈希值。
- 定位哈希桶:根据哈希值找到对应的哈希桶。
- 遍历桶内记录:遍历哈希桶内的索引记录,查找匹配的 key。
- 读取 CommitLog:根据索引记录中的 CommitLog 偏移量,从 CommitLog 文件中读取消息数据。
- 返回消息:将读取到的消息返回给查询请求。
通过这些设计,RocketMQ 实现了高效的消息存储和快速查找。CommitLog 提供高效的顺序写入性能,ConsumeQueue 提供快速的消息拉取索引,而 IndexFile 则支持基于 key 的快速查找。