HBase的table是该region切分的,client操作一个row的时候,如何知道这个row对应的region是在哪台Region server上呢?这里有个region location过程。主要涉及到2张系统表,-ROOT-,.META.。其结构见图
在zookeeper的/hbase/root-region-server节点中存着-ROOT-表所在的Region Server地址。
-ROOT-表的一个row代表着META的一个region信息,其key的结构是META表名,META表Region的startkey,RegionId。其value的主要保存regioninfo和server信息。ROOT表不能split
.META.表的一个row代表着用户表的一个region信息,其key的结构是其实就是用户表的regionName,用户表名,startKey,RegionId。其value同样保存着regioninfo和server信息。META表可以split,但是一个region默认有128M,可以存上亿个用户表的region信息,所以一般不会split。
其查找过程如下:
1.通过zk getData拿-ROOT-表的location
2.RPC -ROOT-表的rs,getClosestRowBefore,拿row对应的meta表的region location
3.RPC .META.表的某一个region,拿该row在真实table所在的region location
4.RPC对应region
region location需要3次网络IO,为了提升性能,client会cache数据。
LocationCache是一个2级Map,第一级的key是tableName的hash值,第二级的key是starRow,用SoftValueSortedMap包装了TreeMap实现,用软引用实现cache,内存不够时才会回收。Cache里存在META表和用户表的region location信息。
其代码实现如下,0.94版本:
HConnectionManager locateRegion入口
private HRegionLocation locateRegion(final byte [] tableName, final byte [] row, boolean useCache) throws IOException { ....... //检查下都应的zkTracker是否启动 ensureZookeeperTrackers(); //如果是-ROOT-表,则通过zk节点/hbase/root-region-server获取-ROOT-表所在的Location if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { try { //通过zk的getData接口拿节点数据,此处会等待节点数据就位或者超时 ServerName servername = this.rootRegionTracker.waitRootRegionLocation(this.rpcTimeout); LOG.debug("Looked up root region location, connection=" + this + "; serverName=" + ((servername == null)? "": servername.toString())); if (servername == null) return null; //返回一个拼装的HRegionLocation,因为-ROOT-表只有一个region,而且不会split return new HRegionLocation(HRegionInfo.ROOT_REGIONINFO, servername.getHostname(), servername.getPort()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; } } //如果是.META.表,则请求.META.表,这里的row其实就是请求row拼装的regionName,类似test,key1,99999999999999 //如果没命中cache,则继续请求-ROOT-表,拿到这个row对应的.META.表的region location else if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) { return locateRegionInMeta(HConstants.ROOT_TABLE_NAME, tableName, row, useCache, metaRegionLock); } //如果是用户表,则请求用户表,这里的row就是key1 //如果没命中cache,则请求.META.表,获取该row对应的region location else { // Region not in the cache - have to go to the meta RS return locateRegionInMeta(HConstants.META_TABLE_NAME, tableName, row, useCache, userRegionLock); } }
locateRegionInMeta方法
private HRegionLocation locateRegionInMeta(final byte [] parentTable, final byte [] tableName, final byte [] row, boolean useCache, Object regionLockObject) throws IOException { HRegionLocation location; // If we are supposed to be using the cache, look in the cache to see if // we already have the region. //先读cache,cache没有再往上找 //注意如果rowkey的region locatin变化了,RPC的时候会失败,客户端做重试的时候useCache是false if (useCache) { location = getCachedLocation(tableName, row); if (location != null) { return location; } } // build the key of the meta region we should be looking for. // the extra 9's on the end are necessary to allow "exact" matches // without knowing the precise region names. //先拼一个想查找的key,类似于test,key1,99999999999999 byte [] metaKey = HRegionInfo.createRegionName(tableName, row, HConstants.NINES, false); //默认重试10次 for (int tries = 0; true; tries++) { //找不到 if (tries >= numRetries) { throw new NoServerForRegionException("Unable to find region for " + Bytes.toStringBinary(row) + " after " + numRetries + " tries."); } HRegionLocation metaLocation = null; try { // locate the root or meta region //递归查找parentTable metaLocation = locateRegion(parentTable, metaKey); // If null still, go around again. if (metaLocation == null) continue; //找到对应Region server地址之后,可以发起RPC请求了。 //这里先生成一个RPC Proxy对象,具体RPC分析见后文 HRegionInterface server = getHRegionConnection(metaLocation.getHostname(), metaLocation.getPort()); Result regionInfoRow = null; // This block guards against two threads trying to load the meta // region at the same time. The first will load the meta region and // the second will use the value that the first one found. synchronized (regionLockObject) { // If the parent table is META, we may want to pre-fetch some // region info into the global region cache for this table. //如果parentTable是.META.表,则预先获取.META.的一些数据,默认10条 if (Bytes.equals(parentTable, HConstants.META_TABLE_NAME) && (getRegionCachePrefetch(tableName)) ) { prefetchRegionCache(tableName, row); } // Check the cache again for a hit in case some other thread made the // same query while we were waiting on the lock. If not supposed to // be using the cache, delete any existing cached location so it won't // interfere. if (useCache) { location = getCachedLocation(tableName, row); if (location != null) { return location; } } //如果不使用cache,则清除之,比如row对应的region发生了分裂,用老的location启动rpc时会抛异常,此时通过useCache=fasle重新 //寻址,并把老的cache删掉 else { deleteCachedLocation(tableName, row); } // Query the root or meta region for the location of the meta region //发起RPC请求,获取<=该key的行 regionInfoRow = server.getClosestRowBefore( metaLocation.getRegionInfo().getRegionName(), metaKey, HConstants.CATALOG_FAMILY); } if (regionInfoRow == null) { throw new TableNotFoundException(Bytes.toString(tableName)); } //region信息,做校验,region会处于不稳定状态 byte [] value = regionInfoRow.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER); if (value == null || value.length == 0) { throw new IOException("HRegionInfo was null or empty in " + Bytes.toString(parentTable) + ", row=" + regionInfoRow); } // convert the row result into the HRegionLocation we need! //反序列化 HRegionInfo regionInfo = (HRegionInfo) Writables.getWritable( value, new HRegionInfo()); // possible we got a region of a different table... //一些校验 if (!Bytes.equals(regionInfo.getTableName(), tableName)) { throw new TableNotFoundException( "Table '" + Bytes.toString(tableName) + "' was not found, got: " + Bytes.toString(regionInfo.getTableName()) + "."); } if (regionInfo.isSplit()) { throw new RegionOfflineException("the only available region for" + " the required row is a split parent," + " the daughters should be online soon: " + regionInfo.getRegionNameAsString()); } if (regionInfo.isOffline()) { throw new RegionOfflineException("the region is offline, could" + " be caused by a disable table call: " + regionInfo.getRegionNameAsString()); } //该region的server location value = regionInfoRow.getValue(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER); String hostAndPort = ""; if (value != null) { hostAndPort = Bytes.toString(value); } ...... // Instantiate the location String hostname = Addressing.parseHostname(hostAndPort); int port = Addressing.parsePort(hostAndPort); location = new HRegionLocation(regionInfo, hostname, port); //cache之 cacheLocation(tableName, location); return location; } catch (TableNotFoundException e) { // if we got this error, probably means the table just plain doesn't // exist. rethrow the error immediately. this should always be coming // from the HTable constructor. throw e; } catch (IOException e) { if (e instanceof RemoteException) { e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e); } if (tries < numRetries - 1) { ....... } else { throw e; } // Only relocate the parent region if necessary //网络有问题,则重新找 if(!(e instanceof RegionOfflineException || e instanceof NoServerForRegionException)) { relocateRegion(parentTable, metaKey); } } //重试次数越多,sleep越长,interrupt则退出重试 try{ Thread.sleep(ConnectionUtils.getPauseTime(this.pause, tries)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException("Giving up trying to location region in " + "meta: thread is interrupted."); } } }
相关推荐
【HBASERegion数量增多问题描述及解决方案】 在HBase分布式数据库中,Region是表数据的基本存储单元,它将表的数据按照ROWKEY的范围进行分割。随着数据的增长,一个Region会分裂成两个,以此来确保数据的均衡分布。...
1、region 拆分机制 ...当region大小大于某个阈值(hbase.hregion.max.filesize=10G)之后就会触发切分,一个region等分为2个region。 但是在生产线上这种切分策略却有相当大的弊端:切分策略对于大表和小表没有
hbase-region-inspector, HBase区域统计信息的可视化仪表板 hbase-region-inspectorHBase区域统计信息的可视化仪表板。 用法下载与HBase集群版本匹配的可执行二进制插件,添加execute权限,并使用以下命令行参数启动...
hbase-packet-inspector hbase-packet-inspector (HPI)是用于分析HBase RegionServers网络流量的命令行工具。 HPI读取tcpdump文件或捕获网络接口的实时数据包流,以提取有关客户端请求和响应的信息。 您可以对其...
在HBase中,Region自动切分是其可扩展性的重要机制,它确保了系统的水平扩展性和数据分布的均匀性。Region切分的关键在于如何高效、平衡地管理数据,避免单个Region过大导致性能下降,同时也要防止过度切分造成资源...
在HBase这个分布式列式数据库中,Region是其核心的数据存储和管理单元,它负责存储表中的行数据。随着数据量的增长,一个Region可能会变得过大,导致读写性能下降。这时,就需要对Region进行数据切割(Split),以...
在IT行业中,尤其是在大数据处理领域,HBase是一个广泛使用的分布式、高性能、列式存储的NoSQL数据库。HBase是建立在Hadoop文件系统(HDFS)之上,为处理大规模数据提供了一个高效的数据存储解决方案。而Spring Data...
1. Region服务器:存储HBase表的分区,负责处理表的读写请求。 2. Master节点:管理Region服务器,处理表和Region的分配,监控服务器健康状态,进行Region分裂和合并操作。 3. ZooKeeper:协调HBase集群,提供服务...
HBASE的主要原理解读:包括HBase 读写逻辑、HBase region拆分和合并
HBase中的Region分割(Region Split)是一个关键特性,它允许HBase在表数据量增大时,自动将一个Region分割成两个,从而保证每个Region的大小都保持在一个合理的范围。这是实现HBase高扩展性和高性能的关键机制之一...
HBase 元数据修复工具包。 ①修改 jar 包中的application.properties,重点是 zookeeper.address、zookeeper.nodeParent、hdfs.root.dir配置项,hdfs 最好写 ip; ②将core-site.xml、hdfs-site.xml添加到BOOT-INF/...
分区,或者说Region,是HBase存储数据的基本单位。每个Region包含一个或多个表的行键范围,确保数据的分散存储,从而提高查询效率。当我们谈论"Hbase分区merge和split操作"时,我们指的是管理员或开发人员对Region...
HBase,全称为Hadoop Distributed File System上的基础结构(HBase on Hadoop Distributed File System),是一种...理解HBase的Region分裂和合并机制、RegionServer负载均衡以及故障处理策略也是深入使用HBase的关键。
在HBase的分布式架构中,`org.apache.hadoop.hbase.client.HConnectionManager`负责管理客户端与HBase服务器之间的连接,而`org.apache.hadoop.hbase.regionserver.HRegionServer`是处理Region服务的主要组件,它...
HBase是Apache Hadoop生态系统中的一个分布式、版本化、列族式存储系统,设计用于处理大规模数据集。这个“hbase-2.4.17-bin”安装包提供了HBase的最新稳定版本2.4.17,适用于大数据处理和分析场景。下面将详细介绍...
7. **Region Server**:Region Server是HBase的主要工作节点,负责Region的存储和管理,包括读写操作。 8. **Zookeeper**:Zookeeper是HBase的重要组件,用于协调集群中的节点,如Region Server的位置信息。 ### ...
- **自动分片**(Auto-Sharding):HBase通过自动将表分割成多个区域(Region),每个区域可以被分配到不同的节点上,从而实现水平扩展。 - **存储API**(Storage API):HBase提供了一套用于数据存储和访问的API...
数据分区与分布**:为了支持大规模数据的高效处理,HBase使用Region的概念对表进行水平分割。每个Region包含一定范围的行键,并且可以在不同的RegionServer之间迁移,以实现负载均衡。 **3. 数据压缩与缓存**:...