HBase Region在两个RegionServer出现分析

文章转自:http://punishzhou.iteye.com/blog/1264874


HBase的操作一般都是以region为粒度的,如split,compact,move等操作。因此对于每个region在集群的唯一性就需要得到保证。若region在两个regionserver中出现显然会有各种各样的bug出现。 

这里我们通过以下的分析来看看region在上吗情况下会出现分配到两个rs中。 


对于一个RS1上的Region A将其move到RS2中,调用HBaseAdmin的move操作: 

  1.创建一个到B的RegionPlan 

  2.然后unassigned Region A,即将RS1上的Region A的region关闭,主要是关闭region上每个storefile的读数据流,在这个过程中会把memstore内容刷一次磁盘 

  3.然后在RS2中open Region A,主要操作是对Region A的初始化,将A的rs地址信息更新Meta表中 


假设在move的过程中RS1 down掉了,那么master会调用servershutdownhandler来处理该事件。主要处理步骤如下:

Java代码  收藏代码
  1. public void process() throws IOException {   
  2.     final String serverName = this.hsi.getServerName();   

 
拆分日志,把regionserver的hlog按照region的不同进行拆分,分别写入各个region目录下 

Java代码  收藏代码
  1. LOG.info("Splitting logs for " + serverName);   
  2.     this.services.getMasterFileSystem().splitLog(serverName);   

 

 在master的内存中清除rs中的region和server,并返回在master的RIT队列上的该RS的online region

 

Java代码  收藏代码
  1. // Clean out anything in regions in transition.  Being conservative and   
  2.    // doing after log splitting.  Could do some states before -- OPENING?   
  3.    // OFFLINE? -- and then others after like CLOSING that depend on log   
  4.    // splitting.   
  5.    List regionsInTransition =   
  6.      this.services.getAssignmentManager().processServerShutdown(this.hsi);   

 [如该RS包含ROOT或META则需首先分配之 

Java代码  收藏代码
  1. // Assign root and meta if we were carrying them.   
  2.    if (isCarryingRoot()) { // -ROOT-   
  3.      try {   
  4.    this.services.getAssignmentManager().assignRoot();   
  5.      } catch (KeeperException e) {   
  6.        this.server.abort("In server shutdown processing, assigning root", e);   
  7.        throw new IOException("Aborting", e);   
  8.      }   
  9.    }   
  10.   
  11.    // Carrying meta?   
  12.    if (isCarryingMeta())this.services.getAssignmentManager().assignMeta();   

     
从meta表中获得RS1上的的region

Java代码  收藏代码
  1. // Wait on meta to come online; we need it to progress.   
  2.     // TODO: Best way to hold strictly here?  We should build this retry logic   
  3.     //       into the MetaReader operations themselves.   
  4.     NavigableMap hris = null;   
  5.     while (!this.server.isStopped()) {   
  6.       try {   
  7.         this.server.getCatalogTracker().waitForMeta();   
  8.         hris = MetaReader.getServerUserRegions(this.server.getCatalogTracker(),   
  9.             this.hsi);   
  10.         break;   
  11.       } catch (InterruptedException e) {   
  12.         Thread.currentThread().interrupt();   
  13.         throw new IOException("Interrupted", e);   
  14.       } catch (IOException ioe) {   
  15.         LOG.info("Received exception accessing META during server shutdown of " +   
  16.             serverName + ", retrying META read");   
  17.       }   
  18.     }   

 
移除RIT中状态为Closing或是PendingClose的region,得到的就是需要重新分配的regions[
 

Java代码  收藏代码
  1. // Skip regions that were in transition unless CLOSING or PENDING_CLOSE   
  2.    for (RegionState rit : regionsInTransition) {   
  3.      if (!rit.isClosing() && !rit.isPendingClose()) {   
  4.        LOG.debug("Removed " + rit.getRegion().getRegionNameAsString() +   
  5.          " from list of regions to assign because in RIT");   
  6.        hris.remove(rit.getRegion());   
  7.      }   
  8.    }   

     
我们可以看到,在move过程中,若region尚未上线,此时master的RIT队列中region的状态是OFFLINE,而该region在master的角度来看是offline的,然而在severshutdown的处理中认为该region是要重新分配的。若在此时region在RS2上线了,那么而master依然要对该region进行分配这就导致了region的两次分配过程[code="java"]    

Java代码  收藏代码
  1. LOG.info("Reassigning " + hris.size() + " region(s) that " + serverName +   
  2.       " was carrying (skipping " + regionsInTransition.size() +   
  3.       " regions(s) that are already in transition)");   
  4.   
  5.     // Iterate regions that were on this server and assign them   
  6.     for (Map.Entry e: hris.entrySet()) {   
  7.       if (processDeadRegion(e.getKey(), e.getValue(),   
  8.           this.services.getAssignmentManager(),   
  9.           this.server.getCatalogTracker())) {   
  10.         this.services.getAssignmentManager().assign(e.getKey(), true);   
  11.       }   
  12.     }   
  13.     this.deadServers.finish(serverName);   
  14.     LOG.info("Finished processing of shutdown of " + serverName);   
  15.   }   

  

整个过程起始是在rs shundown以后master需要对rs上的region重新assign到其他rs中去,但是在需要assign的region的序曲上出现了一些问题,将在master中已经offline的但是依然在RIT队列中的region重新分配,由于这些region可能已经在其他地方正在分配,但是还没有上线。当master开始assign region的时候此时region上线了,master依旧会继续分配重而导致region的两次分配

展开阅读全文

没有更多推荐了,返回首页