hbase的行鎖與多版本併發控制(MVCC)

參考:http://www.rigongyizu.com/hbase-row-lock-and-multiversion-concurrency-control/ 算法

 

MVCC (Multiversion Concurrency Control),即多版本併發控制技術,它使得大部分支持行鎖的事務引擎,再也不單純的使用行鎖來進行數據庫的併發控制,取而代之的是,把數據庫的行鎖與行的多個版本結合起來,只須要很小的開銷,就能夠實現非鎖定讀,從而大大提升數據庫系統的併發性能。 數據庫

HBase正是經過行鎖+MVCC保證了高效的併發讀寫。 apache

爲何須要併發控制

HBase系統自己只能保證單行的ACID特性。ACID的含義是: 併發

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔離性(Isolation)
  • 持久性(Durability)

傳統的關係型數據庫通常都提供了跨越全部數據的ACID特性;爲了性能考慮,HBase只提供了基於單行的ACID。 mvc

下面是一個hbase併發寫的例子。 性能

原始數據以下
mvcc 優化

Apache HBase Write Path一文能夠知道hbase寫數據是分爲兩步:
1. 寫Write-Ahead-Log(WAL)文件
2. 寫MemStore:將每一個cell[(row,column)對]的數據寫到內存中的memstore ui

寫寫同步

假定對寫沒有采起併發控制,並考慮如下的順序: spa

mvcc

最終獲得的結果是: blog

mvcc

這樣就獲得了不一致的結果。顯然咱們須要對併發寫操做進行同步。
最簡單的方式是提供一個基於行的獨佔鎖來保證對同一行寫的獨立性。因此寫的順序是:

  • (0) 獲取行鎖
  • (1) 寫WAL文件
  • (2) 更新MemStore:將每一個cell寫入到memstore
  • (3) 釋放行鎖

讀寫同步

儘管對併發寫加了鎖,可是對於讀呢?見下面的例子:
mvcc

若是在上面的圖中紅線所示的地方進行讀操做,最終獲得的結果是:
mvcc

可見須要對讀和寫也進行併發控制,否則會獲得不一致的數據。最簡單的方案就是讀和寫公用一把鎖。這樣雖然保證了ACID特性,可是讀寫操做同時搶佔鎖會互相影響各自的性能。

MVCC算法

HBase採用了MVCC算法來避免讀操做去獲取行鎖。

對於寫操做:

  • (w1) 獲取行鎖後,每一個寫操做都當即分配一個寫序號
  • (w2) 寫操做在保存每一個數據cell時都要帶上寫序號
  • (w3) 寫操做須要申明以這個寫序號來完成本次寫操做

對於讀操做:

  • (r1) 每一個讀操做開始都分配一個讀序號,也稱爲讀取點
  • (r2) 讀取點的值是全部的寫操做完成序號中的最大整數(全部的寫操做完成序號<=讀取點)
  • (r3) 對某個(row,column)的讀取操做r來講,結果是知足寫序號爲「寫序號<=讀取點這個範圍內」的最大整數的全部cell值的組合

在採用MVCC後的數據執行圖:
mvcc

注意到採用MVCC算法後,每一次寫操做都有一個寫序號(即w1步),每一個cell數據寫memstore操做都有一個寫序號(w2,例如:「Cloudera [wn=1]」)),而且每次寫操做完成也是基於這個寫序號(w3)。

若是在「Restaurant [wn=2]」 這步以後,「Waiter [wn=2]」這步以前,開始一個讀操做。根據規則r1和r2,讀的序號爲1。根據規則3,讀操做以序號1讀到的值是:

mvcc

這樣就實現了以無鎖的方式讀取到一致的數據了。

從新總結下MVCC算法下寫操做的執行流程:

  • (0) 獲取行鎖
  • (0a) 獲取寫序號
  • (1) 寫WAL文件
  • (2) 更新MemStore:將每一個cell寫入到memstore
  • (2a) 以寫序號完成操做
  • (3) 釋放行鎖

本文是基於HBase 0.92. 在HBase 0.94中會有些優化策略,好比 HBASE-5541 提到的。

英文原文:https://blogs.apache.org/hbase/entry/apache_hbase_internals_locking_and

參考:深刻理解MVCC多版本併發控制

相關文章
相關標籤/搜索