一、Region的切分

Region的自动切分

Region自动切分是HBase能够拥有良好扩张性的最重要因素之一,当然他也是分布式系统追求扩展性很好的功能。当一个Region大到一定程度,会进行分裂(split),HBase可以通过Region Split达到负载均衡。

自动切分的触发策略

自动切分的触发策略有很多种,在1.2.6版本中应该有六种触发策略。但是我们经常用的最多三种。

  • ConstantSizeRegionSplitPolicy:0.94版本前默认切分策略
  • I ncreasingToUpperBoundRegionSplitPolicy : 0.94版本~2.0版本默认切分策略
  • SteppingSplitPolicy: 2.0版本默认切分策略
ConstantSizeRegionSplitPolicy

这种切分策略的原理是当region的一个store的大小大于设置的阈值之后才会触发切分。这里实际实现store的大小为压缩后的文件大小。
ConstantSizeRegionSplitPolicy切分策略的弊端,没有对于大表和小表做明显的区分。阈值(hbase。hergion.max.filesize)设置较大对大表比较友好,但是设置较小则对小表比较友好。如果说对小表比较友好,就会出现大表在整个集群产生大量的region,这对于集群管理和资源使用显然不是一件好事。

I ncreasingToUpperBoundRegionSplitPolicy

在前面ConstantSizeRegionSplitPolicy的切分策略中,达到固定的阈值就会触发切分,但是在I ncreasingToUpperBoundRegionSplitPolicy中并不是这样,它的阈值并不是固定的,会在一定条件下进行调整,调整规则和regionserver上的region个数有关系:count(regions)^3 * flush size * 2.当然阈值不会一只增大,范围由用户设置的MaxRegionFileSize来确定。
这样的设计很好的弥补了ConstantSizeRegionSplitPolicy大小表切分不便的现象。

SteppingSplitPolicy: 2.0版本默认切分策略

这种切分就基本与I ncreasingToUpperBoundRegionSplitPolicy的切分方式差不多,但是切分阈值的规则不一样,它的规则是flush size * 2,否则为MaxRegionFileSize。

Region切分流程

Hbase将整个切分过程包装成了一个事务,意图能够保证切分事务的原子性。整个切分分为三个阶段
prepare – execute – (rollback)

  • prepare阶段:在内存中初始化两个子region,具体是生成两个HRegionInfo对象,包含tableName、regionName、startkey、endkey等。同时会生成一个transaction journal,这个对象用来记录切分的进展,具体见rollback阶段。
  • execute阶段:切分的核心操作。见下图(来自 Hortonworks ):
  • regionserver 更改ZK节点 /region-in-transition 中该region的状态为SPLITING。
  • master通过watch节点/region-in-transition检测到region状态改变,并修改内存中region的状态,在master页面RIT模块就可以看到region执行split的状态信息。
  • 在父存储目录下新建临时文件夹.split保存split后的daughter region信息。
  • 关闭parent region:parent region关闭数据写入并触发flush操作,将写入region的数据全部持久化到磁盘。此后短时间内客户端落在父region上的请求都会抛出异常NotServingRegionException。
  • 核心分裂步骤:在.split文件夹下新建两个子文件夹,称之为daughter A、daughter B,并在文件夹中生成reference文件,分别指向父region中对应文件。这个步骤是所有步骤中最核心的一个环节,生成reference文件日志如下所示
  • 父region分裂为两个子region后, 将daughter A、daughter B拷贝到HBase根目录下,形成两个新的region。
  • parent region通知修改 hbase.meta 表后下线,不再提供服务。下线后parent region在meta表中的信息并不会马上删除,而是标注split列、offline列为true,并记录两个子region。为什么不立马删除?且听下文分解。
  • 开启daughter A、daughter B两个子region。通知修改 hbase.meta 表,正式对外提供服务。
  • rollback阶段:如果execute阶段出现异常,则执行rollback操作。为了实现回滚,整个切分过程被分为很多子阶段,回滚程序会根据当前进展到哪个子阶段清理对应的垃圾数据。代码中使用 JournalEntryType 来表征各个子阶段。

二、Region预拆分

指定拆分算法

$ hbase org.apache.hadoop.hbase.util.RegionSplitter my_split_table HexStringSplit -c 10 -f mycf
其中:my_split_table:我们指定要新建的表名。
HexStringSplit:指定的拆分点算法为HexStringSplit。
-c:要拆分的Region数量。
-f:要建立的列族名称。

手动指定拆分点

#指定拆分点
create 'test_split2','mycf2',SPLITS=>['aaa','bbb','ccc','ddd','eee','fff']
#指定拆分文件
create 'students','baseinfo',SPLITS_FILE => '/home/hadoop/data/splits.txt'

三、Region的合并

合并的目的

如果删除了大量数据,很多Region变小,这时候分成多个Region就很浪费,可以把Region合并起来,Region的合并不是为了性能考虑,主要是出于维护的目的

合并分为两种

Minor一般由事件触发,Major一般由时间触发

相关控制
  • Minor(1.2.0-cdh5.14.2版本)
  • hbase.hregion.memstore.flush.size 缓存阈值大小
  • hbase.hstore.compaction.max :每次compact的HFile的最大数目,默认是10
  • hbase.hstore.compaction.kv.max:compact时批量读取和写入KeyValue数据的数量,默认是10
  • Major Compaction
  • hbase.hregion.majorcompaction 时间间隔

四、Flush和Compact操作

flush操作

flush 'tablename'
flush 'regionname'

compact操作

#compact一个表的所有regions
compact 't1'
#compact某个空闲的region
compact 'r1'
#compact一个region中的某个列族
compact 'r1', 'c1'
#compact一个表中的某个列族
compact 't1', 'c1'

六、Compaction - Control

Compaction总结

  • 重写log文件并清除旧值
  • 节约空间,提高读写速度
  • 会占用大量系统空间和I/O,一般在系统空闲时进行

Flush -> Minor Compaction -> Major Compaction

  • Flush:将memstore写到一个新的存储文件中
  • Minor一般由事件触发,Major一般由时间触发

相关控制

  • Flush: hbase.hregion.memstore.flush.size 文件大小
  • Minor: hbase.hstore.compaction.min/max 文件数
  • Major: hbase.hregion.majorcompaction 时间间隔