RocketMQ 4.x 版本的 CommitLog、ConsumeQueue 和 IndexFile 设计详解

179 阅读3分钟

以下是对 RocketMQ 4.x 版本的 CommitLog、ConsumeQueue 和 IndexFile 设计的详细分析,以及消息存储和查找过程的实际实现。

output (3).png

1. CommitLog 设计详解

结构

  • CommitLog 文件:CommitLog 是一个顺序写入的日志文件,消息以字节流的形式顺序追加到文件末尾。
  • 文件切分:每个 CommitLog 文件的默认大小是 1GB,当文件写满时,会创建新的文件。

写入流程

  1. 消息接收:Broker 接收来自生产者的消息。
  2. 消息编码:将消息编码为字节流,包含消息的元数据(Topic、QueueId、消息体等)。
  3. 顺序写入:消息被追加到 CommitLog 文件的末尾。
  4. 刷盘策略
    • 异步刷盘:消息写入内存后立即返回,由后台线程异步刷盘。
    • 同步刷盘:消息写入内存后需要等待数据被刷写到磁盘才返回。

2. ConsumeQueue 设计详解

结构

  • ConsumeQueue 文件:ConsumeQueue 是每个 Topic每个 Queue 逻辑队列文件,用于存储消息索引
  • 索引记录:每条记录固定 20 字节,包含消息在 CommitLog 中的物理偏移量消息大小Tag hashcode

创建流程

  1. 定位 ConsumeQueue:根据 Topic 和 QueueId 定位对应的 ConsumeQueue 文件。
  2. 记录索引:将消息在 CommitLog 中的物理偏移量、消息大小和 Tag hashcode 写入 ConsumeQueue。
  3. 顺序写入:ConsumeQueue 文件是顺序写入的,便于快速定位和读取。

3. IndexFile 设计详解

结构

  • IndexFile 文件:IndexFile 是基于哈希表的索引文件,用于根据消息 key 快速查找消息。
  • 哈希桶(bucket):IndexFile 使用哈希桶存储索引,每个哈希桶记录消息的 CommitLog 偏移量和时间戳。

创建流程

  1. 计算哈希:计算消息 key 的哈希值。
  2. 定位哈希桶:根据哈希值找到对应的哈希桶。
  3. 记录索引:将消息在 CommitLog 中的物理偏移量和时间戳写入哈希桶。

消息存储和查找过程

消息存储过程

假设消息 msg 被发送到 TopicA 的 Queue0,带有 key1,存储过程如下:

  1. 写入 CommitLog

    • 将 msg 编码为字节流。
    • 将编码后的消息顺序写入到 CommitLog 文件末尾。
  2. 创建 ConsumeQueue 索引

    • 定位 TopicA 的 Queue0 对应的 ConsumeQueue 文件。
    • 记录 msg 在 CommitLog 中的物理偏移量、消息大小和 Tag hashcode。
  3. 创建 IndexFile 索引

    • 计算 key1 的哈希值。
    • 将 key1 的哈希值对应的哈希桶中记录 msg 在 CommitLog 中的偏移量和时间戳。

消息查找过程

基于 ConsumeQueue 查找
  1. 定位 ConsumeQueue根据 Topic 和 QueueId 定位对应的 ConsumeQueue 文件
  2. 读取索引:根据消费者的消费进度,从 ConsumeQueue 中读取消息索引
  3. 读取 CommitLog:根据索引中的 CommitLog 偏移量,从 CommitLog 文件中读取消息数据
  4. 返回消息:将读取到的消息返回给消费者。
基于 IndexFile 查找
  1. 计算哈希:计算 key1 的哈希值。
  2. 定位哈希桶:根据哈希值找到对应的哈希桶。
  3. 遍历桶内记录:遍历哈希桶内的索引记录,查找匹配的 key。
  4. 读取 CommitLog:根据索引记录中的 CommitLog 偏移量,从 CommitLog 文件中读取消息数据。
  5. 返回消息:将读取到的消息返回给查询请求。

通过这些设计,RocketMQ 实现了高效的消息存储和快速查找。CommitLog 提供高效的顺序写入性能,ConsumeQueue 提供快速的消息拉取索引,而 IndexFile 则支持基于 key 的快速查找。