HBase的存储架构图:
一些存储相关的一些概念:
HBase中的一张表称为一张Table,由于Table太大,所以Table会按行进行切分然后分配到集群的各个节点上,每一个节点称为一个RegionServer。切分的每一部分称为一个HRegion,HRegion是逻辑上的一个单元。
一个HRegion包括了Table的一部分行,而一行又可以有多个Column Family(以下简称CF),所以每一个CF的数据被存储在一个Store里面,即一个Store代表了一个Region中的一个CF的数据,它也是一个逻辑结构。
每一个Store又由一个MemStore和多个StoreFile组成。为什么有MenStore和这么多个StoreFile是因为不可能每次来一条数据就刷新一次到磁盘,频繁写磁盘会造成效率不高且数据不连续。所以一般是在内存中将数据缓存到一定量,然后在一口气flush到磁盘。每次flush会将内存中的数据flush到磁盘,但是内存中会存储多个CF的数据,所以一次flush会生成多个StoreFile,并且有些StoreFile可能很小。
(这就是为什么要求HBase的CF不能设置太多,太多的话会频繁刷新磁盘,而且小文件会触发耗时的Compact操作)
读多个HFile怎么保证有序:
因为HBase底层存储结构可以不是Hadoop,所以HFile是HBase数据存储在Hadoop上才有的概念,上面引进StoreFile就是由于这个原因对底层存储文件做的一次封装。
注意,从上面的flush()逻辑可以看出,一个StoreFile内元素的顺序是保证有序的,两个StoreFile数据的有序性就无法保证了!举个例子,一开始写入的数据是2,3,4然后生成一个StoreFile,接着又写入了1,5,6,又生成了一个StoreFile。(所以这样的话读数据是怎么保证连续性的?这个我们后面分析读数据的流程的源码再说)
获取数据的流程:
注意:如果数据可以在BlockCache或者MemStore中获取到,那么就不会读HFile了
BlockCache > MemStore > HFile
我们再来聊聊HFile,看看文件里面到底存了哪些东西,从官网上的附录可知,HFile的文件格式一共存在三个版本:
HFile V1:(0.94版本中被移除)
布隆过滤器的作用是告诉你某样东西一定不存在或者可能存在。可能存在是因为是布隆过滤器不支持删除操作。如果某个值之前存在后来被删除了,但是在bloom filter中的信息还是有的,所以说是可能存在。官网上说到:Large Bloom filters produce a different performance problem: the first get request that requires a Bloom filter lookup will incur the latency of loading the entire Bloom filter bit array。也就是说bloom filter是给get请求(随机读)用的。
寻找数据的时候,先通过Trailer寻找到File Info/Data Index/Meta Index,然后再通过Data Index和Meta Index又能找到对应的数据块和元数据块。
Data结构解析:
HBase一行包含了多个CF,每个CF又包含了多个column,每个Column是一个cell,也就是一个key/value对,key就是rowKey,即每个Cell都会保存rowKey的信息。TimeStamp是记录数据入库的时间,存储的是时间戳。KeyType是key的类型,Type分为Put、Delete、DeleteColumn、DeleteFamily。如果只修改一行中的某一列的话,找起来是怎么找的?其他列会put进空么?
HFile V1为什么被弃用:
HFile V1版本被弃用是因为它在运行中占用的内存过多,并且Bloom File和Block Index会变的很大导致启动时间变长:
每次查询需要加载并查询Bloom Filter,如果这个文件很大会引起查询很大的延迟。Bloom Filter可达到100M。
Block Index是在启动时候由RegionServer加载的,如果这个过大,会增加启动时间并占用很大一部分的内存。(可能增长到6G…所以V2中引入了多级索引的概念,只加载部分索引)
并且官网上说,由于HFile是low-level的文件,不应该和业务关联的太紧密,类似Bloom filter之类的应该放在StoreFile级别去做。所以HFiler又设计了V2版本。
HFile V2:(0.92版本中引入)
逻辑结构:
我们逐个部分进行解析。
Trailer:
看下它的PB文件,记录的是HFile中各个部分的基本信息。
Load-on-open-section:
这部分数据是RegionServer启动时候加载到内存中去的,所有StoreFile都要。包括了Root Data Index(根索引)、Meta Index、FileInfo以及Bloom Filter的metadata。
Non-scanned block section:
元数据的block部分,主要存放meta信息,即BloomFilter,还有DataBlock的第二层索引(枝索引,可以没有)。Scan的时候数据不会被读取,侧面说明了BloomFilter是给Get用的。
Scanned block section:
真实存储数据block部分,Scan的时候所有的数据块将会被读取。(还有叶索引,可以没有)
Data Index结构:
HBase的数据索引是分成三层的结构:
Root Data Index -> intermediate Index -> leaf Index
Root必须有,这部分前面说过是启动的时候加载到内存中去的。数据在多的时候增加leaf Index层,再多的时候中间再增加一层intermediate Index。它们的大小通过如下参数控制,过多则分裂成两个Block。
索引的结构类似B+树(其实Bloom Block也有索引)。所以一次请求最坏的情况下会有三次I/O操作,因为Root是在磁盘里面的,所以这一次是没有的,HBase的cache Block可以将一些Block缓存在内存中,减少IO操作。
物理结构:
一个HFile会被切分为多个Block块,块大小是由创建表的时候参数BLOCKSIZE => ‘65536’指定的,默认是64KB,书上建议是设置8KB-1M之间。
如果应用程序主要是顺序访问(Scan),那么将块设置的大一点,但是这样会降低随机访问(Get)的效率。但是块过多的话,也需要更多的内存来索引块,并且频繁刷写还会降低效率。
不是所有的部分都有Block,Block一共有8种类型,如下所示:
每个Block又分为Block Head和Block Data,前者存储Block的元数据信息,后者用于存放真实的数据。
一些补充的点:
Bloom Filter的作用:
之前提到过,Bloom Fiter对于Get这种随机读写的操作非常重要,它可以帮助Get以及部分Scan剔除不会用到的HFile文件,减少I/O以提高性能。
Bloom Filter原理是,当一个元素被加入集合时,通过K个Hash函数将这个元素映射称为一个位阵列(Bit Array)中的K个点,将这些点置为1。检索时,如果这些点是不是都1就知道集合中有没有它。(因为不支持删除,所以不一定存在,但是可以判断肯定不存在)
HBase的Get就是用如上的方式判断rowKey是否存在某个HFile里面,不存在就不加载。
假设没有Bloom Filter,Get是怎么获取到一条数据的:
因为Get可以设置rowKey、timestamp、family、qualifier,HBase会根据这些信息来过滤那些不含有数据的StoreFile和MemStore。这个时候如果还有多个HFile,那就要排排队逐个的去找了。
storeFile是内部有序的,但多个StoreFile之间是无序的。所以多个StoreFile会进行排队,按照rowKey和column升序,timestamp降序的方式排列,这样rowKey最小但是最新的数据会放在队列的最前面。
Pool()时首先取出队列头一个StoreFile,从它里面获取一条数据。获取第二条数据时,继续从头部的StoreFile获取一条记录,然后会和队列中剩下的StoreFile的第一条记录做比对,如果前者大,则继续返回;如果后者大,会把头StoreFile放回队列重新排队,在重新取队列的头StoreFile,重复上述缩成,直道找到key所在的HFile。
知道HFile知道,就可以使用前面说的索引拉取对应的Data Block中的数据了
(源码那边具体是怎么走的,后续分析源码的时候再细看把)
HFile V3:(0.98版本中引入)
和V2相比变化不大,这里就不介绍了,后续会重点分析V2。
参考:
《HBase权威指南》
http://hbase.apache.org/book.html#_hfile_format_2(HBase官网中的附录)
http://blog.jobbole.com/91913/(HFile V1文件弃用)
https://www.cnblogs.com/163yun/p/9020629.html(HFile V2文件解析)
https://blog.csdn.net/yulin_hu/article/details/81673695(HFile数据完整索引流程)
https://blog.csdn.net/pml18710973036/article/details/69389394(Bloom Filter简介)