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多版本并发控制

相关文章
相关标签/搜索