HBase源码分析6—HFile剖析

11. 3 月 2018 hbase, 数据库 0

上一篇中我们介绍了一下BloomFilter的相关内容,这部分内容对于我们理解HFile的结构很重要(其实也没那么重要,跳过不看就是了= =||)。这一篇我们就来针对HFile下手,研究下他的结构究竟是什么样的。

历史

HFile一共经历了三个版本的变迁。我们有必要先了解下每次修改的缘由。

(在HFile出现前还有基于MapFile的解决方案,因为当时并没有HFile这个东西,就不提了。Compaction和标记删除就是那个时候出现的。)

V1

JIRA(HBASE-61)上看,HFile的出现似乎是为了挖掘潜在的性能优化能力。在V1中,data和index保存在同一个文件中,支持保存metadata(如BloomFilter),FileInfo用于保存合并等场景需要的文件信息。

图片来自hbase.apache.org

V2

随着数据量的变大,V1的缺点也逐渐暴露出来:每个HFile中的索引等信息必须全部加载到内存中,这些数据有时会很大。在V2中主要引入了多级索引,不需要把所有索引加载到内存、块级索引等。

在这个图中:

  • Scanned Block Section:顺序扫描时使用的块,包括了data block、leaf index block、bloom block
  • Non-Scanned Block Section:顺序扫描时不使用的块,包括了meta block、intermediate data block等
  • Load-on-Open Section:启动时需要被加载到内存的块,包括root data index、meta index、file info等
  • Trailer:记录HFile基本信息和上面三个块的偏移量等信息

Block

HFileBlock

所有的块(跟data block同级的这些)都继承自HFileBlock(位置在 main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java ),结构如下图

BlockType 表示了这个块的类型。HBase提供了以下几种类型( MagicStr 就是实际填在 BlockType 位置的数据)

BlockType 这个类里还定义了一些基本的读写操作,比较简单不列举了。

HFile是如何被读的呢?可以看同一个包下 HFileReaderV2.java ,在构造的时候有一个循环

追踪 readBlock 这个函数可以追到 HFileBlock.java 中的 readBlockDataInternal ,比较简单,先读header,然后根据长度建一个新的buffer,把header拷贝过去,再把data读到buffer的后面。但是上面这个函数里block搞出来也没有下一步动作,其实是都整个被缓存起来了。代码在 readBlock函数中