[toc]
概述
CommitLog
作为消息存储的载体;ConsumeQueue
面向消费端,被设计为 CommitLog
的消息索引;IndexFile
则提供了一种可以通过 key
或时间区间来查询消息的方法。
下面,就来介绍 IndexFile
。
IndexFile 设计介绍
IndexFile
文件的命名为:当前文件创建时的时间,精确到毫秒。例如 20210626134145150
IndexFile
结构如下
IndexHead
beginTimestamp
文件中消息的最小存储时间
endTimestamp
消息的最大存储时间
beginPhyoffset
消息的最小偏移量
endphyoffset
消息的最大物理偏移量
hashSlotCount
已用 hash 槽个数
indexCount
已用 index 个数
从 IndexHead
的结构,我们可以看出,主要是一些总指标,这些指标,都是为了它方便进行 增删改查
Hash 槽
hash 槽,每个子元素,有 4 个字节。
槽上存储的是 key 的 hash 值。
这里的 key 指:topic
+ #
+ 消息的 key 或 topic
+ #
+ uniqKey
。key
由生产者发送消息时填写,多个用 空格 隔开。
槽上存储的是:最新的 item 在 Index 上的位置
Index Item
hashcode
key
的 hashcode
pyhoffset
commitlog
的物理偏移量
timeDiff
timeDiff
= commitLog
写入时间 – IndexFile
第一条消息写入时间
preIndexNo
preIndexNo
把 hash 冲突的 item 组成链表。hash 槽上的记录的元素的位置,永远是最新加入的 item 位置。
IndexFile 消息写入
写入 key1 后, IndexFile 变成了这样子
写入 key2 后, hash 出现冲突,RocketMQ
会利用 Index item
的 preIndexNo
解决冲突
写入 key3, hash 未出现冲突,正常写入
IndexFile 查找消息
知道了 IndexFile 如何处理 hash 冲突了,那根据 key 查询就很好理解了。
按照 key
进行查询的时候,根据 hash
槽上的 index item
位置 定位到 最新的 index item
, 然后根据 preIndexNo
往前查找,直到 preIndexNo = 0
停止。
因为,index item
存储着 commitlog
的偏移量,因为可以找到具体的消息
IndexFile 落盘
IndexFile
没有专门的线程处理刷盘。
在 RocketMQ
当中,CommitLog
, ConsumeQueue
, IndexFile
都是通过 mmap()
(后续讲解) 创建出来的文件。在内存操作,相当于操作磁盘上的文件。但是刷盘的动作,依赖操作系统。
以下为个人观点
IndexFile
只是用于对 CommitLog
进行索引(方便运维),在 RocketMQ
的存储主线中,并非那么重要,所以不专门提供刷盘线程,刷盘动作直接依赖操作系统
为什么说 IndexFile
可能不是那么重要呢?因为 ReputMessageService
在转发时,可通过参数 messageIndexEnable
关闭转发至 IndexFile