HBase學(xué)習(xí) - HRegion Split

本文基于hbase-1.3.0源碼

1. 前言

本文主要介紹在cluster模式下(并且使用zookeeper協(xié)調(diào))region發(fā)生split的整個(gè)過(guò)程。這其中會(huì)涉及到HMaster和HRegionSever。

2. split發(fā)生的時(shí)機(jī)

2.1 不能split的場(chǎng)景

  1. 當(dāng)前region包含reference file(也就是當(dāng)前region從另外一個(gè)region split出來(lái)之后蒙挑,依然通過(guò)reference file持有父region hfile的一個(gè)區(qū)間(上或下半部分)) 窃肠,compact操作會(huì)導(dǎo)致reference file被刪除蓝谨,因此若干次minor compact或則一次major compact之后reference file就會(huì)被刪除矢沿。
  2. 當(dāng)前region正處在recovering狀態(tài)削樊。
  3. meta table以及namespace table的region不可以split豁生。
  4. 未滿足split policy(見(jiàn)2.2)
  5. 此外由于split之前需要獲取table的read lock,所以此時(shí)如果在修改table的meta信息的話(持有write lock)也會(huì)導(dǎo)致split阻塞漫贞。
  6. 當(dāng)前regionserver的region數(shù)量已經(jīng)達(dá)到了上限甸箱。由hbase.regionserver.regionSplitLimit配置決定

1,2迅脐,3芍殖,4都由HRegion#checkSplit檢查,split需要一個(gè)midKey作為切分點(diǎn)仪际,checkSplit返回值就是midKey围小。5下文會(huì)提到昵骤。

2.2 split policy

split policy決定了region 是否達(dá)到split條件树碱,以及splitKey。表元數(shù)據(jù)'SPLIT_POLICY'配置policy策略变秦。未配置的情況下使用hbase.regionserver.region.split.policy配置的值成榜,默認(rèn)使用IncreasingToUpperBoundRegionSplitPolicy策略。

下面介紹的所有policy類都繼承自RegionSplitPolicy蹦玫, 它有兩個(gè)重要的方法:1, shouldSplit返回true|false決定是否可以split; 2, getSplitPoint返回進(jìn)行split的點(diǎn)(一個(gè)row值赎婚,將所有row劃成兩段)

  1. ConstantSizeRegionSplitPolicy

    這種策略下,只要HRegion的任何一個(gè)HStore的size達(dá)到一個(gè)固定大小之后樱溉,就會(huì)發(fā)生split挣输。關(guān)于這個(gè)大小的設(shè)置遵循一下規(guī)則(大小為desiredMaxFileSize):

    1. 將desiredMaxFileSize設(shè)置為table的元數(shù)據(jù)MAX_FILESIZE的大小,沒(méi)有該元數(shù)據(jù)就從配置文件中讀取hbase.hregion.max.filesize的值(當(dāng)前版本默認(rèn)為10G)
    2. 1中的值不是一個(gè)嚴(yán)格的值福贞,還有一個(gè)抖動(dòng)hbase.hregion.max.filesize.jitter
  2. IncreasingToUpperBoundRegionSplitPolicy

    這種策略下撩嚼,和1不同的是size的選取。這種策略size和當(dāng)前RegionServer上屬于表t1的region個(gè)數(shù)有關(guān)(假設(shè)個(gè)數(shù)Rn)挖帘。

    1. Rn =0 || Rn > 100完丽,size的選取和1一樣。
    2. 不符合1的情況下拇舀,此時(shí)有一個(gè)‘initialSize’. initialSize 的大小由hbase.increasing.policy.initial.size逻族,如果該配置未設(shè)置或者設(shè)置成負(fù)數(shù),則initialSize被設(shè)置為2 * MEMSTORE_FLUSHSIZE(這是table的元數(shù)據(jù))骄崩,如果table沒(méi)有該元數(shù)據(jù)或則initialSize依然小于0聘鳞, initialSize被設(shè)置為2 * "hbase.hregion.memstore.flush.size(該配置默認(rèn)值為128M)
    3. 有了initialSize值后薄辅,size被設(shè)置為min(ConstantSizeRegionSplitPolicy規(guī)則下的size, Rn * Rn * Rn * intialSize)
  3. KeyPrefixRegionSplitPolicy

    這種策略直接繼承至IncreasingToUpperBoundRegionSplitPolicy,所以判斷是否應(yīng)該split的條件和它一樣抠璃,但是splitKey的選取不一樣长搀。

    這種策略中有一個(gè)‘prefixLength’, 有table元數(shù)據(jù)KeyPrefixRegionSplitPolicy.prefix_length決定。它在拿到splitKey之后鸡典,會(huì)截取splitKey的前prefixLength位作為新的prefixKey源请。例如原splitKey為"1234567890",截取5位變成"1234500000", 這樣保證了比"1234500000"小的在一個(gè)region里彻况,比他大的在另一個(gè)region里谁尸,也就是說(shuō)擁有公共前綴的key是不會(huì)被split到不同的region中。

  4. DelimitedKeyPrefixRegionSplitPolicy

    這種策略繼承IncreasingToUpperBoundRegionSplitPolicy纽甘,所以判斷是否應(yīng)該split的條件和它一樣良蛮,但是splitKey的選取不一樣。

    這種策略下有一個(gè)分割符‘delimiter’, 從table元數(shù)據(jù)DelimitedKeyPrefixRegionSplitPolicy.delimiter獲取悍赢,它在拿到原始的splitKey之后决瞳,找到delimiter最早的出現(xiàn)位置,然后截取該位置之前的前綴作為新的splitKey左权。

    ?

2.3 region split時(shí)機(jī):

  1. 內(nèi)存中的數(shù)據(jù)(HMemStore)flush到磁盤(pán)時(shí)皮胡,判斷是否需要split。
  2. 用戶通過(guò)api或者shell觸發(fā)split(RsRpcServices#splitRegion)赏迟。
  3. compaction導(dǎo)致split屡贺。

1,2,3都需要滿足split policy.

2.4 與split相關(guān)的配置參數(shù)

下文都假設(shè)配置zookeeper.znode.parent采用了默認(rèn)值‘hbase’,zookeeper上所有的node都會(huì)以此配置值作為根路徑锌杀。

  1. zookeeper.znode.unassigned 默認(rèn)值為“region-in-transition”甩栈。
    HMaster啟動(dòng)時(shí)會(huì)根據(jù)該配置的值在zookeeper上創(chuàng)建路徑'/hbase/region-in-transition', 發(fā)生split的的HRegion會(huì)在此路徑下創(chuàng)建一個(gè)以region name為名的新節(jié)點(diǎn),HMaster 監(jiān)聽(tīng)該節(jié)點(diǎn)糕再,因此知道正在split的region量没。

  2. hbase.regionserver.regionSplitLimit,默認(rèn)值1000

    它規(guī)定了一個(gè)region server上的最多容納的region的個(gè)數(shù)突想,超過(guò)這個(gè)值就不會(huì)再split殴蹄。

  3. hbase.regionserver.thread.split用來(lái)split的線程池個(gè)數(shù)。默認(rèn)為1.

3. split過(guò)程

3.1 基本概念

  1. HRegionInfo

    記錄的region信息有:

    1. tableName, 即region所屬table
    2. startKey, region 其實(shí)row key, 第一個(gè)region為空
    3. regionId, region 創(chuàng)建時(shí)的timestamp
    4. replicaId, region備份的情況下蒿柳,主region 為0饶套,其他依次遞增
    5. encodedName, 前4項(xiàng)的32位md5值
    以上5項(xiàng)構(gòu)成了region name,下面是'.meta.'這張表中ROW 值(meta表row值即region name):
    t1,,1500458612081.a33bb6a3c49157ab43876540d083e5f1
    t1表名垒探,startKey是空的妓蛮,1500458612081是regionId,沒(méi)有replicaId圾叼,即沒(méi)有備份蛤克,后面是md5值捺癞。
    除上述以外,HRegionInfo還包括:
    endKey, 開(kāi)區(qū)間构挤,為空表示region是最后一個(gè)region
    split,是否region正在split
    offline,region是否下線髓介,split之后的region應(yīng)該下線
    
  2. region split過(guò)程中的狀態(tài)

    public enum SplitTransactionPhase {
        /**
         * Started
         */
        STARTED,
        /**
         * Prepared
         */
        PREPARED,
        /**
         * Before preSplit coprocessor hook
         */
        BEFORE_PRE_SPLIT_HOOK,
        /**
         * After preSplit coprocessor hook
         */
        AFTER_PRE_SPLIT_HOOK,
        /**
         * Set region as in transition, set it into SPLITTING state.
         */
        SET_SPLITTING,
        /**
         * We created the temporary split data directory.
         */
        CREATE_SPLIT_DIR,
        /**
         * Closed the parent region.
         */
        CLOSED_PARENT_REGION,
        /**
         * The parent has been taken out of the server's online regions list.
         */
        OFFLINED_PARENT,
        /**
         * Started in on creation of the first daughter region.
         */
        STARTED_REGION_A_CREATION,
        /**
         * Started in on the creation of the second daughter region.
         */
        STARTED_REGION_B_CREATION,
        /**
         * Opened the first daughter region
         */
        OPENED_REGION_A,
        /**
         * Opened the second daughter region
         */
        OPENED_REGION_B,
        /**
         * Point of no return.
         * If we got here, then transaction is not recoverable other than by
         * crashing out the regionserver.
         */
        PONR,
        /**
         * Before postSplit coprocessor hook
         */
        BEFORE_POST_SPLIT_HOOK,
        /**
         * After postSplit coprocessor hook
         */
        AFTER_POST_SPLIT_HOOK,
        /**
         * Completed
         */
        COMPLETED
      }
    

    region split在hbase里作為一個(gè)事務(wù)處理,整個(gè)split過(guò)程由SplitTransactionImpl(實(shí)現(xiàn)了Runnable接口)包裝筋现,上面枚舉了這一事務(wù)執(zhí)行過(guò)程中會(huì)經(jīng)歷的狀態(tài)變化唐础。在PONR狀態(tài)之前發(fā)生fail,都會(huì)回滾矾飞。

3.2 HRegionServer端

hbase學(xué)習(xí) - HRegionServer啟動(dòng)一文2.2節(jié)中提到hregion server會(huì)啟動(dòng)CompactionSplitThread專門(mén)負(fù)責(zé)split一膨,compact,merge洒沦。CompactionSplitThread有三個(gè)重載的requestSplit方法如下:

1. public synchronized boolean requestSplit(final Region r) 
2. public synchronized void requestSplit(final Region r, byte[] midKey)
3. public synchronized void requestSplit(final Region r, byte[] midKey, User user) {
    if (midKey == null) {
      LOG.debug("Region " + r.getRegionInfo().getRegionNameAsString() +
        " not splittable because midkey=null");
      if (((HRegion)r).shouldForceSplit()) {
        ((HRegion)r).clearSplit();
      }
      return;
    }
    try {
      //splits線程池執(zhí)行SplitRequest
      this.splits.execute(new SplitRequest(r, midKey, this.server, user));
      if (LOG.isDebugEnabled()) {
        LOG.debug("Split requested for " + r + ".  " + this);
      }
    } catch (RejectedExecutionException ree) {
      LOG.info("Could not execute split for " + r, ree);
    }
  }
}
這三個(gè)方法

1調(diào)用2豹绪, 2調(diào)用3。 其中方法1在MemStoreFlusher和CompactSplitThread#compaction調(diào)用申眼,他會(huì)使用split policy的checkSplit(返回null或則midKey)檢查是否可以split瞒津。 方法3由RsRpcServices(rpc服務(wù))調(diào)用,盡管3里面沒(méi)有調(diào)用split policy的checkSplit括尸,但是3的調(diào)用澤RsRpcService#splitRegion在傳midKey參數(shù)時(shí)使用了checkSplit巷蚪,因此不滿足的policy時(shí)midKey為null,依然不能split姻氨。

1. SplitRequest

SplitRequest實(shí)現(xiàn)了Runnable接口钓辆,主要邏輯在其方法doSplitting中:

private void doSplitting(User user) {
    boolean success = false;
    server.metricsRegionServer.incrSplitRequest();
    long startTime = EnvironmentEdgeManager.currentTime();
    // 真正的split的主要過(guò)程都封裝在SplitTransactionImpl中完成,包含了split過(guò)程中的狀態(tài)轉(zhuǎn)移.
    // 參考3.2 -1 split中會(huì)出現(xiàn)的狀態(tài)肴焊。
    SplitTransactionImpl st = new SplitTransactionImpl(parent, midKey);
    try {
      // 獲取table lock,獲取的是read lock功戚,因此不會(huì)影響table的其他region的split娶眷,compact等操作
      // 但是由于任何試圖修改table schema的操作需要獲取write lock,因此會(huì)被阻塞啸臀。
      tableLock =    
               server.getTableLockManager().readLock(parent.getTableDesc().getTableName()
          , "SPLIT_REGION:" + parent.getRegionInfo().getRegionNameAsString());
      try {
        tableLock.acquire();
      } catch (IOException ex) {
        tableLock = null;
        throw ex;
      }

      
      if (!st.prepare()) return;
      try {
        st.execute(this.server, this.server, user);
        success = true;
      } catch (Exception e) {
        if (this.server.isStopping() || this.server.isStopped()) {
          LOG.info(
              "Skip rollback/cleanup of failed split of "
                  + parent.getRegionInfo().getRegionNameAsString() + " because server is"
                  + (this.server.isStopping() ? " stopping" : " stopped"), e);
          return;
        }
        if (e instanceof DroppedSnapshotException) {
          server.abort("Replay of WAL required. Forcing server shutdown", e);
          return;
        }
        try {
          LOG.info("Running rollback/cleanup of failed split of " +
            parent.getRegionInfo().getRegionNameAsString() + "; " + e.getMessage(), e);
          // split過(guò)程中出現(xiàn)錯(cuò)誤届宠,都會(huì)嘗試rollback,具體細(xì)節(jié)將會(huì)在split過(guò)程講完后講解乘粒。
          if (st.rollback(this.server, this.server)) {
            LOG.info("Successful rollback of failed split of " +
              parent.getRegionInfo().getRegionNameAsString());
          } else {
            this.server.abort("Abort; we got an error after point-of-no-return");
          }
        } catch (RuntimeException ee) {
          String msg = "Failed rollback of failed split of " +
            parent.getRegionInfo().getRegionNameAsString() + " -- aborting server";
          // If failed rollback, kill this server to avoid having a hole in table.
          LOG.info(msg, ee);
          this.server.abort(msg + " -- Cause: " + ee.getMessage());
        }
        return;
      }
    } catch (IOException ex) {
      LOG.error("Split failed " + this, RemoteExceptionHandler.checkIOException(ex));
      server.checkFileSystem();
    } finally {
      if (this.parent.getCoprocessorHost() != null) {
        try {
          this.parent.getCoprocessorHost().postCompleteSplit();
        } catch (IOException io) {
          LOG.error("Split failed " + this,
              RemoteExceptionHandler.checkIOException(io));
        }
      }
      
      // rpc發(fā)起的split會(huì)設(shè)置forceSplit=true豌注,完成split之后需要?dú)w位為false。
      if (parent.shouldForceSplit()) {
        parent.clearSplit();
      }
      //釋放 read lock
      releaseTableLock();
      ...
  }

核心邏輯在SplitTransactionImpl中完成灯萍,調(diào)用器prepare和execute完成轧铁。doSplitting中完成table的readlock獲取和釋放,以及出現(xiàn)異常后rollback旦棉。

2. SplitTransactionImpl

在SplitTransacntionImple中完成split全部過(guò)程齿风,他有一些重要成員:

  • parent药薯, 等待split的HRegion
  • hri_a, hri_b, parent分裂成這兩個(gè)
  • currentPhase救斑, 當(dāng)前split所處狀態(tài)童本,參考3.1 - 2,初始狀態(tài)為STARTED脸候。
  • private final List<JournalEntry> journal, 當(dāng)前所有已經(jīng)完成的狀態(tài)列表
  • splitRow穷娱,以這個(gè)值降parent分裂成兩個(gè)。

上面1中代碼运沦,先是調(diào)用了SplitTransactionImpl#prepare主要完成一項(xiàng)工作:

  • 拿到splitKey鄙煤,parent的startKey和endKey,創(chuàng)建出兩個(gè)HRegionInfo實(shí)例hri_a, hri_b茶袒,它們分別擁有的rowKey區(qū)間[startKey, splitRow), [splitRow, endKey)
  • 將當(dāng)前狀態(tài)currentPhase又STARTED轉(zhuǎn)換成PREPARED梯刚。

接下來(lái)時(shí)SplitTransactionImpl#execute方法的調(diào)用,剩下split的所有過(guò)程以及涉及到的狀態(tài)變化都是在這里完成薪寓,這里面調(diào)用鏈比較復(fù)雜亡资,代碼較多,下面是調(diào)用鏈的核心點(diǎn)以及狀態(tài)變化(大寫(xiě)的表示狀態(tài)):

execute()  -->  SplitTransactionImpl# createDaughters 
                      |
                      v
          (PREPARED >> BEFORE_PRE_SPLIT_HOOK)
                      |
                      v
                 RegionCoprocessorHost # preSplit()
                      |
                      v
          (BEFORE_PRE_SPLIT_HOOK >> AFTER_PRE_SPLIT_HOOK)
                      |
                      |-----------> SplitTransactionImpl#stepsBeforePONR()
                                               |
                                               v
               ZkSplitTransactionCordination # startSplitTransaction  
                [注:startSplitTransaction在zk的/hbase/region-in-transition
                 節(jié)點(diǎn)下創(chuàng)建一個(gè)parent的encodedName的臨時(shí)節(jié)點(diǎn)向叉, 節(jié)點(diǎn)的
                data包含hri_a, hri_b锥腻;
              以及狀態(tài)'RS_ZK_REQUEST_REGION_SPLIT'枚舉值(10). ]
                                              |
                                            v
                  (AFTER_PRE_SPLIT_HOOK >> SET_SPLITTING)
                                             |
                                            v
            ZkSplitTransactionCordination # waitForSplitTransaction
    [注: 上一步創(chuàng)建的節(jié)點(diǎn)master被master監(jiān)聽(tīng)到后將data里的狀態(tài)修改為'RS_ZK_REGION_SPLITTING'枚舉值(5),
        此方法等待master修改完成后返回]
                                            |
                                            v           
                                                            
        this.parent.getRegionFileSystem().createSplitsDir();
             [注:在hdfs上table下面 parent region目錄下面創(chuàng)建
             一個(gè)'.splits'的目錄母谎,例如這是筆者defualt.t1表一個(gè)region
              encodedName為a33...的路徑的目錄:  
            /hbase/data/default/t1/a33bb6a3c49157ab43876540d083e5f1]
                                              |
                                               v
                  (SET_SPLITTING >> CREATE_SPLIT_DIR)
                                               |
                                               -> parent.close(false)
                                                  |
                                       coprocessorHost#preClose
                                                  |
                                  [注:closing設(shè)為true
                                   region不再提供服務(wù),
                                 flush memstore,close all HStore]
                                                  |
                                coprocessorHost#postClose
                                              |<--|
                                              |
                             (CREATE_SPLIT_DIR >> CLOSED_PARENT_REGION)
                                              |
                       services.removeFromOnlineRegions(this.parent, null);
                             [注:service即RegionServerService
                               此時(shí)parent已經(jīng)是closed狀態(tài)瘦黑,不再提供服務(wù),
                                移除parent奇唤。]
                                              |
                                  ( CLOSED_PARENT_REGION >> OFFLINED_PARENT )
                                              |
                                              |--> SplitTransactionImpl # splitStoreFiles
                                                        |
                                             [注:Region對(duì)應(yīng)table所有了column family幸斥,每一個(gè)colume family下有HFile,每個(gè)HFile都需要split咬扇。
                              下文假設(shè)分裂的HFile屬于列族cf-n甲葬,分裂的HFile文件名了file-n, 被分裂的parent region的encoded name為r-n,b_name, a_name表示分裂后上下兩個(gè)region的encoded name懈贺。
                                  需要split的HFile包裝成StoreFileSplitter(實(shí)現(xiàn)Callable)提交線程池執(zhí)行经窖。
                                   對(duì)于需要split的HFile,分裂成上下兩部分梭灿,執(zhí)行如下:
                                   1.  創(chuàng)建下半部分引用文件(Reference)画侣,在'.splits'下創(chuàng)建'a_name/cf-n'路徑 ,在cf-n路徑下創(chuàng)建名為file-n.r-n的文件堡妒。
                                   并在文件中寫(xiě)入bottom, splitKey信息(二進(jìn)制格式)配乱,表示它引用split前hfile的下半部分.
                                   2.  創(chuàng)建上半部引用,在'.splits'下創(chuàng)建'b_name/cf-n'路徑 ,在cf-n路徑下創(chuàng)建名為file-n.r-n的文件。
                                       并在文件中寫(xiě)入top, splitKey信息(二進(jìn)制格式)宪卿,表示它引用split前hfile的上半部分的诵。
                                              |<--------|
                                              |
                                              v
                                          ((OFFLINE_PARENT >> STARTED_REGION_A_CREATION))
                                              [注: 標(biāo)記成開(kāi)始創(chuàng)建hri_a這個(gè)region,上一步雖然已完成parent的所有的hfile的split,
但是佑钾,分裂后的region:a,b各自的hfile都在parent_region_encode_name/.splits/a_encoded_name和b_encoded_name下.
需要移動(dòng)到正確的目錄下西疤,也就是table_name/encoded_region_name/ 這個(gè)目錄。]
                                              |
                                       HRegion# parent.createDaughterRegionFromSplits(this.hri_a)
                                              [注:首先移動(dòng)region a, region a持有parent region的下部分休溶,步驟如下(假設(shè)parent region所屬表的目錄是/hbase/data/default/table-n):
                                                1.  創(chuàng)建/hbase/data/default/table-n/a_encoded_name路徑   
                                                2. 在上面路徑下創(chuàng)建.regioninfo文件代赁,寫(xiě)入a的RegionInfo二進(jìn)制信息.
                                                3. 通過(guò)hdfs的rename調(diào)用將.splits/a_encoded_name所有文件移動(dòng)到1中的路徑下。至此兽掰,region_a創(chuàng)建完芭碍,此時(shí)a不可用,因?yàn)閙aster還沒(méi)有把新的region調(diào)度到某個(gè)region server上孽尽,metatable也還沒(méi)有region a的信息窖壕。]
                                              |
                               ((STARTED_REGION_A_CREATION  >> STARTED_REGION_B_CREATION))
                                               [注: 省略region b的過(guò)程,和a是一樣的]
                    |------------------------ |
                    |                                        
                    v
    RegionCoprocessorHost # preSplitBeforePONR
                    |
                    v
     ((STARTED_REGION_B_CREATION  >> PONR))
  [到這一步杉女,region a瞻讽,b已經(jīng)的hfile已經(jīng)寫(xiě)到hdfs中,但是meta table還沒(méi)更新熏挎,依然是parent的速勇,a揪惦,b也還沒(méi)有被指派到RegionServer涧窒。
   PONR之后發(fā)生任何失敗異常郊丛,都不會(huì)做rollback枢步,而是直接關(guān)閉當(dāng)前region server。
  HMaster檢查到region server的失敗契沫,會(huì)做失敗處理钱床,split會(huì)繼續(xù)示罗,meta table會(huì)更新猴蹂,region a院溺,b會(huì)被正確管理。]
                    |
                    v
        MetaTableAccessor.splitRegion()
      [注:下線parent磅轻,為parent構(gòu)建一個(gè)meta table的Put操作如下:  
        - 將parent的region Info標(biāo)記為offline=true && split=true(meta中rowkey是regionname,參考3.1 - 1)逐虚,修改的列為info:regioninfo
        - 增加兩列info:splitA和info:splitB聋溜,value是a,b的regioninfo 
       在meta table中加入region a叭爱, b的信息撮躁,為a,b構(gòu)建Put操作买雾,每一個(gè)在meta table中的region至少包含這些信息(列):
           1. info:server把曼,region 所在server杨帽。
           2. info:startcode, region所在region server的startcode,是region server啟動(dòng)的時(shí)間戳嗤军。
           3. info:seqnumDuringOpen, 新region為1 注盈。
           metatable更新成功后,region a叙赚,b還沒(méi)有在region server上打開(kāi)老客,所以還不能被訪問(wèn)。]
|-------------------|
|
v                   
parent.getCoprocessorHost().preSplitAfterPONR();
 [調(diào)用注冊(cè)在parent region上的coprocessor]
|
|--------------->stepsAfterPONR()
            [注:并行執(zhí)行兩個(gè)線程打開(kāi)a震叮, b兩個(gè)region(調(diào)用HRegion#openRegion),此時(shí)region a,b就可以被訪問(wèn)了胧砰。
            通知master完成region的split,即將zk上/hbase/region-in-transition下encoded_parent_name的值改成'RS_ZK_REGION_SPLIT' 枚舉值6.]
                        |
   ((PONR  >> BEFORE_POST_SPLIT_HOOK))
                        |
          parent.getCoprocessorHost().postSplit
      [調(diào)用parent region注冊(cè)的coprocessor]
                        |
 ((BEFORE_POST_SPLIT_HOOK  >> AFTER_POST_SPLIT_HOOK))
|-----------------------|
|
v
((AFTER_POST_SPLIT_HOOK >> COMPLETED))
[至此苇瓣,region server端完成]
                                      

3.3 HMaster端

這里開(kāi)始是split過(guò)程中HMaster端做的一些事情尉间。回顧3.2 -2 中split過(guò)程中哪些需要和HMaster交互:

  1. 調(diào)用ZkSplitTransactionCordination # waitForSplitTransaction
    等待HMaster將zk的/hbase/region-in-transition/{encoded-regionname}的data中狀態(tài)設(shè)置由‘ RS_ZK_REQUEST_REGION_SPLIT’改變成‘ RS_ZK_REGION_SPLITTING’击罪。

  2. 調(diào)用stepsAfterPONR()過(guò)程中哲嘲,HRegionServer端將/hbase/region-in-transition/{encoded-regionname}的data中狀態(tài)設(shè)置由'RS_ZK_REGION_SPLITTING'變?yōu)椤甊S_ZK_REGION_SPLIT’,由于HMaster會(huì)監(jiān)控這幾zk節(jié)點(diǎn),所以HMaster也會(huì)做出處理外邓。

先說(shuō)說(shuō)1撤蚊, HMaster通過(guò)AssignmentManager監(jiān)控/hbase/region-in-transition節(jié)點(diǎn)的改變(可以參考文章HMaster啟動(dòng)), AssignmentManager通過(guò)如下的調(diào)用:

nodeCreated -> handleAssignmentEvent -> handleRegion -> handleRegionSplitting 

進(jìn)入到方法‘handleRegionSplitting’處理RS_ZK_REQUEST_REGION_SPLIT狀態(tài)损话,它所在的處理就是將RS_ZK_REQUEST_REGION_SPLIT狀態(tài)改變成RS_ZK_REGION_SPLITTING使得ZkSplitTransactionCordination # waitForSplitTransaction能夠返回繼續(xù)處理split侦啸。

再是2,同樣是在AssignmentManager #handleRegionSplitting中處理丧枪,到狀態(tài)‘ RS_ZK_REGION_SPLIT’說(shuō)明split已經(jīng)完成了光涂,這時(shí)會(huì)處理的是parent以及a,b的replicas拧烦。它需要unassign parent的所有replicas忘闻,然后建立a,b的replicas恋博,完成replicas region的assign齐佳。在方法的最后刪除zk /hbase/region-in-transition/{encoded-parent-region-name}這個(gè)節(jié)點(diǎn).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市债沮,隨后出現(xiàn)的幾起案子炼吴,更是在濱河造成了極大的恐慌,老刑警劉巖疫衩,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硅蹦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)童芹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)涮瞻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人假褪,你說(shuō)我怎么就攤上這事署咽。” “怎么了嗜价?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵艇抠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我久锥,道長(zhǎng)家淤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任瑟由,我火速辦了婚禮絮重,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘歹苦。我一直安慰自己青伤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布殴瘦。 她就那樣靜靜地躺著狠角,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚪腋。 梳的紋絲不亂的頭發(fā)上丰歌,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音屉凯,去河邊找鬼立帖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛悠砚,可吹牛的內(nèi)容都是我干的晓勇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼灌旧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼绑咱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起枢泰,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤羡玛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后宗苍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年讳窟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了让歼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丽啡,死狀恐怖谋右,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情补箍,我是刑警寧澤改执,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站坑雅,受9級(jí)特大地震影響辈挂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜裹粤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一终蒂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遥诉,春花似錦拇泣、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至苞笨,卻和暖如春债朵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猫缭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工葱弟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人猜丹。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓芝加,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親射窒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子藏杖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容