三: indexFile

除了通过通常的指定Topic进行消息消费外,RocketMQ还提供了根据key进行消息查询的功能。

该查询是通过store目录中的index子目录中的indexFile进行索引实现的快速查询。

这个indexFile中的索引数据是在如果包含了key的消息被生产者发送到Broker时写入的。

如果消息中没有包含key,则不会写入。

1. 索引条目结构

每个Broker中会包含一组indexFile,每个indexFile都是以一个时间戳命名的(这个indexFile被创建时 的时间戳)。

每个indexFile文件由三部分构成:indexHeader,slots槽位,indexes索引数据。

每个 indexFile文件中包含500w个slot槽。而每个slot槽又可能会挂载很多的index索引单元。

indexFile的文件结构如下:

其中slots中的每个slot槽挂载的index索引单元都来源于indexes区中

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索引单元。(如图所示,每个index索引单元都记录此slot的前一个索引单元)

而slot中始终存放的是其下最新的index索引单元的indexNo,这样的话,只要找到了slot就可以找到其最新的index索引单元,而通过这个index索引单元就可以依次找到其之前的所有 index索引单元。

slot记录的索引单元的indexNo是index索引单元在indexFile中的流水号,从0开始依次递增。即在一个indexFile中所有indexNo是 以此递增的。

indexNo在index索引单元中是没有维护的,其是通过indexes中依次数出来的。

index索引单元默写20个字节,主要存放某条消息key值和地址,其中存放着以下四个属性:

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

2 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)字节

3. 查询流程

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

式子1: 计算指定消息key的slot槽位序号:

​ slot槽位序号 = key的hash % 500w

式子2: 计算槽位序号为n的slot在indexFile中的起始位置:

​ slot(n)位置 = 40 + (n - 1) * 4

式子3: 计算indexNo为m的index在indexFile中的位置:

​ index(m)位置 = 40 + 500w * 4 + (m - 1) * 20

说明:

  • 40为indexFile中indexHeader的字节数
  • 500w * 4 是所有slots所占的字节数

具体查询流程如下:

这里解释一下为什么需要计算查询时间和文件创建时间的差值, 并和 index 索引单元的timeDiff值做比较,

这两个值都是记录的和indexFile文件创建时间的差值,

所以如果 index 索引单元的timeDiff大于查询时间的timeDiff,说明此index索引单元在需要查询的时间之后创建的,即不满足需要查询的时间条件

RocketMQ(3) 根据消息key查询功能的实现: indexFile的更多相关文章

  1. 深入剖析 RocketMQ 源码 - 消息存储模块

    一.简介 RocketMQ 是阿里巴巴开源的分布式消息中间件,它借鉴了 Kafka 实现,支持消息订阅与发布.顺序消息.事务消息.定时消息.消息回溯.死信队列等功能.RocketMQ 架构上主要分为四 ...

  2. 精华推荐 | 【深入浅出RocketMQ原理及实战】「性能原理挖掘系列」透彻剖析贯穿RocketMQ的事务性消息的底层原理并在分析其实际开发场景

    什么是事务消息 事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败.RocketMQ的事务消息提供类似 X/Open ...

  3. RocketMQ支持事务消息机制

    事务消费 我们经常支付宝转账余额宝,这是日常生活的一件普通小事,但是我们思考支付宝扣除转账的钱之后,如果系统挂掉怎么办,这时余额宝账户并没有增加相应的金额,数据就会出现不一致状况了. 上述场景在各个类 ...

  4. Springboot+Vue实现仿百度搜索自动提示框匹配查询功能

    案例功能效果图 前端初始页面 输入搜索信息页面 点击查询结果页面 环境介绍 前端:vue 后端:springboot jdk:1.8及以上 数据库:mysql 核心代码介绍 TypeCtrler .j ...

  5. 阿里云RocketMQ定时/延迟消息队列实现

    新的阅读体验:http://www.zhouhong.icu/post/157 一.业务需求 需要实现一个提前二十分钟通知用户去做某件事的一个业务,拿到这个业务首先想到的最简单得方法就是使用Redis ...

  6. Sharepoint学习笔记—ECM系列—文档列表的Metedata Navigation与Key Filter功能的实现

    如果一个文档列表中存放了成百上千的文档,想要快速的找到你想要的还真不是件容易的事,Sharepoint提供了Metedata Navigation与Key Filter功能可以帮助我们快速的过滤和定位 ...

  7. RPM软件包管理的查询功能

    以后大家升级rpm包的时候,不要用Uvh了! 我推荐用Fvh 前者会把没有安装过得包也给装上,后者只会更新已经安装的包   总结:未安装的加上小写p,已安装的不需要加p   查询q    rpm {- ...

  8. java 模拟消息的发送功能

    import java.util.HashMap; import java.util.Iterator; import java.util.Map; /* * 完成消息的发送功能 * 在发送消息之前, ...

  9. 【百度地图API】小学生找哥哥——小学生没钱打车,所以此为公交查询功能

    原文:[百度地图API]小学生找哥哥--小学生没钱打车,所以此为公交查询功能 任务描述: 有位在魏公村附近上小学的小朋友,要去北京邮电大学找哥哥.他身上钱很少,只够坐公交的.所以,百度地图API快帮帮 ...

  10. 拾人牙慧篇之——基于HTML5中websocket来实现消息推送功能

    一.写在前面 要求做一个,后台发布信息,前台能即时得到通知的消息推送功能.网上搜了也有很多方式,ajax的定时询问,Comet方式,Server-Sent方式,以及websocket.表示除了定时询问 ...

随机推荐

  1. 详解Promise.race()可以解决多个异步请求那个请求先返回

    Promise.race([]);接受一个参数,由promise组成的一个数组: 它的返回结果是promise对象: 它的结果和状态由什么去决定呢? 由第一个改变Promise状态的对象去决定:若是返 ...

  2. .net web发布至阿里云服务器

    1.发 布网站第一步:右键网站主项目,选择 发布网站.如下图 第二步 填写发布网站的相关配置,选择配置文件,新建配置文件 第三步 选择发布的文件存放的位置 第四步,选择Release 再点击下一步,点 ...

  3. Fabric升级示例

    Fabric v1.4.x升级至v2.2.0 本文首发于这里,转载请注明出处. 以fabric-samples v1.4.8为例,将v1.4.8升级至v2.2.0.注意,所有节点以滚动的方式进行升级, ...

  4. windowsbat删除命令

    widnwosbat命令 DEL /F /A /Q \?%1 用于删除指定路径下的文件,参数含义如下: /F: Force delete,即强制删除: /A: 用于指定文件属性,A代表存档,D代表目录 ...

  5. postman测试Integer[]数组

    背景说明:在做批量删除列表数据的时候,前端发送数组格式给后端,后端使用数组格式(Integer[] ids)接受,需要使用postman测试结果. @ApiOperation("管理系统-删 ...

  6. Python 实现ARP扫描与欺骗

    ARP欺骗又称ARP毒化或ARP攻击,是针对以太网地址解析协议ARP的一种攻击技术,通过欺骗局域网内访问者PC的网关MAC地址,使访问者PC错以为攻击者更改后的MAC地址是网关的MAC,导致网络不通. ...

  7. sed文本处理工具常见用法

    sed的全称是stream editor, 表示它是一个流编译器.可以处理文本内容和终端命令的流标准输出,对文本做查找,替换,插入,删除操作. 它是把文件中的内容逐行copy到缓冲区,然后在缓冲区中进 ...

  8. 你天天用4G 这些基本常识都知道吗?

    不少朋友在选购4G智能手机的时候,经常可能会遇到这样的名词,五模十三频.五模十七频.双4G.移动4G.联通4G.那这些名词到底是什么意思呢?它们之间又有什么区别呢? 其实上面的这些说法其实都是比较具有 ...

  9. iSCSI的客户端messages频繁报错问题解决

    问题现象: 在自己的工作站中安装的RAC测试环境,使用了iSCSI模拟共享存储,环境运行OK,但是在messages信息中频繁报错如下: [root@db01rac2 ~]# tail -20f /v ...

  10. Go语言核心36讲(Go语言实战与应用十)--学习笔记

    32 | context.Context类型 我们在上篇文章中讲到了sync.WaitGroup类型:一个可以帮我们实现一对多 goroutine 协作流程的同步工具. 在使用WaitGroup值的时 ...