HBase原子性保證

來源:互聯網
上載者:User

標籤:style   blog   http   java   color   使用   

HBase提供基於單 資料操作的原子性保證

即:對同一行的變更操作(包括針對一列/多列/多column family的操作),要麼完全成功,要麼完全失敗,不會有其他狀態
樣本:
A用戶端針對rowkey=10的行發起操作:dim1:a = 1  dim2:b=1
B用戶端針對rowkey=10的行發起操作:dim1:a = 2  dim2:b=2
dim1、dim2為column family, a、b為column

A用戶端和B用戶端同時發起請求,最終rowkey=10的行各個列的值可能是dim1:a = 1  dim2:b=1,也可能是dim1:a = 2  dim2:b=2
但絕對不會是dim1:a = 1  dim2:b=2

HBase基於行鎖來保證單行操作的原子性,可以看下HRegion put的代碼(base: HBase 0.94.20)::
org.apache.hadoop.hbase.regionserver.HRegion:
  /**   * @param put   * @param lockid   * @param writeToWAL   * @throws IOException   * @deprecated row locks (lockId) held outside the extent of the operation are deprecated.   */  public void put(Put put, Integer lockid, boolean writeToWAL)  throws IOException {    checkReadOnly();    // Do a rough check that we have resources to accept a write.  The check is    // 'rough' in that between the resource check and the call to obtain a    // read lock, resources may run out.  For now, the thought is that this    // will be extremely rare; we'll deal with it when it happens.    checkResources();    startRegionOperation();    this.writeRequestsCount.increment();    this.opMetrics.setWriteRequestCountMetrics(this.writeRequestsCount.get());    try {      // We obtain a per-row lock, so other clients will block while one client      // performs an update. The read lock is released by the client calling      // #commit or #abort or if the HRegionServer lease on the lock expires.      // See HRegionServer#RegionListener for how the expire on HRegionServer      // invokes a HRegion#abort.      byte [] row = put.getRow();      // If we did not pass an existing row lock, obtain a new one      Integer lid = getLock(lockid, row, true);      try {        // All edits for the given row (across all column families) must happen atomically.        internalPut(put, put.getClusterId(), writeToWAL);      } finally {        if(lockid == null) releaseRowLock(lid);      }    } finally {      closeRegionOperation();    }  }
getLock調用了internalObtainRowLock:
 private Integer internalObtainRowLock(final HashedBytes rowKey, boolean waitForLock)      throws IOException {    checkRow(rowKey.getBytes(), "row lock");    startRegionOperation();    try {      CountDownLatch rowLatch = new CountDownLatch(1);      // loop until we acquire the row lock (unless !waitForLock)      while (true) {        CountDownLatch existingLatch = lockedRows.putIfAbsent(rowKey, rowLatch);        if (existingLatch == null) {          break;        } else {          // row already locked          if (!waitForLock) {            return null;          }          try {            if (!existingLatch.await(this.rowLockWaitDuration,                            TimeUnit.MILLISECONDS)) {              throw new IOException("Timed out on getting lock for row=" + rowKey);            }          } catch (InterruptedException ie) {            // Empty          }        }      }      // loop until we generate an unused lock id      while (true) {        Integer lockId = lockIdGenerator.incrementAndGet();        HashedBytes existingRowKey = lockIds.putIfAbsent(lockId, rowKey);        if (existingRowKey == null) {          return lockId;        } else {          // lockId already in use, jump generator to a new spot          lockIdGenerator.set(rand.nextInt());        }      }    } finally {      closeRegionOperation();    }  }
HBase行鎖的實現細節推薦下:hbase源碼解析之行鎖  

HBase也提供API(lockRow/unlockRow)顯示的擷取行鎖,但不推薦使用。原因是兩個用戶端很可能在擁有對方請求的鎖時,又同時請求對方已擁有的鎖,這樣便形成了死結,在鎖逾時前,兩個被阻塞的用戶端都會佔用一個服務端的處理線程,而伺服器線程是非常稀缺的資源

HBase提供了幾個特別的原子操作介面:
 checkAndPut/checkAndDelete/increment/append,這幾個介面非常有用,內部實現也是基於行鎖
checkAndPut/checkAndDelete內部調用程式碼片段:
      // Lock row      Integer lid = getLock(lockId, get.getRow(), true);      ......      // get and compare      try {        result = get(get, false);        ......        //If matches put the new put or delete the new delete        if (matches) {          if (isPut) {            internalPut(((Put) w), HConstants.DEFAULT_CLUSTER_ID, writeToWAL);          } else {            Delete d = (Delete)w;            prepareDelete(d);            internalDelete(d, HConstants.DEFAULT_CLUSTER_ID, writeToWAL);          }          return true;        }        return false;      } finally {        // release lock        if(lockId == null) releaseRowLock(lid);      }
實現邏輯:加鎖=>get=>比較=>put/delete

checkAndPut在實際應用中非常有價值,我們線上產生Dpid的項目,多個用戶端會並行產生DPID,如果有一個用戶端已經產生了一個DPID,則其他用戶端不能產生新的DPID,只能擷取該DPID
程式碼片段:

ret = hbaseUse.checkAndPut("bi.dpdim_mac_dpid_mapping", mac, "dim","dpid", null, dpid);if(false == ret){String retDpid = hbaseUse.query("bi.dpdim_mac_dpid_mapping", mac, "dim", "dpid");if(!retDpid.equals(ABNORMAL)){return retDpid;}}else{columnList.add("mac");valueList.add(mac);}

checkAndPut詳細試用可以參考: HBaseEveryDay_Atomic_compare_and_set  

Reference:
HBase - Apache HBase (TM) ACID Properties
hbase源碼解析之行鎖  
HBase權威指南
HBaseEveryDay_Atomic_compare_and_set  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.