HFile索引结构根据索引层级不同分为2种:Single-Level 和 Multi-Level。前者表示单级索引,后者表示多级索引,一般分为2级或者3级。之所以HFile v2引入多级索引是因为,随着HFile文件越来越大,Data Block越来越多,索引数据也越来越多,大到已经无法全部加载到内存,而多级索引可以只是加载部分索引,降低内存的使用空间。

Index Block分为2种:Root Index Block和 Non-Root Index Block.

Non-Root Index Block又分为Intermediate Index Block和Leaf Index

Block2种。HFile中索引结构类似于一棵树,Root Index Block表示索引数据根节点,Intermediate Index Block表示中间节点,Leaf Index Block表示叶子节点,叶子结点直接指向实际数据块。

对于Data Block,由于HFile刚开始数据量比较小,采用single-level结构,只有root index 一级索引,直接指向数据块。当数据量慢慢变大时,root index block满了之后,索引就会变成multi-level结构,由一级索引变成两级索引,根节点指向叶子节点,叶子结点指向实际数据块。如果数据量在变大,索引就会变成三级索引。

我们来着重分析Index Block结构:

一 Root Index Block

Root Index Block表示索引树根节点索引块,可以作为Bloom Block的直接索引,也可以作为Data Block索引的根索引。在Single-Level和Multi-Level中两种索引结构对应的Root Index Block稍有差异,如图示:

Index Entry: 表示具体的索引对象,每一个索引由BlockOffset,BlockDataSize,BlockKey三个字段组成。

# BlockOffset: 指的是当前索引指向数据块的偏移量

# BlockDataSize: 指的是索引指向的数据块在磁盘上的大小

# BlockKey: 指的是索引指向的数据块中的第一个key

如果在Multi-Level还有MidKey相关信息:

MidKey表示HFile中所有Data Block中中间的一个Data Block,用于对HFile进行split操作,快速定位HFile中间的位置。

Root Index Block会在HFile解析的时候,直接加载进内存,我们知道Trailer Block中有一个字段为dataIndexCount,就表示此处Index Entry个数。因为Index Entry并不定长,只有知道Entry的个数才能正确将所有Index Entry加载进内存。

二 Non-Root Index Block

当HFile越来越大的时候,Single-Level结构的索引,已经不足以支撑所有数据都加载到内存,需要分化为Multi-Level结构。Multi-Level结构中,Non-Root Index Block可作为中间节点,也可以直接作为叶子节点,他们都拥有相同的结构:

和Root Index Block相比,Non-Root Index Block也有Index Entry,用于指向叶子节点或者实际的数据块。对于Intermediate Index Block就是指向叶子节点,对于Leaf Index Block就是指向实际的数据块。但是Non-Root Index Block多了EntryOffset 和 numEntires

numEntires: 记录entry的数量

EntryOffset: 是Non-Root Index Block内部索引字段,表示Index Entry在该block中的相对偏移量,相对于第一个Index Entry,用于实现Block内部的二分查找,故针对Non-Root Index Block,在其内部定位一个key的具体索引,不是通过遍历而是通过二分查找实现,可以更加高效快速定位到待查找的key

三 索引的分裂

我们知道,数据量少的时候,文件小的时候,只需要一个Root Index

Block 就可以完成索引,即索引树只有一级。但是当数据不断写入的的时候,文件变大之后,索引数据也会相应变大,索引结构就会由Single-Level转化为Multi-Level,这期间会涉及到索引块写入和分裂,我们就分析一下数据写入是如何引起索引分裂的?

我们知道MemStore的flush主要分为三个阶段:

第一阶段:将MemStore的KeyValue数据进行snapshot

第二阶段: 再将这部分数据flush到HFile,并生成临时目录

第三阶段: 将临时文件移动到指定的Column Family目录下

在flush阶段又可以具体分为两个阶段:

Append阶段:MemStore中的KeyValue首先会写入到HFile中的数据块

# 预检查: 检查key的大小是否大于前一个key,如果大于则不符合HBase顺序排列,抛出异常;检查value是否为null,如果为null也会抛出异常

# block是否写满:检查当前Data Block是否已经写满,如果没有则直接写入KeyValue;否则需要执行数据块写入磁盘以及索引块修改操作

# 数据块落盘并修改索引: 如果Data Block已满,首先将block写入流;再生成一个Leaf Index Entry,写入Leaf Index Block;再检查该Leaf Index Block是否已经写满需要落盘,如果已经写满,就将该Leaf Index Block写入输出流,并且为索引树根节点Root Index Block新增一个索引,指向叶子节点

# 生成一个新的block:reset 输出流,初始化startOffset = -1

# 写入KeyValue: 将KeyVlaue以流的方式写入输出流,同时需要写入memstoreTS,除此之外,如果该key是第一个key,还要赋值给变量firstKeyInBlock

Finalized阶段: 修改HFile中meta元数据,索引块数据以及Trailer数据块

当数据落盘并修改索引会使得Root Index 不断增多,当增大到一定程度之后就需要分裂。

根节点索引指向叶子节点索引块。finalize阶段系统会对Root Index Block进行大小检查,如果大小大于规定的大小就需要进行分裂,图中分裂过程实际上就是将原来的Root Index Block块分割成4块,每块独立形成中间节点InterMediate Index Block,系统再重新生成一个Root Index Block(图中红色部分),分别指向分割形成的4个interMediate Index Block。此时索引结构就变成了third-level结构。

四HFile数据完整索引流程

了解了HFile中数据索引块的两种结构之后,就来看看如何使用这些索引数据块进行数据的高效检索。整个索引体系类似于MySQL的B+树结构,但是又有所不同,比B+树简单,并没有复杂的分裂操作。具体见下图所示:

图中上面三层为索引层,在数据量不大的时候只有最上面一层,数据量大了之后开始分裂为多层,最多三层,如图所示。最下面一层为数据层,存储用户的实际keyvalue数据。这个索引树结构类似于InnoSQL的聚集索引,只是HBase并没有辅助索引的概念。

图中红线表示一次查询的索引过程(HBase中相关类为HFileBlockIndex和HFileReaderV2),基本流程可以表示为:

1. 用户输入rowkey为fb,在root index block中通过二分查找定位到fb在’a’和’m’之间,因此需要访问索引’a’指向的中间节点。因为root index block常驻内存,所以这个过程很快。

2. 将索引’a’指向的中间节点索引块加载到内存,然后通过二分查找定位到fb在index ‘d’和’h’之间,接下来访问索引’d’指向的叶子节点。

3. 同理,将索引’d’指向的中间节点索引块加载到内存,一样通过二分查找定位找到fb在index ‘f’和’g’之间,最后需要访问索引’f’指向的数据块节点。

4. 将索引’f’指向的数据块加载到内存,通过遍历的方式找到对应的keyvalue。

上述流程中因为中间节点、叶子节点和数据块都需要加载到内存,所以io次数正常为3次。但是实际上HBase为block提供了缓存机制,可以将频繁使用的block缓存在内存中,可以进一步加快实际读取过程。所以,在HBase中,通常一次随机读请求最多会产生3次io,如果数据量小(只有一层索引),数据已经缓存到了内存,就不会产生io。

HBase之HFile索引机制相关推荐

  1. HBase与时空索引技术

    title: HBase与时空索引技术 date: 2021-05-13 10:04:05 tags: HBase GIS 所谓时空数据,顾名思义,包含了两个维度的信息:空间信息与时间信息.空间信息, ...

  2. Hbase的二级索引和RowKey的设计

    Hbase查询简介 Hbase查询的时候,有以下几种方式: • 通过 rowkey方式,指定 获取唯一记录 • 通过 scan方式,设置satrtRow 和stopRow 参数进行范围匹配(模糊查询) ...

  3. 面试官问:为什么MySQL的索引不采用Kafka的索引机制

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 第一眼看到这个问题,也是很迷惑的,谁没事会问这种问题.然而,事实上 ...

  4. 深入 Lucene 索引机制

    简介: Lucene 是一个基于 Java 的全文检索工具包,你可以利用它来为你的应用程序加入索引和检索功能.Lucene 目前是著名的 Apache Jakarta 家族中的一个开源项目,下面我们即 ...

  5. delphi报列表索引越界怎么处理_图解Elasticsearch索引机制,此篇带你领悟新世界...

    前言 随着Elastic的上市,ELK不仅在互联网大公司得到长足的发展,而且在各个中小公司都得到非常广泛的应用,甚至连"婚庆网站"都开始使用Elasticsearch了.随之而来的 ...

  6. 百度新闻的索引机制(二):智能聚类

    百度新闻的索引机制(二):智能聚类 http://net.chinabyte.com/377/2520877.shtml 转载于:https://www.cnblogs.com/cy163/archi ...

  7. 解决问题的反馈机制_谈谈HBase中的Nonce机制

    最近在读hbase源码关于rpc的一些实现细节,想正好趁此机会和大家分享一下我理解到的hbase关于Nonce机制的实现. Nonce机制的来源 Nonce这个词由来已久,且在各个领域都会有相对应的名 ...

  8. mysql索引机制_mysql索引原理详解

    预备知识 什么是索引? 上一篇中有详细的介绍,可以过去看一下:什么是索引? 索引的本质:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机 ...

  9. db2 删除索引_程序员必须了解的知识点——你搞懂mysql索引机制了吗?

    一.索引是什么 MySQL官方对索引的定义为:索引(Index)是帮助MySQL 高效 获取数据的数据结构,而MYSQL使用的数据结构是: B+树 在这里推荐大家看一本书, <深入理解计算机系统 ...

最新文章

  1. oracle logminer全解析
  2. java 找不到mysql驱动_java lib目录添加了mysql驱动包,仍然找不到class??
  3. oracle触发器 select into,Oracle触发器中selectinto报错no_data_found异常处理
  4. Tensorflow实例3: 验证码图片的识别训练,每张图片有4个字母
  5. 大文件分片上传前端框架_基于Node.js的大文件分片上传
  6. try catch finally 中包含return的几种情况,及返回结果
  7. Windows 2008 R2 SP1部署Lync2010企业版(一)
  8. matlab求微分方程的系数,Matlab中系数为离散值的微分方程求解【编辑完成求解答】...
  9. 他回国后对学生说,玩会这12个游戏就能掌握python基础,其实不难
  10. GitHub in vs2010、vs2013
  11. 医学图像分析相关的会议
  12. Node.js 初步学习总结
  13. 2019web前端全新面试题库 一
  14. 【Oracle】手工建库
  15. POJ-1163(DP,Water)
  16. 北京自贸区国际商务服务片区挂牌 总面积48平方公里
  17. 【ffmpeg】视频解码器
  18. 如何将Nios II硬件和软件合成一个文件(NIOS II)烧进EPCS falsh
  19. QA问答系统中的深度学习技术实现
  20. python软著申请_软著申请流程时间

热门文章

  1. 雷凌linux车机升级_绿老师学堂:15万合资车谁更“聪明”?体验思域/福克斯/雷凌车机...
  2. java aio socket_[Java]socket Aio demo
  3. pdo mysql连接类_PHP PDO-MYSQL:如何在不同类之间使用数据库连接
  4. android+动画完成后不可点击,动画后,TranslateAnimated ImageView无法点击[Android]
  5. linux快捷键如dd,Linux的150个命令和快捷键 整理
  6. oracle数据库11g完全卸载,oracle 11g完全卸载
  7. sitescope 监控mysql_LoadRunner通过SiteScope监控MySQL的性能
  8. Endnote自定义参考文献格式锦集
  9. c语言sizeof(test),解析C语言中的sizeof
  10. html显示日志_如何实现类似“jenkins”的滚动日志功能?