【RocketMQ入门到精通 | 4】工作原理:indexFile索引文件
indexFile
RocketMQ提供了根据Key查询消息的功能,索引数据是包含了key的消息被发送到Broker中被写入的,如果没有包含key则不写。
索引条目结构
每个Broker都包含一组indexFile,每个indexFile以其被创建时的时间戳命名。 每个indexFile文件由三部分构成:indexHeader,slots槽位,indexes索引数据。每个 indexFile文件中包含500w个slot槽。而每个slot槽又可能会挂载很多的index索引单元。
indexHeader固定40个字节,其中存放着如下数据:
- beginTimestamp:该indexFile中第一条消息的存储时间
- endTimestamp:该indexFile中最后一条消息存储时间
- beginPhyoffset:该indexFile中第一条消息在commitlog中的偏移量commitlog offset
- endPhyoffset:该indexFile中最后一条消息在commitlog中的偏移量commitlog offset
- hashSlotCount:已经填充有index的slot数量(并不是每个slot槽下都挂载有index索引单元,这里统计的是所有挂载了index索引单元的slot槽的数量)
- indexCount:该indexFile中包含的索引单元个数(统计出当前indexFile中所有slot槽下挂载的所有index索引单元的数量之和)
slots是固定的,但indexs索引数据是变化的,如果在每个slot后面存放其对应的索引数据,其所需的空间是无法确定的。因此统一将索引数据放到slots之后,那么用来存储索引数据的空间是无穷的。
为了便于理解,slots和indexs对应关系如图:
index索引单元默认20个字节,其中存放着以下四个属性:
- keyHash:消息中指定的业务key的hash值
- phyOffset:当前key对应的消息在commitlog中的偏移量commitlog offset
- timeDiff:当前key对应消息的存储时间与当前indexFile创建时间的时间差
- preIndexNo:当前slot下当前index索引单元的前一个index索引单元的indexNo
keyhash值 % 500w的结果即为slot槽位,然后将该slot值修改为该index索引单元的indexNo,根据这个indexNo可以计算出该index单元在indexFile中的位置。
indexNo是一个在indexFile中的流水号,从0开始依次递增。indexNo在index索引单元中是没有体现的,其是通过在indexes中依次数出来的。
在每个index索引单元中增加了preIndexNo,用于指定该slot中当前index索引单元的前一个index索引单元。而slot中始终存放的是其下最新的index索引单元的indexNo。
文件名
根据业务key进行查询时,查询条件除了key之外,还需要指定一个要查询的时间戳,表示要查询不大于该时间戳的最新的消息。
时间戳文件名可以简化查询,提高查询效率。
indexFile创建时机:
- 当第一条带key的消息发送来后,系统发现没有indexFile,此时会创建第一个indexFile文件
- 当一个indexFile中挂载的index索引单元数量超出2000w个时,会创建新的indexFile。当带key的消息发送到来后,系统会找到最新的indexFile, 并从其indexHeader的最后4字节中读取到 indexCount。若indexCount >= 2000w时,会创建新的indexFile。