深入理解HBASE(4)HFile

简介

1)HFile由DataBlock、Meta信息(Index、BloomFilter)、Info等信息组成。

2)整个DataBlock由一个或者多个KeyValue组成。

3)在文件内按照Key排序。

HFile 组织形式

这里只介绍V2版本的,HFileV1的数据格式在0.92版本升级到V2版本。

深入理解HBASE(4)HFile_第1张图片
官方介绍的V2

1)文件分为三部分:Scanned block section,Non-scanned block section,以及Opening-time data section

Scanned block section:表示顺序扫描HFile时(包含所有需要被读取的数据)所有的数据块将会被读取,包括Leaf Index Block和Bloom Block;

Non-scanned block section:HFile顺序扫描的时候该部分数据不会被读取,主要包括Meta Block即BloomFilter和Intermediate Level Data Index Blocks两部分;

Load-on-open-section:这部分数据在HBase的region server启动时,需要加载到内存中。包括FileInfo、Bloom filter block、data block index和meta block index;

Trailer:这部分主要记录了HFile的基本信息、各个部分的偏移值和寻址信息。

  1. 为DataBlockIndex建立多层索引。DataBlockIndex分为Leaf Index Block、Root Data Index(或者multi Root Data index(紫色的Meta Index区域)),

Leaf index block具体存储了DataBlock的offset、length、以及firstkey的信息。

RootDataIndex 存储的是每个Leaf index block的offset、length、Leaf index Block记录的第一个key,以及截至到该Leaf Index Block记录的DataBlock的个数。

假定DataBlock的个数足够多,HFile文件又足够大的情况下,默认的128KB的长度的ROOTDataIndex仍然存在超过chunk大小的情况时,会分成更多的层次。这样最终的可能是ROOT INDEX –> IntermediateLevel ROOT INDEX(可以是多层) —〉Leaf index block

在ROOT INDEX中会记录Mid Key所对应的信息,帮助在做File Split或者折半查询时快速定位中间Row的信息。

写HFile

HFile V2的写操作流程:

1)Append KV到 Data Block。在每次Append之前,首先检查当前DataBlock的大小是否超过了默认的设置,如果不超出阈值,写入输出流。如果超出了阈值,则执行finishBlock(),按照Table-CF的设置,对DataBlock进行编码和压缩,然后写入HFile中。//以Block为单位进行编码和压缩,会有一些性能开销,可以参考HBase实战系列1—压缩与编码技术

2)根据数据的规模,写入Leaf index block和Bloom block。

Leaf index Block,每次Flush一个DataBlock会在该Block上添加一条记录,并判断该Block的大小是否超过阈值(默认128KB),超出阈值的情况下,会在DataBlock之后写入一个Leaf index block。对应的控制类:HFileBlockIndex,内置了BlockIndexChunk、BlockIndexReader和BlockIndexWriter(实现了InlineBlockWriter接口)。

Bloom Block设置:默认使用MURMUR hash策略,每个Block的默认大小为128KB,每个BloomBlock可以接收的Key的个数通过如下的公式计算,接收的key的个数 与block的容量以及errorRate的之间存在一定的关系,如下的计算公式中,可以得到在系统默认的情况下,每个BloomBlock可以接纳109396个Key。

注意:影响BloomBlock个数的因素,显然受到HFile内KeyValue个数、errorRate、以及BlockSize大小的影响。可以根据应用的需求合理调整相关控制参数。

每一个BloomBlock会对应index信息,存储在Meta Index区域。

这样在加载数据的时候,只需加载不超过128KB的RootDataIndex以及IntermediateLevelRootIndex,而避免加载如HFile V1的所有的Leaf index block信息,同样,也只需要加载BloomBlockIndex信息到内存,这样避免在HFile V1格式因为加载过大的DataBlockIndex造成的开销,加快Region的加载速度。

读HFile

在HFile中根据一个key搜索一个data的过程:

1、先内存中对HFile的root index进行二分查找。如果支持多级索引的话,则定位到的是leaf/intermediate index,如果是单级索引,则定位到的是data block

2、如果支持多级索引,则会从缓存/hdfs(分布式文件系统)中读取leaf/intermediate index chunk,在leaf/intermediate chunk根据key值进行二分查找(leaf/intermediate index chunk支持二分查找),找到对应的data block。

3、从缓存/hdfs中读取data block

4、在data block中遍历查找key。

读取HFile

1、 首先读取文件尾的4字节Version信息(FileTrailer的version字段)。

2、 根据Version信息得到Trailer的长度(不同版本有不同的长度),然后根据trailer长度,加载FileTrailer。

3、 加载load-on-open部分到内存中,起始的文件偏移地址是trailer中的loadOnOpenDataOffset,load-on-open部分长度等于(HFile文件长度 - HFileTrailer长度)

Load-on-open各个部分的加载顺序如下:

依次加载各部分的HFileBlock(load-on-open所有部分都是以HFileBlock格式存储):data index block、meta index block、FileInfo block、generate bloom filter index、和delete bloom filter。HFileBlock的格式会在下面介绍。

HFile Block

在hfile中,所有的索引和数据都是以HFileBlock的格式存在在hdfs中,

HFile version2的Block格式如下两图所示,有两种类型,第一种类型是没有checksum;第二种是包含checksum。对于block,下图中的绿色和浅绿色的内存是block header;深红部分是block data;粉红部分是checksum。

第一种block的header长度= 8 + 2 * 4 + 8;

第二种block的header长度=8 + 2 * 4 + 8 + 1 + 4 * 2;

深入理解HBASE(4)HFile_第2张图片
Block结构

BlockType:8个字节的magic,表示不同的block 类型。

CompressedBlockSize:表示压缩的block 数据大小(也就是在HDFS中的HFileBlock数据长度),不包括header长度。

UncompressedBlockSize:表示未经压缩的block数据大小,不包括header长度。

PreBlockOffset:前一个block的在hfile中的偏移地址;用于访问前一个block而不用跳到前一个block中,实现类似于链表的功能。

CheckSumType:在支持block checksum中,表示checksum的类型。

bytePerCheckSum:在支持checksum的block中,记录了在checksumChunk中的字节数;records the number of bytes in a checksum chunk。

SizeDataOnDisk:在支持checksum的block中,记录了block在disk中的数据大小,不包括checksumChunk。

DataBlock

DataBlock是用于存储具体kv数据的block,相对于索引和meta(这里的meta是指bloom filter)DataBlock的格式比较简单。

在DataBlock中,KeyValue的分布如下图,在KeyValue后面跟一个timestamp。

深入理解HBASE(4)HFile_第3张图片
DataBlock结构

HFile Index

HFile中的index level是不固定的,根据不同的数据类型和数据大小有不同的选择,主要有两类,一类是single-level(单级索引),另一类是multi-level(多级索引,索引block无法在内存中存放,所以采用多级索引)。

HFile中的index chunk有两大类,分别是root index chunk、nonRoot index chunk。而nonRoot index chunk又分为interMetadiate index chunk和leaf index chunk,但intermetadiate index chunk和leaf index chunk在内存中的分布是一样的。

对于meta block和bloom block,采用的索引是single-level形式,采用single-level时,只用root index chunk来保存指向block的索引信息(root_index-->xxx_block)。

而对于data,当HFile的data block数量较少时,采用的是single level(root_index-->data_block)。当data block数量较多时,采用的是multi-level,一般情况下是两级索引,使用root index chunk和leaf index chunk来保存索引信息(root_index-->leaf_index-->data_block);但当data block数量很多时,采用的是三级索引,使用root index chunk、intermetadiate index chunk和leaf index chunk来保存指向数据的索引(root_index-->intermediate_index-->leaf_index-->data_block)。

所有的index chunk都是以HFileBlock格式进行存放的,首先是一个HFileBlock Header,然后才是index chunk的内容。

Root Index

Root index适用于两种情况:

1、作为data索引的根索引。

2、作为meta和bloom的索引。

在Hfile Version2中,Meta index和bloom index都是single-level,也都采用root索引的格式。Data index可以single-level和multi-level的这形式。Root index可以表示single-level index也可以表示multi-level的first level。但这两种表示方式在内存中的存储方式是由一定差别,见图。

深入理解HBASE(4)HFile_第4张图片
multi-level结构图

对于multi-level root index,除了上面index entry数组之外还带有格外的数据mid-key的信息,这个mid-key是用于在对hfile进行split时,快速定位HFile的中间位置所使用。Multi-level root index在硬盘中的格式见图3.4。

Mid-key的信息组成如下:

1、Offset:所在的leaf index chunk的起始偏移量

2、On-disk size:所在的leaf index chunk的长度

3、Key:在leaf index chunk中的位置。

深入理解HBASE(4)HFile_第5张图片
查找路径

你可能感兴趣的:(深入理解HBASE(4)HFile)