HBase分析之Region定位

以前的理论是:客户端向ZooKeeper请求 -ROOT- 表的位置,然后通过 -ROOT- 表找 META 表的位置,再通过 META 表定位到Region Server位置。但这个理论已经过时了, -ROOT- 表已经消失在历史的尘埃中。

现在的ZooKeeper直接缓存了 META 表所在的位置信息(本质是一样的,只是这跳过了 -ROOT- 表,这个过程本来就很多余。。),可以直接通过ZooKeeper获取 META 表的位置,后续流程也还是一样的。因为限定了 META 表不可分割,只能存在一个Region,所以存储他的Region Server一定只有一个。下面看看具体怎么定位的。

定位流程

1. 发起定位

客户端向服务端发起请求时,会先去定位存储数据的Region位置,代码在HConnectionImplementation#locateRegion方法里。

@Override
public RegionLocations locateRegion(final TableName tableName,
  final byte [] row, boolean useCache, boolean retry, int replicaId)
throws IOException {
  ...
  if (tableName.equals(TableName.META_TABLE_NAME)) {
    return locateMeta(tableName, useCache, replicaId);
  } else {
    // Region not in the cache - have to go to the meta RS
    return locateRegionInMeta(tableName, row, useCache, retry, replicaId);
  }
}

2. 查询hbase:meta表

通过locateRegionInMeta(tableName, row, useCache, retry, replicaId);方法定位,这个方法里会向hbase:meta表发起请求。既然是HBase的!!要获取数据就需要用Scan。

byte[] metaKey = HRegionInfo.createRegionName(tableName, row, HConstants.NINES, false);

Scan s = new Scan();
s.setReversed(true);
s.setStartRow(metaKey);
s.setSmall(true);
s.setCaching(1);

Result regionInfoRow = null;
ReversedClientScanner rcs = null;

rcs = new ClientSmallReversedScanner(conf, s, TableName.META_TABLE_NAME, this,
  rpcCallerFactory, rpcControllerFactory, getMetaLookupPool(), 0);
regionInfoRow = rcs.next();

Scan的start_row格式是table_name,start_row,stop_row,例如要找到test表里startRow为row1,stopRow为row9的数据的位置,就会构造一个startRow为test,row1,99999999999999的scan,stopRow是被无视的变量。

3. 定位hbase:meta表

发起请求就会再次调用HConnectionImplementation#locateRegion方法,这次定位的是TableName.META_TABLE_NAME,就是hbase:meta,调用的方法是locateMeta(tableName, useCache, replicaId);,从ZooKeeper中获取到META表的位置信息。

private RegionLocations locateMeta(final TableName tableName,
    boolean useCache, int replicaId) throws IOException {
  // 缓存判断
  ...
    // 从zookeeper里获取hbase:meta的位置
    locations = this.registry.getMetaRegionLocation();
    if (locations != null) {
      cacheLocation(tableName, locations);
    }
  }
  return locations;
}

4. 得到Region信息

然后查询到的结果是这样的。

 test,,1509281716605.6a column=info:regioninfo, timestamp=1509282949240, value={ENCODED 
 369c3c62302852bc15e563 => 6a369c3c62302852bc15e563b28606a9, NAME => 'test,,150928171660
 b28606a9.              5.6a369c3c62302852bc15e563b28606a9.', STARTKEY => '', ENDKEY => 
                        ''}                                                             
 test,,1509281716605.6a column=info:seqnumDuringOpen, timestamp=1509282949240, value=\x0
 369c3c62302852bc15e563 0\x00\x00\x00\x00\x00\x00\x09                                   
 b28606a9.                                                                              
 test,,1509281716605.6a column=info:server, timestamp=1509282949240, value=192.168.1.108
 369c3c62302852bc15e563 :51140                                                          
 b28606a9.                                                                              
 test,,1509281716605.6a column=info:serverstartcode, timestamp=1509282949240, value=1509
 369c3c62302852bc15e563 282943972                                                       
 b28606a9. 

这样就知道这个数据的位置了,Connection就把这个结果缓存住,接着就拿这个定位信息去查询数据了。

总结

在初始情况下,需要请求一次ZooKeeper获得hbase:meta表位置,Scan hbase:meta表获得Region位置,Scan Region获得数据;最差情况下发现缓存的都是错的,都得重来一遍。

-END-

你可能感兴趣的:(大数据)