HBase MVCC实现流程

数据库为了保证一致性,在执行读写操作时往往会对数据做一些锁操作,比如两个client同时修改一条数据,我们无法确定最终的数据到底是哪一个client执行的结果,所以需要通过加锁来保证数据的一致性。

但是锁操作的代价是比较大的,往往需要对加锁操作进行优化,主流的数据库Mysql,PG等都采用MVCC(多版本并发控制)来尽量避免使用不必要的锁以提高性能。本文主要介绍HBase的MVCC实现机制。

在讲解HBase的MVCC之前,我们先了解一下现有的隔离级别,sql标准定义了4种隔离级别:

1.read uncommitted    读未提交

2.read committed        读已提交

3.repeatable read        可重复读

4.serializable               可串行化

HBase不支持跨行事务,目前只支持单行级别的read uncommitted和read committed隔离级别。下面主要讲解HBase的read committed实现机制。

HBase采用LSM树结构,当client发送数据给regionserver端时,regionserver会将数据写入对应的region中,region是由一个memstore和多个storeFile组成,我们可以将memstore看做是一个skipList(跳表),所有写入的数据首先存放在memstore中,当memstore增大到指定的大小后,memstore中的数据flush到磁盘生成一个新的storeFile。

HBase的写入主要分两步:

1.数据首先写入memstore

2.数据写入WAL

写入WAL的目的是为了持久化,防止memstore中的数据还未落盘时宕机造成的数据丢失,只有数据写入WAL成功之后才会认为该数据写入成功。

下面我们考虑一个问题:

根据前面的讨论可知,假如数据已经写入memstore,但还没有写入WAL,此时认为该条数据还没有写成功,如果按照read committed隔离界别的定义,用户在进行查询操作时(尤其是查询memstore时),是不应该看到这条数据的,那HBase是如何区分正在写入和写入成功的数据呢?

我们可以简单理解HBase在每次put操作时,都会为该操作分配一个id,可以类比mysql里面的事务id,是本次put的唯一标识,该id是region级别递增的,并且每个region还有一个MVCC控制中心,它还同时维护了两个pos:一个readpoint,一个writepoint。readpoint指向目前已经插入完成的id,当put操作完成时会更新readpoint;而writepoint指向目前正在插入的最大id,可以认为writepoint永远和最新申请的put的事务id是一样的。

下面我们画图解释:

1.client插入数据时(这里的client我们可以理解为是regionserver),首先会向MVCC控制中心(MultiVersionConsistencyControl类)申请最新的事务id,其实就是返回write point++,每一个region各自拥有一个独立MVCC控制中心。

2.假设初始状态read和write point都指向2,表明目前没有正在进行的put操作,新的put请求过来时,该region的MVCC控制中心向它自己维护的队列中插入一个新的entry,表示发起了一个新的put事务,并且第一步中将write point++。

3.向client返回本次事务的id为3.

4.client向memstore中插入数据,并且该数据附带本次事务的id号:3

5.将本次的put操作写入WAL,写入成功后代表数据写入成功

6.此时移动read point至3,表示任何MVCC值小于等于3的数据此时都可以被新创建的scan查询检索到。

scan执行查询操作时,首先会向MVCC控制中心拿到目前的read point,然后对memstore和storeFiles进行查询,并过滤掉MVCC值大于本次scan MVCC的数据,保证了scan不会检索到还未提交成功的数据。这也说明HBase默认即为read committed级别,只不过是单行事务。


真正业务场景下是会有很多个client同时写入的,此时不管向MVCC申请事务id还是更新read point都会涉及到多用户竞争的情况。如图client A B C分别写入了数据de/fg/hi,有可能A C已经写入成功了,而B还未执行完,下面我们看一下MVCC控制中心是如何协调并发请求的。

先介绍一下MVCC控制中心–MultiVersionConsistencyControl类.

它包含了三个重要的成员:

1.memstoreRead:即我们提到的read point,记录可以已执行完毕的事务id

2.memstoreWrite:即我们提到的write point,记录当前正在执行的最大事务id

3.writeQueue:一个LinkedList,每一个元素是一个WriteEntry对象。

WriteEntry类包含两个属性:

1.writeNumber:事务id

2.completed: True/False,数据写入成功后,写入线程会将其设置为True

下面详细解释MVCC控制中心针对多用户请求是如何做到同步的:

1.当一个client写入数据时,首先lock住MVCC控制中心的写入队列LinkedList,并向其插入一个新的entry,并将之前的write point+1赋予entry的num(write point+1也是同步操作),表示发起了一个新的写入事务。Flag值此时为False,表名目前事务还未完成,数据还在写入过程中。

2.第二步client将数据写入memstore和WAL,此时认为数据已经持久化,可以结束该事务。

3.client调用MVCC控制中心的completeMemstoreInsert(num)方法,该方法采用synchronized关键字,可以理解就是同步方法,将该num对应的entry的Flag设置为True,表示该entry对应的事务完成。但是单单将Flag设置为True是不够的,我们的最终目的是要让scan能够看到最新写入完成的数据,也就是说还需要更新read point。

4.更新read point:同样在completeMemstoreInsert方法中完成,每一个client将其对应的entry的Flag设置为True后,都会去按照队列顺序,从read point开始遍历,假如遍历到的entry的Flag为True,则将read point更新至此位置,直到遇到Flag为False的位置时停止。也就是说每个client写入之后,都会尽力去将read point更新到目前最大连续的已经完成的事务的点(因为是有可能后开始的事务先于之前的事务完成)。

看到这里,可能大家会想了,那假如事务A先于事务C,事务A还未完成,但事务C已经完成,事务C也只能将read point更新到事务A之前的位置,如果此时事务C返回写入成功,那按道理来说scan是应该能够查到事务C的数据,但是由于read point没有更新到C,就会造成一个现象就是:事务C明明提示执行成功,但是查询的时候却看不到。

所以上面说的第4步其实还并没有完,client在执行completeMemstoreInsert后,还会执行一个waitForRead(entry)方法,参数的entry就是该事务对应的entry,该方法会一直等待read point大于等于该entry的num时才会返回,这样保证了事务有序完成。

以上就是HBase写入时MVCC的工作流程,scan就比较好理解了,每一个scan请求都会申请一个readpoint,保证了该read point之后的事务不会被检索到。

note:HBase也同样支持read uncommitted级别,也就是我们在查询的时候将scan的mvcc值设置为一个超大的值,大于目前所有申请的MVCC值,那么查询时同样会返回正在写入的数据。

end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260