客户端如何定位regionserver

2023-12-01 22:38

本文主要是介绍客户端如何定位regionserver,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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入口

Java代码   收藏代码
  1. private HRegionLocation locateRegion(final byte [] tableName,  
  2.       final byte [] row, boolean useCache)  
  3.     throws IOException {  
  4.     .......  
  5.     //检查下都应的zkTracker是否启动  
  6.       ensureZookeeperTrackers();  
  7.     //如果是-ROOT-表,则通过zk节点/hbase/root-region-server获取-ROOT-表所在的Location  
  8.       if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) {  
  9.         try {  
  10.         //通过zk的getData接口拿节点数据,此处会等待节点数据就位或者超时  
  11.           ServerName servername = this.rootRegionTracker.waitRootRegionLocation(this.rpcTimeout);  
  12.           LOG.debug("Looked up root region location, connection=" + this +  
  13.             "; serverName=" + ((servername == null)? "": servername.toString()));  
  14.           if (servername == nullreturn null;  
  15.     //返回一个拼装的HRegionLocation,因为-ROOT-表只有一个region,而且不会split  
  16.           return new HRegionLocation(HRegionInfo.ROOT_REGIONINFO,  
  17.             servername.getHostname(), servername.getPort());  
  18.         } catch (InterruptedException e) {  
  19.           Thread.currentThread().interrupt();  
  20.           return null;  
  21.         }  
  22.       }   
  23.     //如果是.META.表,则请求.META.表,这里的row其实就是请求row拼装的regionName,类似test,key1,99999999999999  
  24.     //如果没命中cache,则继续请求-ROOT-表,拿到这个row对应的.META.表的region location  
  25.       else if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) {  
  26.         return locateRegionInMeta(HConstants.ROOT_TABLE_NAME, tableName, row,  
  27.             useCache, metaRegionLock);  
  28.       }   
  29.     //如果是用户表,则请求用户表,这里的row就是key1  
  30.     //如果没命中cache,则请求.META.表,获取该row对应的region location  
  31.       else {  
  32.         // Region not in the cache - have to go to the meta RS  
  33.         return locateRegionInMeta(HConstants.META_TABLE_NAME, tableName, row,  
  34.             useCache, userRegionLock);  
  35.       }  
  36.     }  

 locateRegionInMeta方法

Java代码   收藏代码
  1. private HRegionLocation locateRegionInMeta(final byte [] parentTable,  
  2.       final byte [] tableName, final byte [] row, boolean useCache,  
  3.       Object regionLockObject)  
  4.     throws IOException {  
  5.       HRegionLocation location;  
  6.       // If we are supposed to be using the cache, look in the cache to see if  
  7.       // we already have the region.  
  8.     //先读cache,cache没有再往上找  
  9.     //注意如果rowkey的region locatin变化了,RPC的时候会失败,客户端做重试的时候useCache是false  
  10.       if (useCache) {  
  11.         location = getCachedLocation(tableName, row);  
  12.         if (location != null) {  
  13.           return location;  
  14.         }  
  15.       }  
  16.   
  17.       // build the key of the meta region we should be looking for.  
  18.       // the extra 9's on the end are necessary to allow "exact" matches  
  19.       // without knowing the precise region names.  
  20.     //先拼一个想查找的key,类似于test,key1,99999999999999  
  21.       byte [] metaKey = HRegionInfo.createRegionName(tableName, row,  
  22.         HConstants.NINES, false);  
  23.     //默认重试10次  
  24.       for (int tries = 0true; tries++) {  
  25.     //找不到  
  26.         if (tries >= numRetries) {  
  27.           throw new NoServerForRegionException("Unable to find region for "  
  28.             + Bytes.toStringBinary(row) + " after " + numRetries + " tries.");  
  29.         }  
  30.       
  31.         HRegionLocation metaLocation = null;  
  32.         try {  
  33.           // locate the root or meta region  
  34.         //递归查找parentTable  
  35.           metaLocation = locateRegion(parentTable, metaKey);  
  36.           // If null still, go around again.  
  37.           if (metaLocation == nullcontinue;  
  38.         //找到对应Region server地址之后,可以发起RPC请求了。  
  39.         //这里先生成一个RPC Proxy对象,具体RPC分析见后文  
  40.           HRegionInterface server =  
  41.             getHRegionConnection(metaLocation.getHostname(), metaLocation.getPort());  
  42.   
  43.           Result regionInfoRow = null;  
  44.           // This block guards against two threads trying to load the meta  
  45.           // region at the same time. The first will load the meta region and  
  46.           // the second will use the value that the first one found.  
  47.           synchronized (regionLockObject) {  
  48.             // If the parent table is META, we may want to pre-fetch some  
  49.             // region info into the global region cache for this table.  
  50.         //如果parentTable是.META.表,则预先获取.META.的一些数据,默认10条  
  51.             if (Bytes.equals(parentTable, HConstants.META_TABLE_NAME) &&  
  52.                 (getRegionCachePrefetch(tableName)) )  {  
  53.               prefetchRegionCache(tableName, row);  
  54.             }  
  55.   
  56.             // Check the cache again for a hit in case some other thread made the  
  57.             // same query while we were waiting on the lock. If not supposed to  
  58.             // be using the cache, delete any existing cached location so it won't  
  59.             // interfere.  
  60.             if (useCache) {  
  61.               location = getCachedLocation(tableName, row);  
  62.               if (location != null) {  
  63.                 return location;  
  64.               }  
  65.             }   
  66.         //如果不使用cache,则清除之,比如row对应的region发生了分裂,用老的location启动rpc时会抛异常,此时通过useCache=fasle重新  
  67.         //寻址,并把老的cache删掉  
  68.         else {  
  69.               deleteCachedLocation(tableName, row);  
  70.             }  
  71.   
  72.             // Query the root or meta region for the location of the meta region  
  73.         //发起RPC请求,获取<=该key的行  
  74.             regionInfoRow = server.getClosestRowBefore(  
  75.             metaLocation.getRegionInfo().getRegionName(), metaKey,  
  76.             HConstants.CATALOG_FAMILY);  
  77.           }  
  78.           if (regionInfoRow == null) {  
  79.             throw new TableNotFoundException(Bytes.toString(tableName));  
  80.           }  
  81.         //region信息,做校验,region会处于不稳定状态  
  82.           byte [] value = regionInfoRow.getValue(HConstants.CATALOG_FAMILY,  
  83.               HConstants.REGIONINFO_QUALIFIER);  
  84.           if (value == null || value.length == 0) {  
  85.             throw new IOException("HRegionInfo was null or empty in " +  
  86.               Bytes.toString(parentTable) + ", row=" + regionInfoRow);  
  87.           }  
  88.           // convert the row result into the HRegionLocation we need!  
  89.         //反序列化  
  90.           HRegionInfo regionInfo = (HRegionInfo) Writables.getWritable(  
  91.               value, new HRegionInfo());  
  92.           // possible we got a region of a different table...  
  93.         //一些校验  
  94.           if (!Bytes.equals(regionInfo.getTableName(), tableName)) {  
  95.             throw new TableNotFoundException(  
  96.                   "Table '" + Bytes.toString(tableName) + "' was not found, got: " +  
  97.                   Bytes.toString(regionInfo.getTableName()) + ".");  
  98.           }  
  99.           if (regionInfo.isSplit()) {  
  100.             throw new RegionOfflineException("the only available region for" +  
  101.               " the required row is a split parent," +  
  102.               " the daughters should be online soon: " +  
  103.               regionInfo.getRegionNameAsString());  
  104.           }  
  105.           if (regionInfo.isOffline()) {  
  106.             throw new RegionOfflineException("the region is offline, could" +  
  107.               " be caused by a disable table call: " +  
  108.               regionInfo.getRegionNameAsString());  
  109.           }  
  110.         //该region的server location  
  111.           value = regionInfoRow.getValue(HConstants.CATALOG_FAMILY,  
  112.               HConstants.SERVER_QUALIFIER);  
  113.           String hostAndPort = "";  
  114.           if (value != null) {  
  115.             hostAndPort = Bytes.toString(value);  
  116.           }  
  117.           ......  
  118.   
  119.           // Instantiate the location  
  120.           String hostname = Addressing.parseHostname(hostAndPort);  
  121.           int port = Addressing.parsePort(hostAndPort);  
  122.           location = new HRegionLocation(regionInfo, hostname, port);  
  123.         //cache之  
  124.           cacheLocation(tableName, location);  
  125.           return location;  
  126.         } catch (TableNotFoundException e) {  
  127.           // if we got this error, probably means the table just plain doesn't  
  128.           // exist. rethrow the error immediately. this should always be coming  
  129.           // from the HTable constructor.  
  130.           throw e;  
  131.         } catch (IOException e) {  
  132.           if (e instanceof RemoteException) {  
  133.             e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e);  
  134.           }  
  135.           if (tries < numRetries - 1) {  
  136.             .......  
  137.           } else {  
  138.             throw e;  
  139.           }  
  140.           // Only relocate the parent region if necessary  
  141.         //网络有问题,则重新找  
  142.           if(!(e instanceof RegionOfflineException ||  
  143.               e instanceof NoServerForRegionException)) {  
  144.             relocateRegion(parentTable, metaKey);  
  145.           }  
  146.         }  
  147.         //重试次数越多,sleep越长,interrupt则退出重试  
  148.         try{  
  149.           Thread.sleep(ConnectionUtils.getPauseTime(this.pause, tries));  
  150.         } catch (InterruptedException e) {  
  151.           Thread.currentThread().interrupt();  
  152.           throw new IOException("Giving up trying to location region in " +  
  153.             "meta: thread is interrupted.");  
  154.         }  
  155.       }  
  156.     }  

这篇关于客户端如何定位regionserver的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/442959

相关文章

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

Python FastMCP构建MCP服务端与客户端的详细步骤

《PythonFastMCP构建MCP服务端与客户端的详细步骤》MCP(Multi-ClientProtocol)是一种用于构建可扩展服务的通信协议框架,本文将使用FastMCP搭建一个支持St... 目录简介环境准备服务端实现(server.py)客户端实现(client.py)运行效果扩展方向常见问题结

C#使用MQTTnet实现服务端与客户端的通讯的示例

《C#使用MQTTnet实现服务端与客户端的通讯的示例》本文主要介绍了C#使用MQTTnet实现服务端与客户端的通讯的示例,包括协议特性、连接管理、QoS机制和安全策略,具有一定的参考价值,感兴趣的可... 目录一、MQTT 协议简介二、MQTT 协议核心特性三、MQTTNET 库的核心功能四、服务端(BR

SpringBoot快速搭建TCP服务端和客户端全过程

《SpringBoot快速搭建TCP服务端和客户端全过程》:本文主要介绍SpringBoot快速搭建TCP服务端和客户端全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录TCPServerTCPClient总结由于工作需要,研究了SpringBoot搭建TCP通信的过程

Redis客户端工具之RedisInsight的下载方式

《Redis客户端工具之RedisInsight的下载方式》RedisInsight是Redis官方提供的图形化客户端工具,下载步骤包括访问Redis官网、选择RedisInsight、下载链接、注册... 目录Redis客户端工具RedisInsight的下载一、点击进入Redis官网二、点击RedisI

使用Java实现获取客户端IP地址

《使用Java实现获取客户端IP地址》这篇文章主要为大家详细介绍了如何使用Java实现获取客户端IP地址,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 首先是获取 IP,直接上代码import org.springframework.web.context.request.Requ

Python手搓邮件发送客户端

《Python手搓邮件发送客户端》这篇文章主要为大家详细介绍了如何使用Python手搓邮件发送客户端,支持发送邮件,附件,定时发送以及个性化邮件正文,感兴趣的可以了解下... 目录1. 简介2.主要功能2.1.邮件发送功能2.2.个性签名功能2.3.定时发送功能2. 4.附件管理2.5.配置加载功能2.6.

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

SpringBoot实现websocket服务端及客户端的详细过程

《SpringBoot实现websocket服务端及客户端的详细过程》文章介绍了WebSocket通信过程、服务端和客户端的实现,以及可能遇到的问题及解决方案,感兴趣的朋友一起看看吧... 目录一、WebSocket通信过程二、服务端实现1.pom文件添加依赖2.启用Springboot对WebSocket