分布式查找过程[HBase]Region location

来源:互联网 发布:记忆宫殿软件下载 编辑:程序博客网 时间:2024/06/05 09:23

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.     }  
0 0
原创粉丝点击