HBase在新建一个表的时候,默认会把所有数据都会放在一个HRegion上,主节点HMaster根据一定的策略把HRegion分配到不同的HRegionServer从节点上,客户端在进行读写操作的时候,就会访问对应HRegionServer的HRegion。当HRegion的数据量超过阀值的时候,为了防止单个热点访问带来的压力,HBase就会对HRegion进行split操作,一个父HRegion分为两个子HRegion,后续的数据写入操作就会分配到两个HRegion里,减轻了单个热点的负载。由此可以看到split是一种动态的负载平衡机制。如果对数据库知识有过一定了解,就会发现这就是数据库常用的sharding技术,只不过HBase提供了自动化处理,减轻维护开销。另外split会产生额外的IO,实际实践中也有手动关闭该特性,按照规模进行预先分配HRegion的做法。
具体实现
split是把数据平均分配的操作:按照父HRegion的SplitKey(约为rowKey范围的中间值)把父HRegion分成两个子HRegion后,同时会把父HRegion的数据也会重新写入到两个子HRegion上。另外子HRegion的rowKey范围是父HRegion的各自一半,这样后面的rowKey就会按照范围插入对应的HRegion。split在执行过程中采取一些做法避免影响读写请求,由于split过程需要较长时间大量的IO操作,如果发生故障就需要有效的failover机制,防止数据处于不一致的状态。整个步骤可以参考文章的这个图,其中有些细节不同,但大致过程基本一致。
split入口
当memstore flush操作后,HRegion写入新的HFile或者HStore刚刚进行完compact操作后,这两个操作都有可能产生较大的HFile,HBase就会调用CompactSplitThread.requestSplit判断是否需要split操作。这个判断如下: