Fuhui

HBase Region Split


Tables are automatically partitioned horizontally by HBase into regions. Each region comprises a subset of a table's rows

引言

HBaseTable提供了自动拆分的功能,非常好奇,它的自动拆分是如何实现的呢?在工作中,我们经常会遇到MySQL数据分表的情况,比如一个数据表已经超过20G了,查询耗时相对严重,我们考虑对其进行分表。又比如,我们预测每个月的交易流水会有几十亿条数据,我们按月对表进行拆分,等等。

MySQL提供了分区表,市面上也有很多的Sharding策略。但具体问题需要具体分析,分表策略也必须结合具体的业务来考虑。比如一个博客网站,用户主页需要展示他过去发布的所有博客列表,基于此,按照用户来分表就更为合理,保证同一个用户的所有数据都存储在同一张表里。

Concepts

HBasecolumn被划分到一个column family里,所有的column family成员有一个唯一的前缀来标识。比如info:190101info:190102就属于info family的的成员。有趣的是,虽然column families必须在表schema definition中被声明,但它的成员却是能够随意添加。

关于Region,作为分布式HBase集群数据的最小单元,每个RegionServer管理着table regions的若干个子集。客户端在和HBase交互时,都需要请求集群的ZooKeeper来获取集群的服务信息,缓存相关的元信息,之后就跟具体的RegionServer做交互了。

Reading Data

专门去查看了HBase获取数据的方式,主要包括两种:

  1. 获取行
  2. 获取指定的列

相应的,我们需要了解它写入数据的方式:

put ’<table name>’,’row1’,’<colfamily:colname>’,’<value>’

ConstantSizeRegionSplitPolicy

Region有两个重要的属性StartKeyEndKey,用来表示Region维护的RowKey范围,当Region Size达到一定的阈值,HBase就会对其执行split操作,Region被划分为两个,其中一个Region,称呼为Region_1包含的StartKeyMidKey,另一个Region_2包含MidKeyEndKey的数据。这也引申出HBase的前缀范围查询的功能。

之所以可以这样划分,是因为HBase中数据行是以RowKey的字典序排列的,并且RowKey是全局唯一的。这样的划分策略对RowKey的设计有点需求,如果RowKey的随机性不好,在分布式集群中,负责Region_1RegionServer负载和负责Region_2的负载相差可能会很多,导致资源的利用很不均衡。

其实也很好理解,就比如以中国的姓作为RowKey的前缀,那么负责“王、李”的RegionServer的负载就会很高,因为这些数据都会根据StartKey-EndKey写入到具体的Region上。很多时候,为了使数据分布的更加均匀,充分利用集群的资源,我们需要对原始的RowKey做一次HASH处理,在原始的RowKey和实际存储的RowKey之间生成一个固定的映射关系。

extension

处理问题的思想都是相通的,比如HBase将数据存储到不同Region中。本质上也是:对数据进行分片,来扩展写操作。具体点就是:将数据划分成多个完全独立的子集,客户端通过映射关系,定向到具体的数据分片进行处理。

工作中接触最多的非MySQL莫属,如何对数据分片,根本还在于业务最终要实现怎样的查询。注意:设计中要尽量避免分片数据集的关联表查询,可能会有痛苦。

参考文章:

  1. HBase - Read Data