HBase的第一次读写

在最新HBase中去掉了ROOT -Table,只剩下一个特殊的目录叫做Meta Table(hbase:meta),它查出了集群中所有用户的HRegion的位置信息,而Zookeeper的节点中(/hbase/meta-region-server)存储的则直接是这个Meta Table的位置,并且这个Meta Table如以前的-ROOT-Tabke一样是不可split的,这样,客户端在第一次访问用户Tabke的流程就变成了:

  1. 从Zookeeper(/hbase/meta-region-server)中获取hbase:mete的位置(HRegionServer的位置),缓存该位置信息。
  2. 从HRegionServer中查询用户Table对应请求的RowKey所在的HRegionServer,缓存该位置信息。
  3. 从查询到的HRegionServer中读取Row

从这个过程中,我们发现客户会缓存这些位置信息,然而第二步它只是缓存当前RowKey对应的HRegion的位置,因而如果下一个要查的RowKey不在同一个HRegion中,则需要继续查询hbase:meta所在的HRegion,然而随着时间的推移,客户端缓存的位置信息越来越多,以至于不需要再次查找hbase:meta Table的信息,除非某个HRegion因为宕机或Split被移动,此时需要重新查询并且更新缓存。

HBase学习笔记(5)---HBase写流程

HRegionServer中数据写流程图解

当客户端发起一个Put请求时,首先它从hbase:meta表中查出该Put数据最终需要去的

HRegionServer,然后客户端将Put请求发送给相应的HRegionServer,在HRegionServer中

它首先会将该Put操作写入WAL日志文件中(Flush到磁盘中)。

HBase学习笔记(5)---HBase写流程

写完WAL日志文件后,然后会将数据写到Memstore,在Memstore中按RowKey排序,以及用LSM-TREE对数据做合并处理,HRegionServer根据Put中的TableName和RowKey找到对应的HRegion,并根据列族找到对应的HStore,并将put写入到给HStore的MemStore中。此时写成功,并返回通知客户端。

HBase学习笔记(5)---HBase写流程

MemStore Flush

MemStore是一个In Memory Sorted Buffer,在每个HStore中都有一个MemStore,即它是一个HRegion的一个Column Family对应一个实例。它的排列顺序以RowKey、Column Family、Column的顺序以及Timestamp的倒序,如下所示:
HBase学习笔记(5)---HBase写流程

每一次Put/Delete请求都是先写入到MemStore中,当MemStore满后会Flush成一个新的StoreFile(底层实现是HFile),即一个HStore(Column Family)可以有0个或多个StoreFile(HFile)。有以下三种情况可以触发MemStore的Flush动作:
1. 当一个HRegion中的MemStore的大小超过了:
hbase.hregion.memstore.flush.size的大小,默认128MB。
此时当前的MemStore会Flush到HFile中。
2. 当RS服务器上所有的MemStore的大小超过了:hbase.regionserver.global.memstore.upperLimit的大小,默认35%的内存使用量。
比如:一台服务器内存是64GB,留出10GB给操作系,留出4GB给他技术框架,剩余的50GB给HBase用,即当RS服务器上所有的Memstore总内存大小达到 50GB*35%,会触发flush
此时当前HRegionServer中所有HRegion中的MemStore可能都会Flush。从最大的Memostore开始flush

3. 当前HRegionServer中WAL的大小超过了 1GB
hbase.regionserver.hlog.blocksize(32MB) * hbase.regionserver.max.logs(32)的数量,当前HRegionServer中所有HRegion中的MemStore都会Flush
这里指的是两个参数相乘的大小。
查代码发现:hbase.regionserver.max.logs默认值是32,而hbase.regionserver.hlog.blocksize是HDFS的默认blocksize,32MB

此外,在MemStore Flush过程中,还会在尾部追加一些meta数据,其中就包括Flush时最大的WAL sequence值,以告诉HBase这个StoreFile写入的最新数据的序列,那么在Recover时就直到从哪里开始。在HRegion启动时,这个sequence会被读取,并取最大的作为下一次更新时的起始sequence。

HFile格式

HBase的数据以KeyValue(cell)的形式顺序的存储在HFile中,在MemStore的Flush过程中生成HFile,由于MemStore中存储的Cell遵循相同的排列顺序,因而Flush过程是顺序写我们知道磁盘的顺序写的性能很高,因为不需要不停的移动磁盘指针。
HBase学习笔记(5)---HBase写流程
每个HFile中有1或者多个Data Block,BlockCache中也一样。

HFile里面的每个KeyValue对就是一个简单的byte数组,但是这个byte数组里面包含了很多项,并且有固定的结构。
HBase学习笔记(5)---HBase写流程

开始是两个固定长度的数值,分别表示Key的长度和Value的长度。紧接着是Key,开始是固定长度的数值,表示RowKey的长度,紧接着是 RowKey,然后是固定长度的数值,表示Family的长度,然后是Family,接着是Qualifier,然后是两个固定长度的数值,表示Time Stamp和Key Type(Put/Delete)。Value部分没有这么复杂的结构,就是纯粹的二进制数据了。随着HFile版本迁移,KeyValue(Cell)的格式并未发生太多变化,只是在V3版本,尾部添加了一个可选的Tag数组。

HFileV1版本的在实际使用过程中发现它占用内存多,因而增加了启动时间。为了解决这些问题,在0.92版本中引入HFileV2版本:
HBase学习笔记(5)---HBase写流程
在这个版本中,为了提升启动速度,还引入了延迟读的功能,即在HFile真正被使用时才对其进行解析。

对HFileV2格式具体分析,它是一个多层的类B+树索引,采用这种设计,可以实现查找不需要读取整个文件:
HBase学习笔记(5)---HBase写流程

Data Block中的Cell都是升序排列,每个block都有它自己的Leaf-Index,每个Block的最后一个Key被放入Intermediate-Index中,Root-Index指向Intermediate-Index。在HFile的末尾还有Bloom Filter(布隆过滤)用于快速定位那么没有在某个Data Block中的Row;TimeRange信息用于给那些使用时间查询的参考。在HFile打开时,这些索引信息都被加载并保存在内存中,以增加以后的读取性能。

相关文章:

  • 2021-12-04
  • 2021-04-25
  • 2021-05-29
猜你喜欢
  • 2022-02-06
  • 2021-06-05
  • 2021-10-04
  • 2021-11-07
  • 2021-11-20
  • 2021-11-08
相关资源
相似解决方案