时间:2021-07-01 10:21:17 帮助过:17人阅读
MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是,把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高
MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是,把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能。
HBase正是通过行锁+MVCC保证了高效的并发读写。
HBase系统本身只能保证单行的ACID特性。ACID的含义是:
传统的关系型数据库一般都提供了跨越所有数据的ACID特性;为了性能考虑,HBase只提供了基于单行的ACID。
下面是一个hbase并发写的例子。
原始数据如下
从Apache HBase Write Path一文可以知道hbase写数据是分为两步:
1. 写Write-Ahead-Log(WAL)文件
2. 写MemStore:将每个cell[(row,column)对]的数据写到内存中的memstore
假定对写没有采取并发控制,并考虑以下的顺序:
最终得到的结果是:
这样就得到了不一致的结果。显然我们需要对并发写操作进行同步。
最简单的方式是提供一个基于行的独占锁来保证对同一行写的独立性。所以写的顺序是:
尽管对并发写加了锁,但是对于读呢?见下面的例子:
如果在上面的图中红线所示的地方进行读操作,最终得到的结果是:
可见需要对读和写也进行并发控制,不然会得到不一致的数据。最简单的方案就是读和写公用一把锁。这样虽然保证了ACID特性,但是读写操作同时抢占锁会互相影响各自的性能。
HBase采用了MVCC算法来避免读操作去获取行锁。
对于写操作:
对于读操作:
在采用MVCC后的数据执行图:
注意到采用MVCC算法后,每一次写操作都有一个写序号(即w1步),每个cell数据写memstore操作都有一个写序号(w2,例如:“Cloudera [wn=1]”)),并且每次写操作完成也是基于这个写序号(w3)。
如果在“Restaurant [wn=2]” 这步之后,“Waiter [wn=2]”这步之前,开始一个读操作。根据规则r1和r2,读的序号为1。根据规则3,读操作以序号1读到的值是:
这样就实现了以无锁的方式读取到一致的数据了。
重新总结下MVCC算法下写操作的执行流程:
本文是基于HBase 0.92. 在HBase 0.94中会有些优化策略,比如 HBASE-5541 提到的。
英文原文:https://blogs.apache.org/hbase/entry/apache_hbase_internals_locking_and
参考:深入理解MVCC多版本并发控制
原文地址:hbase的行锁与多版本并发控制(MVCC), 感谢原作者分享。