所有的写请求都是在RegionServer中进行,数据在memstore累积后一次性写入到Storefile磁盘中,这个过程称为memstore flush。数据量不断地增长,storefile文件不断增大。RegionServer会根据分表策略决定是否开始执行分表。
从逻辑上而言,Region的分裂过程是极为简单的,我们只有确定将Region分为两部分的分裂点,然后将一个Region拆分为两个新的Region即可。而实际上执行过程要相对复杂的多。当分裂开始时,新创建的两个子Region并不会写入数据,而是创建一个称为Reference files的链接文件分别指向原来Region Storefile的前半部分和后半部分。当原Region数据文件不再被访问时,Region开始进行分裂。Reference files会随着分裂而逐渐被清除,最终Region不再引用原Region,分裂逐渐完成,原Region被清除。
Region分裂虽然由RegionServer本身做出的决定,但是在分裂过程中会牵扯到其他部分的协作,分裂之前和之后RegionServer会通知Master;为了客户端可以找到新的Region更新.META.表;重新排列HDFS上的文件结构。分裂是一个多线程、多任务的操作,为了在错误发生时可以回滚,RegionServer会将执行的状态保存在内存之中。
下面是RegionServer分裂的过程,RegionServer和Master操作标识,客户端操作为:
利用ZooKeeper通信,通知Master。
RegionServer做出决定,Region的分裂开始。RegionServer会申请HBase表上的一个读锁,防止在分裂的过程中,HBase表的schema发生改变。在zookeeper的目录/hbase/region-in-transition/region-name下创建一个新的znode节点,并且设置为SPLITTING;
Master监听/hbase/region-in-transition/region-name目录下的znode节点,会同时感知到新的znode节点的创建;
父region关闭,进行分裂。
RegionServer在HDFS的父Region文件夹下创建一个名为.splits的子文件夹;
RegionServer在本地的数据结构中会关闭父Region,刷入cache中数据,并且使region处于下线状态。此时,如果客户端请求到关闭的父Region,会弹出NotServingRegionException的异常。客户端进行一些补偿性重试;
RegionServer在文件夹.splits下创建Region文件夹(子Region A和子Region B)和必要的数据结构。然后开始对store files进行分裂,对每一个父Region的store file文件创建两个Reference files,这些reference files指向父Region的文件;
RegionServer在HDFS上创建实际的Region文件夹,然后将reference files分别移到两个子Region文件夹下;
更新.META.表。
- RegionServer发送Put请求给.META.表,修改父Region为下线状态并且增加两个子Region的信息。这时,在.META.表中仍旧没有访问入口。客户端如果扫描.META.表,将会看到父Region正在分裂,不会看到子Region。如果Put请求执行成功,父Region将会高效的被分裂,否则Master和下次打开Region的RegionServer会清除这些脏数据;
分裂之后,打开新region,.META.表更新可访问新region,通知Master完成。
RegionServer并发打开子Region A和子Region B;
RegionServer增加子Region A 和子Region B的信息。具有父Region引用的子Region现在处于在线状态,客户端可以发现新的Region并且向它们发送请求。客户端会在本地缓存全部的.META.表信息,向新的Region发送请求时,本地的缓存无效,从.META.获取最新的Region信息;
RegionServer更新znode节点/hbase/region-in-transition/region-name的状态为SPLIT,这样Master可以及时了解到分裂的情况。负载均衡器如果需要可以自由地分配子Region到其他RegionServer中。现在,分裂操作完成。
最后清除无效的数据。
- 在分裂完成后,.META.和HDFS仍旧存在着指向父Region的引用。随着子Region数据的重写,这些引用会逐渐清除。Master中的垃圾回收器任务会定期检查子Region是否仍然具有父Region的引用。如果父Region不存在引用,则将会被清除。
上面是完整的RegionServer分裂的实现。在大数据存储过程中常常会遇到分表的情况产生,也是面试过程中大数据方面,面试官常常爱问的问题,“当数据量过大时,如果进行分库分表呢?”。HBase的分表操作或许会给我们一些启示。