09第三章:03_indexFile

一、indexFile

除了通过通常的指定 Topic 进行消息消费外,RocketMQ 还提供了根据 key 进行消息查询的功能。该查询是通过 store 目录中的 index 子目录中的 indexFile 进行索引实现的快速查询。当然,这个
indexFile 中的索引数据是在包含了 key 的消息被发送到 Broker 时写入的。如果消息中没有包含 key,则不会写入。

二、索引条目结构

每个 Broker 中会包含一组 indexFile,每个 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 索引单元的数量之和)

indexFile 中最复杂的是 Slots 与 Indexes 间的关系。在实际存储时,Indexes 是在 Slots 后面的,但为了便于理解,将它们的关系展示为如下形式:

key 的 hash 值 % 500w 的结果即为 slot 槽位,然后将该 slot 值修改为该 index 索引单元的 indexNo,根据这个 indexNo 可以计算出该 index 单元在 indexFile
中的位置。不过,该取模结果的重复率是很高的,为了解决该问题,在每个 index 索引单元中增加了 preIndexNo,用于指定该 slot 中当前 index 索引单元的前一个 index 索引单元。而 slot 中始终存放的是其下最新的
index 索引单元的 indexNo,这样的话,只要找到了 slot 就可以找到其最新的 index 索引单元,而通过这个 index 索引单元就可以找到其之前的所有 index 索引单元。

indexNo 是一个在 indexFile 中的流水号,从 0 开始依次递增。即在一个 indexFile 中所有 indexNo 是 以此递增的。indexNo 在 index 索引单元中是没有体现的,其是通过 indexes 中依次数出来的。(可以认为是在indexes中的下标位置)

index 索引单元默写 20 个字节,其中存放着以下四个属性:

  • keyHash:消息中指定的业务 key 的 hash 值
  • phyOffset:当前 key 对应的消息在 commitlog 中的偏移量 commitlog offset
  • timeDiff:当前 key 对应消息的存储时间与当前 indexFile 创建时间的时间差
  • preIndexNo:当前 slot 下当前 index 索引单元的前一个 index 索引单元的 indexNo

三、indexFile 的创建

indexFile 的文件名为当前文件被创建时的时间戳。这个时间戳有什么用处呢?

根据业务 key 进行查询时,查询条件除了 key 之外,还需要指定一个要查询的时间戳,表示要查询不大于该时间戳的最新的消息,即查询指定时间戳之前存储的最新消息。这个时间戳文件名可以简化查询,提高查询效率。具体后面会详细讲解。

indexFile 文件是何时创建的?其创建的条件(时机)有两个:

  • 当第一条带 key 的消息发送来后,系统发现没有 indexFile,此时会创建第一个 indexFile 文件
  • 当一个 indexFile 中挂载的 index 索引单元数量超出 2000w 个时,会创建新的 indexFile。当带 key 的消息发送到来后,系统会找到最新的 indexFile,并从其 indexHeader 的最后 4
    字节中读取到 indexCount。若 indexCount >= 2000w 时,会创建新的 indexFile。

由于可以推算出,一个 indexFile 的最大大小是:(40 + 500w * 4 + 2000w * 20)字节

四、查询流程

当消费者通过业务 key 来查询相应的消息时,其需要经过一个相对较复杂的查询流程。不过,在分析查询流程之前,首先要清楚几个定位计算式子:

计算指定消息key的slot槽位序号:
slot槽位序号 = key的hash % 500w (式子1)

计算槽位序号为n的slot在indexFile中的起始位置:
slot(n)位置 = 40 + (n - 1) * 4 (式子2)

计算indexNo为m的index在indexFile中的位置:
index(m)位置 = 40 + 500w * 4 + (m - 1) * 20 (式子3)

40 为 indexFile 中 indexHeader 的字节数

500w * 4 是所有 slots 所占的字节数

具体查询流程如下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值