hbase源码系列(三)Client如何找到正确的Region Server
客户端在进行put、delete、get等操作的时候,它都需要数据到底存在哪个Region Server上面,这个定位的操作是通过HConnection.locateRegion方法来完成的。
loc = hConnection.locateRegion(this.tableName, row.getRow());这里我们首先要讲hbase的两张元数据表-ROOT-和.META.表,它们一个保存着region的分部信息,一个保存着region的详细信息。在《hbase实战》这本书里面详细写了查找过程总共有8步:
1)客户端首先查询zookeeper -ROOT-表在哪里
2)zookeeper告诉客户端,-ROOT-在RegionServer RS1上面
3)客户端向RS1发起查询,哪一个.META表可以查到T1表里面的00009
4)RS1上的-ROOT-告诉客户端在RS3上面的.META. region M2可以找到
5)客户端向RS3上的.META. region M2查询T1表的00009行数据在哪个region上,哪一个Region Server可以提供服务
6)RS3告诉客户端,在RS3上面的region T1R3
7)客户端向RS3上面的region T1R3发起请求,我要读取00009行
8)RS3上的region T1R3把数据发给客户端,行,拿去吧
那在代码里面是怎么体验上述过程的呢?好,我们开始查看locateRegion这个方法,打开HConnectionManager这个类。
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); }TableName.META_TABLE_NAME,这个就是我们要找的-ROOT-,在0.96里面它已经被取消了,取而代之的是META表中的第一个regionHRegionInfo.FIRST_META_REGIONINFO,它位置在zk的meta-region-server节点当中的。
好吧,再回到代码里面,我们这里肯定是走else这个路径,我们进入locateRegionInMeta看看。代码好长啊,我们一点一点看吧,先从缓存里面找,把tableName和rowkey传进去。
if (useCache) { location = getCachedLocation(tableName, row); if (location != null) { return location; }这里的cache是这样组织的Map tableName, SoftValueSortedMap rowkey, HRegionLocation , 通过tableName获得它的基于rowkey的子map,这个map是按照key排好序的,如果找不到合适的key,就找比它稍微小一点的key。
接下来就是一个for循环了,默认是尝试31次。
HRegionLocation metaLocation = null; try { // locate the meta region 还好这个不是玩递归,直接获取meta表所在的位置 metaLocation = locateRegion(parentTable, metaKey, true, false); if (metaLocation == null) continue; // 通过这方法可以获得Region Server,超值啊 ClientService.BlockingInterface service = getClient(metaLocation.getServerName()); synchronized (regionLockObject) if (useCache) { location = getCachedLocation(tableName, row); if (location != null) { return location; // 如果表没有被禁用,就预加载缓存 if (parentTable.equals(TableName.META_TABLE_NAME) (getRegionCachePrefetch(tableName))) { prefetchRegionCache(tableName, row); // 如果缓存中有,就从缓存中取 location = getCachedLocation(tableName, row); if (location != null) { return location; }else { // 不需要缓存就在缓存中删掉 forceDeleteCachedLocation(tableName, row); }
从上面的代码分析,它在prefetchRegionCache方法预先缓存了和表和row相关的位置信息,核心的代码如下:
MetaScannerVisitor visitor = new MetaScannerVisitorBase() { public boolean processRow(Result result) throws IOException { // 把result转换为regionInfo HRegionInfo regionInfo = MetaScanner.getHRegionInfo(result); long seqNum = HRegionInfo.getSeqNumDuringOpen(result); HRegionLocation loc = new HRegionLocation(regionInfo, serverName, seqNum); // cache this meta entry cacheLocation(tableName, null, loc); return true; }; MetaScanner.metaScan(conf, this, visitor, tableName, row, this.prefetchRegionLimit, TableName.META_TABLE_NAME);
这里面的核心代码只有两行,实现一个MetaScannerVisitor,然后传入到MetaScanner.metaScan扫描一下,metaScan会调用visiter的processRow方法,processRow方法把满足条件的全都缓存起来。下面是条件,有兴趣的人可以看一下,我折叠起来。
HRegionInfo regionInfo = MetaScanner.getHRegionInfo(result); if (regionInfo == null) { return true; // possible we got a region of a different table... if (!regionInfo.getTable().equals(tableName)) { return false; // stop scanning if (regionInfo.isOffline()) { // dont cache offline regions return true; ServerName serverName = HRegionInfo.getServerName(result); if (serverName == null) { return true; // dont cache it }
看一下MetaScanner.metaScan吧,它也是用了new了一个HTable。
HTable metaTable = new HTable(TableName.META_TABLE_NAME, connection, null);然后根据有三种情况,根据情况来构建Scan的StartKey:
1.根据rowkey来扫描
2.全表扫
3.根据表的名来
这里讲一下根据rowkey来扫描吧,别的都很简单,它用的是HTable的getRowOrBefore来找到这个Row,只不过因为它是meta表,可以从zk上直接找到位置。
byte[] searchRow = HRegionInfo.createRegionName(tableName, row, HConstants.NINES, false); Result startRowResult = metaTable.getRowOrBefore(searchRow, HConstants.CATALOG_FAMILY); HRegionInfo regionInfo = getHRegionInfo(startRowResult); byte[] rowBefore = regionInfo.getStartKey(); startRow = HRegionInfo.createRegionName(tableName, rowBefore, HConstants.ZEROES, false);
下面就开始Scan了,这个Scan的代码,和我们平常用HTable来扫描表是一样的。
final Scan scan = new Scan(startRow).addFamily(HConstants.CATALOG_FAMILY); int rows = Math.min(rowLimit, configuration.getInt(HConstants.HBASE_META_SCANNER_CACHING, HConstants.DEFAULT_HBASE_META_SCANNER_CACHING)); scan.setCaching(rows); // Run the scan scanner = metaTable.getScanner(scan); Result result = null; int processedRows = 0; while ((result = scanner.next()) != null) { // 用visitor.processRow来过滤不符合的result if (visitor != null) { if (!visitor.processRow(result)) break; processedRows++; if (processedRows = rowUpperLimit) break; }
如果没用缓存的情况,就只能走接口的方式了,直接从服务器去了,如果这都找不着,这一次就算结束了。
regionInfoRow = ProtobufUtil.getRowOrBefore(service,metaLocation.getRegionInfo().getRegionName(), metaKey, HConstants.CATALOG_FAMILY); // 下面是具体的实现 GetRequest request = RequestConverter.buildGetRowOrBeforeRequest(regionName, row, family); GetResponse response = client.get(null, request); if (!response.hasResult()) return null; return toResult(response.getResult());好,现在最后总结一下吧:
1)要查询数据时候,在locateRegion方法要先走locateRegionInMeta这段
2)从zk当中获取meta表的位置,通过这个位置信息ServerName,获得Region Server的接口,但是这里先不用,留给不用缓存的情况用的
3)使用缓存的话,如果这个表没被禁用,就先把要定位的整个表的region的位置信息,全部缓存起来
4)在缓存表的过程当中,我们要借助new HTable(TableName.META_TABLE_NAME, connection, null)来计算startKey和扫描。
5)把扫描到的表相关的位置信息缓存起来,缓存之后取的过程这里忘了交代了,通过表名找到表对应的一个HRegionInfo,HRegionInfo里面包括startKey和stopKey,用rowkey一比对就知道是哪个region了。
6)不用缓存的情况,就走接口的方式,构造一个GetRequest,调用Region Server里面的get方法获取到位置信息。
HBase Region合并分析 1.概述 HBase中表的基本单位是Region,日常在调用HBase API操作一个表时,交互的数据也会以Region的形式进行呈现。一个表可以有若干个Region,今天笔者就来和大家分享一下Region合并的一些问题和解决方法。
1.HbaseAdmin发起split:### 2.RSRpcServices实现类执行split(Implements the regionserver RPC services.)### 3.CompactSplitThread类与SplitRequest类用来执行region切割:### 4.splitRequest执行doSplitting操作### 4.1初始化两个子region### 4.2执行切割#### 4.2.1:(创建子region。
第十二届 BigData NoSQL Meetup — 基于hbase的New sql落地实践 立即下载
相关文章
- HBase源码:HMaster启动过程
- 手动安装Cloudera HBase CDH
- HBase学习之深入理解Memstore-6
- hbase 单机+伪分布环境搭建学习-1
- 基于C#+Thrift操作HBase实践
- C# 连接SQL Server数据库的几种方式--server+data source等方式
- SQL SERVER错误:已超过了锁请求超时时段。 (Microsoft SQL Server,错误: 1222)
- 大数据应用之HBase数据插入性能优化实测教程
- Spring Boot 2.x :通过 spring-boot-starter-hbase 集成 HBase
- SQL SERVER全面优化-------Expert for SQL Server 诊断系列
- SQL Server replication requires the actual server name to make a connection to the server.错误解决
- VIEW SERVER STATE permission was denied on object 'server', database 'master'
- Hbase 学习(十一)使用hive往hbase当中导入数据
- hbase源码系列(九)StoreFile存储格式
- hbase 完全分布式启动集群报错: KeeperErrorCode = NoNode for /hbase/master 问题
- Java客户端操作HBase:创建表代码示例
- SQL SERVER服务器链接连接(即sql server的跨库连接)
- hbase 多个过滤器组合(列表)
- hbase 安装笔记
- MySQL、HBase、ES的特点和区别
- SQL SERVER服务器链接连接(即sql server的跨库连接)
- E-MapReduce的HBase集群使用Hue
- 0402-服务注册与发现-Eureka Server使用、将服务注册到Eureka server上
- 从 Microsoft Dynamics CRM 4.0 server迁移到 Microsoft Dynamics CRM 2013 Server
- HBase单机环境搭建
- OpenTSDB介绍——基于Hbase的分布式的,可伸缩的时间序列数据库,而Hbase本质是列存储
- 安装CDH6.3版本的时候遇到 ‘ERROR main:com.cloudera.server.cmf.Main: Server failed’的解决方案
- hbase_学习_HBase环境搭建(单机)
- hbase中regionservice split 过程
- Hbase常见异常hbase:meta,,1.1588230740 is NOT online; state={1588230740 state=OPEN, ts=162
- 【大数据开发运维解决方案】Hadoop+Hive+HBase+Kylin 伪分布式安装指南