HBase Split分析

Posted by BigData Blog on November 23, 2018


HBase Split分析

HBase split概述

   HBasesplitHBase根据一定的触发条件和一定的分裂策略将HBase的一个region进行分裂成两个子region并对父region进行清除处理的过程。RegionHBase中一个非常核心的组织单元,所有的region组成了整个HBase集群,如下面的HBase的体系结构所示:

(图一)

因此在HBase的整体region分裂过程中达到一生二,二生三,三生万物的效果。




HBase为啥要split


   HBase中,split其实是进行sharding的一种技术手段,通过HBasesplit条件和split策略,将region进行合理的split,再通过HBasebalance策略,将分裂的region负载均衡到各个regionserver上,最大化的发挥分布式系统的优点。HBase这种自动的sharding技术比传统的数据库sharding要省事的多,减轻了维护的成本,但是这样也会给HBase带来额外的IO开销,因此在很多系统中如果能很好的预计rowkey的分布和数据增长情况,可以通过预先分区,事先将region分配好,再将HBase的自动分区禁掉。


 


触发条件:


HBase中共有3种情况会触发HBasesplit,分别是:


1.memstore flush操作后,HRegion写入新的HFile,有可能产生较大的HFileHBase就会调用CompactSplitThread.requestSplit判断是否需要split操作。


2.HStore刚刚进行完compact操作后有可能产生较大的HFile,当满足HBase的某一分裂策略后就会进行split操作。


3.HBaseAdmin手动发起split时,也会触发split操作。


split策略


1.采用ConstantSizeRegionSplitPolicy策略,即storefile固定大小策略:


0.94版本之前ConstantSizeRegionSplitPolicy 是默认和唯一的split策略。当某个storefile(对应一个columnfamily)的大小大于配置值 ‘hbase.hregion.max.filesize’的时候(默认DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024 *1024L=10Gregion就会自动分裂:


对应的源代码如下:


                                    


(图二)


 


2.采用IncreasingToUpperBoundRegionSplitPolicy策略,即根据region数来决定:


0.94.0(包含)之后,默认采用此策略,即当同一table在同一regionserver上的region数量在[0,100)之间时按照如下的计算公式算,否则按照上一策略计算:


Min (R^3* "hbase.hregion.memstore.flush.size"*2, "hbase.hregion.max.filesize")


R为同一个table中在同一个regionserverregion的个数,


hbase.hregion.memstore.flush.size默认为128M


hbase.hregion.max.filesize默认为10G


对应源代码如下:


                                     


(图三)


 


这里还发现HBase源码里面的一个bug,即在此策略的注释中,讲的是某一table在同一regionserver中的个数的平方(squared),实际上代码的公式是立方,如下面标红所示,同时也发现网上很多人写的也是平方,但实际上就是立方(cube


 


 


两种用户自定义策略:KeyPrefixRegionSplitPolicyDelimitedKeyPrefixRegionSplitPolicy这两张策略是IncreasingToUpperBoundRegionSplitPolicy策略的具体实现


1.KeyPrefixRegionSplitPolicy策略,即根据rowkey指定长度的前缀来划分region


   即保证相同的前缀的row保存在同一个region中。指定rowkey前缀位数划分region,通过读取 KeyPrefixRegionSplitPolicy.prefix_length 属性,该属性为数字类型,表示前缀长度,在进行split时,按此长度对splitPoint进行截取。此种策略比较适合固定前缀的rowkey。当table中没有设置该属性,指定此策略效果等同与使用IncreasingToUpperBoundRegionSplitPolicy


相关源代码如下:


                                          


(图四)


 


2.DelimitedKeyPrefixRegionSplitPolicy策略:


保证以分隔符前面的前缀为splitPoint,保证相同RowKey前缀的数据在一个Region中。


                   


(图五)


 


HBase split的整体流程


下文引用hortonworks官方博客对HBasesplit流程的解释:


                                                


(图六)


 


1.RegionServer触发在本地进行split,并准备split。第一步就是在zk/hbase/region-in-transition/region-name的节点下创建一个znode节点,并置为SPLITTING状态;


2.因为Master一直watchzkznode,发现parentregion需要split


3.region server  hdfsparent region的目录下创建一个名为“.splits”的子目录。


4.region server关闭parent region。强制flush缓存,并且在本地数据结构中标记region为下线状态。如果这个时候客户端刚好请求到parent region,会抛出NotServingRegionException。这时客户端会进行重试。


5.region server.split目录下分别为两个daughter regionA,B)创建目录和必要的数据结构。然后创建两个引用文件指向parent regions的文件。


6.region serverHDFS中,创建真正的region目录,并且把引用文件移到对应的目录下。


7.region server发送一个put的请求到.META.表中,并且在.META.表中设置parent region为下线状态,并添加关于daughter regions的信息。但是这个时候在.META.表中daughter region 还不是独立的row,客户端在此时scan .META.表时会发现parent regionsplit,但是还不能获得daughter region的信息,直到她们独立的出现.META.表中。如果此时这个往.META.表中的put操作成功,parent region会高效的split,如果此时rsRPC请求成功前失败,Master和下一个regionserver会重新打开这个parent region并将之前产生的split的脏数据清掉,.META.表成功更新后,HBase继续进行下面split的流程。


8.region server并行打开两个daughter region接受写操作。


9.region server.META.表中增加daughters A B  region的相关信息,在这以后,client就能发现这两个新的regions并且能发送请求到这两个新的region了。client本地具体有.META.表的缓存,当他们访问到parent region的时候,发现parent region下线了,就会重新访问.META.表获取最新的信息,并且更新本地缓存。


10.region server 更新znode 的状态为SPLITmaster就能知道状态更新了,master的平衡机制会判断是否需要把daughter regions 分配到其他region server中。


11.split之后,metaHDFS依然会有引用指向parentregion.compact操作发生在daughter regions中,会重写数据file,这个时候引用就会被逐渐的去掉。GC任务会定时检测daughter regions是否还有引用指向parent files,如果没有引用指向parent files的话,parent region 就会被删除。


 


HBase split的过程分析


                                                    


(图七)


 


 


 


实际例子:


做个实际的例子分析一下:


我们在测试环境上对某张表(初始化时只有一个region),通过3split,变成了8region。下图是具体的每个parent region split成两个daughter region的过程。这里只缩写每个region的后四位编号:


 

                                         



(图八)


 


最终分裂完之后在hdfs上的region是这样的:


                  


(图九)


 

注意事项:


1.不能对元数据表进行split


2.不能对正在recoveryregionsplit


3.如果某个region存在引用文件的不能split


4.split的过程执行到将parent region offline之后,daughter region还未创建之前,客户端如果此刻正访问的是parent region,在客户端没有更新缓存的情况下,会报NotServingRegionException异常,因此客户端需要做好重试机制;

5.split的整个过程中有个关键的点,即PONR,即point of no return,无法回退的点,发生在将.META.表中的parent region更新为offline之前,如果进入PONR之后,由于种种原因更新.META.失败,需要重启所在的regionserver进行回滚。



参考:

http://zh.hortonworks.com/blog/apache-hbase-region-splitting-and-merging/