HBase Split分析,hbasesplit分析
HBase Split分析
HBase split概述
HBasesplit是HBase根据一定的触发条件和一定的分裂策略将HBase的一个region进行分裂成两个子region并对父region进行清除处理的过程。Region是HBase中一个非常核心的组织单元,所有的region组成了整个HBase集群,如下面的HBase的体系结构所示:
(图一)
因此在HBase的整体region分裂过程中达到一生二,二生三,三生万物的效果。
HBase为啥要split
在HBase中,split其实是进行sharding的一种技术手段,通过HBase的split条件和split策略,将region进行合理的split,再通过HBase的balance策略,将分裂的region负载均衡到各个regionserver上,最大化的发挥分布式系统的优点。HBase这种自动的sharding技术比传统的数据库sharding要省事的多,减轻了维护的成本,但是这样也会给HBase带来额外的IO开销,因此在很多系统中如果能很好的预计rowkey的分布和数据增长情况,可以通过预先分区,事先将region分配好,再将HBase的自动分区禁掉。
触发条件:
HBase中共有3种情况会触发HBase的split,分别是:
1.当memstore flush操作后,HRegion写入新的HFile,有可能产生较大的HFile,HBase就会调用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=10G)region就会自动分裂:
对应的源代码如下:
(图二)
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中在同一个regionserver中region的个数,
hbase.hregion.memstore.flush.size默认为128M,
hbase.hregion.max.filesize默认为10G。
对应源代码如下:
(图三)
这里还发现HBase源码里面的一个bug,即在此策略的注释中,讲的是某一table在同一regionserver中的个数的平方(squared),实际上代码的公式是立方,如下面标红所示,同时也发现网上很多人写的也是平方,但实际上就是立方(cube)。
两种用户自定义策略:KeyPrefixRegionSplitPolicy和DelimitedKeyPrefixRegionSplitPolicy,这两张策略是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官方博客对HBase的split流程的解释:
(图六)
1.RegionServer触发在本地进行split,并准备split。第一步就是在zk的/hbase/region-in-transition/region-name的节点下创建一个znode节点,并置为SPLITTING状态;
2.因为Master一直watch着zk的znode,发现parentregion需要split。
3.region server 在hdfs的parent region的目录下创建一个名为“.splits”的子目录。
4.region server关闭parent region。强制flush缓存,并且在本地数据结构中标记region为下线状态。如果这个时候客户端刚好请求到parent region,会抛出NotServingRegionException。这时客户端会进行重试。
5.region server在.split目录下分别为两个daughter region(A,B)创建目录和必要的数据结构。然后创建两个引用文件指向parent regions的文件。
6.region server在HDFS中,创建真正的region目录,并且把引用文件移到对应的目录下。
7.region server发送一个put的请求到.META.表中,并且在.META.表中设置parent region为下线状态,并添加关于daughter regions的信息。但是这个时候在.META.表中daughter region 还不是独立的row,客户端在此时scan .META.表时会发现parent region在split,但是还不能获得daughter region的信息,直到她们独立的出现.META.表中。如果此时这个往.META.表中的put操作成功,parent region会高效的split,如果此时rs在RPC请求成功前失败,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 的状态为SPLIT。master就能知道状态更新了,master的平衡机制会判断是否需要把daughter regions 分配到其他region server中。
11.在split之后,meta和HDFS依然会有引用指向parentregion.当compact操作发生在daughter regions中,会重写数据file,这个时候引用就会被逐渐的去掉。GC任务会定时检测daughter regions是否还有引用指向parent files,如果没有引用指向parent files的话,parent region 就会被删除。
HBase split的过程分析
(图七)
实际例子:
做个实际的例子分析一下:
我们在测试环境上对某张表(初始化时只有一个region),通过3次split,变成了8个region。下图是具体的每个parent region split成两个daughter region的过程。这里只缩写每个region的后四位编号:
(图八)
最终分裂完之后在hdfs上的region是这样的:
(图九)
注意事项:
1.不能对元数据表进行split;
2.不能对正在recovery的region做split;
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/