由于写请求是由regionserver处理的,它们会存储在被称作memstore的内存存储系统中。一旦memstore填满,它的内容就会被写到磁盘上,作为额外的存储文件。这个事件被称为memstore的flush。随着存储文件的累积,regionserver将把它们compact成更少,更大的文件。每次flush或compact完成后,该region内存储的数据量就发生了变化。regionserver咨询region split策略,以确定该region是否增长过大,或者是否应该因另一个特定split policy而被分割。region split的请求就会进入执行队列。

从逻辑上讲,region split的过程很简单。我们在该region的keyspace中找到一个合适的split point,在这个split point上将该region的数据划分为两个新的region。然而,这个过程的细节并不简单。当split发生时,新创建的子region不会立即将所有数据重新写入新文件。相反,它们创建类似于符号链接文件的小文件,命名为引用文件(reference files),根据split point,指向父存储文件的顶部或底部。引用文件就像常规的数据文件一样,但是只有一半的记录被考虑。如果没有对parent region的不可变数据文件的引用,则该区域只能被分割。这些参考文件会逐渐被compact,从而使该区域不再引用它的父文件,并且可以进一步分割。

尽管split该region是由regionserver做出的本地决策,但split过程本身必须与许多参与者协调。regionserver在split之前和之后通知Master以更新元数据表(hbase:meta表)。这样,客户端就可以发现新的子region,并在HDFS中重新安排目录结构和数据文件。region split是一个多任务的过程。为了在出现错误的情况下启用回滚,regionserver在内存中保留了执行过程日志。regionserver执行split的步骤在RegionServer Split Process中得到了说明,执行顺序见下图中的标签。regionserver或hmaster的操作显示为红色,而来自客户端的操作则显示为绿色。

hbase 按月年分表 hbase region split_hdfs

1.HRegionServer在本地决定split 该region,并准备split。分割事务开始了。作为第一步,HRegionServer获取表上的共享读锁,以防止在split过程中对模式进行修改。然后在/hbase/region-in-transition/region-name中创建一个znode,并将znode的状态设置为splitting。

2.HMaster读取这个znode,因为它读取原region-in-transition的znode。

3.HRegionServer在parent's region的HDFS目录下创建一个名为.splits的子目录.

4.HRegionServer 将被split的parent Region 关闭并在本地数据结构(local data structures)中标记为offline。因此正在splitting的region 当下就是offline状态。这个时候对该parent Region的客户端读写请求就会抛出“NotServingRegionException”的异常,客户端会进行一些retry,直到region被flush。(The client will retry with some backoff. The closing region is flushed.)

5.HRegionServer  在.splits目录下为子region创建目录,并创建必要的数据结构。然后,它会分割story files,因为会在parent region的每个story file上创建两个referrence file,这些referrence file会指向parent region’s files。

6.HRegionServer 在HDFS中为两个子region的referrence file创建实际的region目录。

7.HRegionServer会向hbase:meta表发送一个put请求,将parent region 标记为offline,并向hbase:meta表中添加子region的信息。这个时候子region在hbase:meta表中并没有单独的条目,如果扫描hbase:meta表,会发现parent region正在split,并不能看到子region的信息(需要等待之前的操作完成)。当子region 的信息写入hbase:meta表完成以后,表明这个parent region 被有效的split。如果RegionServer执行这个过程失败,master和下一个使用这个region的regionserver会清除split相关的状态数据。meta表更新后,由master推进这个split过程。

8.regionserver 并行启动两个子region.

9.regionserver将两个子region的相关信息写入meta表,这时候两个子region状态即为online。在这之后客户端就可以发现这两个新的region 并可以向他们发起请求。客户端会将meta表数据缓存到本地,但是当他们向regionserver或者meta表发起请求时,他们的本地缓存将会失效,这时他们会从meta表重新读取新的region信息。

10.regionserver将zookeeper中的znode /hbase/region-in-transition/region-name状态更新为split,这样master就可以获取到该信息。如果需要的话,balancer可以自由的将子region负载均衡到需要的regionserver上。整个split事务就这样完成了。

11.split完成后,meta表和HDFS都还保留了parent region的引用,这些引用会在子region进行compaction操作重新数据时删除。master的GC任务会周期性的检查子region是否还指向parent region 的存储文件,如果没有,则parent region 被删除。