进阶篇 RocketMQ 原理之key查询

进阶篇 RocketMQ 原理之key查询

凡是自强不息者,最终都会成功 —— 歌德

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战

indexFile

       除了通过通常的指定Topic进行消息消费外,RocketMQ还提供了根据key或者时间区间进行消息查询的功能。该查询是通过store目录中的index子目录中的indexFile进行索引实现的快速查询。当然,这个indexFile中的索引数据是在包含了key的消息被发送到Broker时写入的。如果消息中没有包含key,则不会写入,固定的单个IndexFile文件大小约为400M,一个IndexFile可以保存 2000W个索引,IndexFile的底层存储设计为在文件系统中实现HashMap结构,故rocketmq的索引文件其底层实现为hash索引。

存储位置

      $HOME\store\index${fileName},名字是时间戳命名的 image.png

索引条目结构

      每个Broker中会包含一组indexFile,每个indexFile都是以一个时间戳命名的(这个indexFile被创建时的时间戳)。每个indexFile文件由三部分构成:indexHeader,slots槽位,indexes索引数据。每个indexFile文件中包含500w个slot槽,每个slot槽含有4个字节。而每个slot槽又可能会挂载很多的index索引单元,每个索引单元20个字节
      所以总大小是:indexHeader的size + (slots的size)500w + (索引单元的size) * 2000w = 40 + 4 * 500w + 202000w = 420000040个字节大小 = 400M image.png

indexHeader

indexHeader固定40个字节,其中存放着如下数据: image.png

  1. beginTimestamp:该indexFile中第一条消息的存储时间
  2. endTimestamp:该indexFile中最后一条消息存储时间
  3. beginPhyoffset:该indexFile中第一条消息在commitlog中的偏移量commitlog offset
  4. endPhyoffset:该indexFile中最后一条消息在commitlog中的偏移量commitlog offset
  5. hashSlotCount:已经填充有index的slot数量(并不是每个slot槽下都挂载有index索引单元,这里统计的是所有挂载了index索引单元的slot槽的数量)
  6. indexCount:该indexFile中包含的索引单元个数(统计出当前indexFile中所有slot槽下挂载的所有index索引单元的数量之和)

Slots 与indexes关系

逻辑存储
      indexFile中最复杂的是Slots与Indexes间的关系。在实际存储时,Indexes是在Slots后面的,但为了便于理解,将它们的关系展示为如下形式: image.png       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中依次数出来的。 物理存储 image.png

索引单元

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

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

按照Message Key查询消息

      按照Message Key查询消息,主要是基于RocketMQ的IndexFile索引文件来实现的。RocketMQ的索引文件逻辑结构,类似JDK中HashMap的实现。索引文件的具体结构如下: image.png       IndexFile索引文件为用户提供通过“按照Message Key查询消息”的消息索引查询服务,IndexFile文件的存储位置是:$HOME\store\index${fileName},文件名fileName是以创建时的时间戳命名的,文件大小是固定的,等于40+500W4+2000W20= 420000040个字节大小。如果消息的properties中设置了UNIQ_KEY这个属性,就用 topic + “#” + UNIQ_KEY的value作为 key 来做写入操作。如果消息设置了KEYS属性(多个KEY以空格分隔),也会用 topic + “#” + KEY 来做索引。

Guess you like

Origin juejin.im/post/7068808709254119431