2021SC@SDUSC
一、初步认识region定位
在 HBase 中,表的所有行都是按照 RowKey 的字典序排列的,表在行的方向上分割为多个分区(Region),如下图所示。
每张表一开始只有一个 Region,但是随着数据的插入,HBase 会根据一定的规则将表进行水平拆分,形成两个 Region。当表中的行越来越多时,就会产生越来越多的 Region,而这些 Region 无法存储到一台机器上时,则可将其分布存储到多台机器上。
Meta表
有了 Region 标识符,就可以唯一标识每个 Region。为了定位每个 Region 所在的位置,可以构建一张映射表。
映射表的每个条目包含两项内容,一项是 Region 标识符,另一项是 Region 服务器标识。这个条目就表示 Region 和 Region 服务器之间的对应关系,从而就可以使用户知道某个 Region 存储在哪个 Region 服务器中。这个映射表包含了关于 Region 的元数据,因此也被称为“元数据表”,又名“Meta表”。
Meta 表中的每一行记录了一个 Region 的信息。RowKey 包含表名、起始行键和时间戳信息,中间用逗号隔开,第一个 Region 的起始行键为空。时间戳之后用.隔开的为分区名称的编码字符串,该信息是由前面的表名、起始行键和时间戳进行字符串编码后形成的。
Meta 表里有一个列族 info。info 包含了三个列,分别为 RegioninfoServer 和 Serverstartcode。Regionlnfo中记录了 Region 的详细信息,包括行键范围 StartKey 和 EndKey、列族列表和属性。
Server 记录了管理该 Region 的 Region 服务器的地址,如 localhost:16201。Serverstartcode 记录了 Region 服务器开始托管该 Region 的时间。
当用户表特别大时,用户表的 Region 也会非常多。Meta 表存储了这些 Region 信息,也变得非常大。Meta 表也需要划分成多个 Region,每个 Meta 分区记录一部分用户表和分区管理的情况。
Region定位
在 HBase 的早期设计中,Region 的查找是通过三层架构来进行查询的,即在集群中有一个总入口 ROOT 表,记录了 Meta 表分区信息及各个入口的地址。这个 ROOT 表存储在某个 Region 服务器上,但是它的地址保存在 ZooKeeper 中。
这种早期的三层架构通过先找到 ROOT 表,从中获取分区 Meta 表位置;然后再获取分区 Meta 表信息,找出 Region 所在的 Region 服务器。
从 0.96 版本以后,三层架构被改为二层架构,去掉了 ROOT 表,同时 ZooKeeper 中的 /hbase/root-region-server 也被去掉。Meta 表所在的 Region 服务器信息直接存储在 ZooKeeper 中的 /hbase/meta-region-server 中。
客户端通过 ZooKeeper 获取 Meta 表分区存储的地址,首先在对应的 Region 服务器上获取 Meta 表的信息,得到所需的表和行键所在的 Region 信息,然后从 Region 服务器上找到所需的数据。
一般客户端获取 Region 信息后会进行缓存,用户下次再查询不必从 ZooKeeper 开始寻址。
二、Region定位
loc = hConnection.locateRegion(this.tableName, row.getRow());
一、
private HRegionLocation locateRegion(final TableName tableName,
final byte [] row, boolean useCache, boolean retry) {
if (tableName.equals(TableName.META_TABLE_NAME)) {
return this.registry.getMetaRegionLocation();
} else {
// Region not in the cache - have to go to the meta RS
return locateRegionInMeta(TableName.META_TABLE_NAME, tableName, row,
useCache, userRegionLock, retry);
}
}
这是HConnectionManager
类,TableName.META_TABLE_NAME
,这个就是我们要找的-ROOT-,在0.96里面它已经被取消了,取而代之的是META表中的第一个regionHRegionInfo.FIRST_META_REGIONINFO
,它位置在zk的meta-region-server节点当中的。
private RegionLocations locateRegionInMeta(TableName tableName, byte[] row, boolean useCache,
boolean retry, int replicaId) throws IOException {
// If we are supposed to be using the cache, look in the cache to see if we already have the
// region.
if (useCache) {
RegionLocations locations = getCachedLocation(tableName, row);
if (locations != null && locations.getRegionLocation(replicaId) != null) {
return locations;
}
}
byte[] metaStartKey = RegionInfo.createRegionName(tableName, row, HConstants.NINES, false);
byte[] metaStopKey =
//...
这是locateRegionInMeta
类,调用locateRegionInMeta函数,首先查找cache中是否有table对应的row,对应缓存中的Table对应的startkey与endkey,判断row是否在某个region中;若能找到,直接返回该regionlocation信息
这里的cache是Map<tableName, SoftValueSortedMap<rowkey, HRegionLocation>>
, 通过tableName获得它的基于rowkey的子map,这个map是按照key排好序的,如果找不到合适的key,就找比它稍微小一点的key。
下面是for循环,默认尝试31次
HRegionLocation metaLocation = null;
try {
metaLocation = locateRegion(parentTable, metaKey, true, false);
if (metaLocation == null) continue;
ClientService.BlockingInterface service = getClient(metaLocation.getServerName