MVCC(Multi-Version Concurrent Control),即多版本并发控制协议,广泛使用于数据库系统。本文将介绍HBase中对于MVCC的实现及应用情况。

MVCC基本原理

在介绍MVCC概念之前,我们先来想一下数据库系统里的一个问题:假设有多个用户同时读写数据库里的一行记录,那么怎么保证数据的一致性呢?一个基本的解决方法是对这一行记录加上一把锁,将不同用户对同一行记录的读写操作完全串行化执行,由于同一时刻只有一个用户在操作,因此一致性不存在问题。但是,它存在明显的性能问题:读会阻塞写,写也会阻塞读,整个数据库系统的并发性能将大打折扣。

MVCC(Multi-Version Concurrent Control),即多版本并发控制协议,它的目标是在保证数据一致性的前提下,提供一种高并发的访问性能。在MVCC协议中,每个用户在连接数据库时看到的是一个具有一致性状态的镜像,每个事务在提交到数据库之前对其他用户均是不可见的。当事务需要更新数据时,不会直接覆盖以前的数据,而是生成一个新的版本的数据,因此一条数据会有多个版本存储,但是同一时刻只有最新的版本号是有效的。因此,读的时候就可以保证总是以当前时刻的版本的数据可以被读到,不论这条数据后来是否被修改或删除。

更多关于MVCC基本思想的介绍,参考Wikipedia。

一个MVCC实现类

见org.apache.hadoop.hbase.regionserver.MultiVersionConsistencyControl,用于控制Memstore中读写的一致性,其中维护两个long型的变量:

1)memstoreRead:用于记录当前全局可读的readPoint,同时为了每个客户端读请求能够记录自己发起请求时刻的readPoint,还有一个ThreadLocal的perThreadReadPoint变量,以及相关的set和get方法;

2)memstoreWrite:用于记录当前全局最大的writePoint,根据它为下个事务生成新的writePoint。

MultiVersionConsistencyControl中关键的实现方法如下:

1)WriteEntry beginMemstoreInsert():开始一个更新操作,将memstoreWrite加1,创建writeQueue并插入到writeQueue,并返回WriteEntry对象;

2)void completeMemstoreInsert(WriteEntry e):完成当前更新操作,将WriteEntry对象标记为可读,具体分两步:

boolean advanceMemstore(WriteEntry e):从头开始遍历writeQueue,移除所有已完成的WriteEntry对象,最后将memstoreRead更新为最新已完成的memstoreWrite;

void waitForRead(WriteEntry e):阻塞当前线程,直到memstoreRead等于当前WriteEntry的memstoreWrite,至此表明当前WriteEntry之前的所有更新事务都已经完成。

MVCC使用场景

见org.apache.hadoop.hbase.regionserver.HRegion.java,每个Region包含一个Memstore,维护一个MultiVersionConsistencyControl对象。

写操作

见HRegion.java中的以下写操作的方法:

1)put

2)checkAndPut

3)delete

4)checkAndDelete

5)internalFlushcache

6)mutateRow

7)mutateRowsWithLocks

8)batchMutate

最终会调用到applyFamilyMapToMemstore方法使用MVCC进行写操作:

/*** Atomically apply the given map of family->edits to the memstore.

* This handles the consistency control on its own, but the caller

* should already have locked updatesLock.readLock(). This also does

* not check the families for validity.

*

*@paramfamilyMap Map of kvs per family

*@paramlocalizedWriteEntry The WriteEntry of the MVCC for this transaction.

* If null, then this method internally creates a mvcc transaction.

*@returnthe additional memory usage of the memstore caused by the

* new entries.*/

private long applyFamilyMapToMemstore(Map>familyMap,

MultiVersionConsistencyControl.WriteEntry localizedWriteEntry) {long size = 0;boolean freemvcc = false;try{if (localizedWriteEntry == null) {

localizedWriteEntry=mvcc.beginMemstoreInsert();

freemvcc= true;

}for (Map.Entry>e : familyMap.entrySet()) {byte[] family =e.getKey();

List edits =e.getValue();

Store store=getStore(family);for(KeyValue kv: edits) {

kv.setMemstoreTS(localizedWriteEntry.getWriteNumber());

size+=store.add(kv);

}

}

}finally{if(freemvcc) {

mvcc.completeMemstoreInsert(localizedWriteEntry);

}

}returnsize;

}

View Code

读操作

HRegion.java中通过private ConcurrentHashMap scannerReadPoints;维护各个查询请求的readPoint。

以get或scan请求为例,最终会通过getScanner方法需要构造RegionScannerImpl对象:

org.apache.hadoop.hbase.regionserver.HRegion.RegionScannerImpl:

1)根据Scan对象构造时设置好readPoint,scan.getIsolationLevel()分为READ_UNCOMMITTED和READ_COMMITTED,只有当READ_COMMITTED时根据MultiVersionConsistencyControl.resetThreadReadPoint(mvcc);设置当前scanner线程的readPoint,并插入到scannerReadPoints维护起来。

2)根据scan需要读取的column family,创建StoreScanner(根据bloom filter、time range、ttl筛选需要的MemStoreScanner和StoreFileScanner),添加到scanners中,并最终根据scanners构造出一个KeyValueHeap。

下面看下RegionScannerImpl中的next方法是每次查询时需要调用的函数:

boolean org.apache.hadoop.hbase.regionserver.HRegion.RegionScannerImpl.next(List outResults, int limit) throws IOException

而上述方法会通过KeyValueHeap的next方法读取下一条数据:先定位到当前KeyValueScanner(即之前构造KeyValueHeap时传入的MemStoreScanner或StoreScanner),然后调用next方法。

StoreFileScanner和MemStoreScanner均为KeyValueScanner,通过其中的next()接口方法,分别调用到StoreFileScanner.java的skipKVsNewerThanReadpoint方法、Memstore.java中MemStoreScanner对象的getNext方法。

1)StoreFileScanner.java的skipKVsNewerThanReadpoint方法:

protected boolean skipKVsNewerThanReadpoint() throwsIOException {long readPoint =MultiVersionConsistencyControl.getThreadReadPoint();//We want to ignore all key-values that are newer than our current//readPoint

while(enforceMVCC&& cur != null

&& (cur.getMemstoreTS() >readPoint)) {

hfs.next();

cur=hfs.getKeyValue();

}if (cur == null) {

close();return false;

}//For the optimisation in HBASE-4346, we set the KV's memstoreTS to//0, if it is older than all the scanners' read points. It is possible//that a newer KV's memstoreTS was reset to 0. But, there is an//older KV which was not reset to 0 (because it was//not old enough during flush). Make sure that we set it correctly now,//so that the comparision order does not change.

if (cur.getMemstoreTS() <=readPoint) {

cur.setMemstoreTS(0);

}return true;

}

View Code

2)  Memstore.java中MemStoreScanner对象的getNext方法:

protected KeyValue getNext(Iteratorit) {long readPoint =MultiVersionConsistencyControl.getThreadReadPoint();while(it.hasNext()) {

KeyValue v=it.next();if (v.getMemstoreTS() <=readPoint) {returnv;

}

}return null;

}

View Code

java 实现mvcc_HBase中MVCC的实现机制及应用情况相关推荐

  1. java和net共同点,Java和.NET中的垃圾回收机制比较

    相同点: 都采用了分代的机制. 都支持并发GC. 都没有采用引用计数方式,而是采用了追踪技术. .NET中,可以通过代码GC.Collect() 强制要求CLR进行垃圾回收(由于垃圾回收是异步的,CL ...

  2. java 参数传递_java中方法的参数传递机制

    无论是什么语言,要讨论参数传递方式,就得从内存模型说起,主要是我个人觉得从内存模型来说参数传递更为直观一些.闲言少叙,下面我们就通过内存模型的方式来讨论一下Java中的参数传递. 这里的内存模型涉及到 ...

  3. Java中的等待/通知机制(wait/notify)

    为什么80%的码农都做不了架构师?>>>    当一个线程修改了一个对象的值,另外一个线程需要感知到这个变化,并且做出相应的操作时,可以使用Java中的等待/通知机制去实现这个功能. ...

  4. Java中事件监听机制

    Java中事件监听机制 一.事件监听机制的定义 要想了解Java中的事件监听机制,首先就要去了解一下在Java中事件是怎样去定义的呢!在使用Java编写好一个界面后,我们就会对界面进行一些操作,比如, ...

  5. Java中如何实现代理机制(JDK、CGLIB)

    代理分为两种: 1.静态代理 2.动态代理  动态代理又分为两种:jdk 实现  :Cglib 实现 3.Java中如何实现代理机制(JDK.CGLIB) JDK动态代理:代理类和目标类实现了共同的接 ...

  6. java map扩容机制_java中ConcurrentHashMap的扩容机制是怎样的?详细解析

    大家都知道java中有很多的基础知识,需要大家花费一定的时间去消化.关于java中ConcurrentHashMap 的扩容机制不知道大家是否了解过,其实内容也是很好理解的,一起来看看吧. 首先,我们 ...

  7. Java Jvm 中的垃圾回收机制中的思想与算法 《对Java的分析总结》-四

    Java中的垃圾回收机制中的思想与算法 <对Java的分析总结>-四 垃圾回收机制 中的思想与算法 引用计算法 给对象中添加一个引用计数器,每当一个地方引用它的时候就将计数器加1,当引用失 ...

  8. mysql mvcc机制rc_Mysql中MVCC的使用及原理

    数据库默认隔离级别:RR(Repeatable Read,可重复读),MVCC主要适用于Mysql的RC,RR隔离级别 创建一张存储引擎为testmvcc的表,sql为: CREATE TABLE t ...

  9. Android系统中的Binder通信机制分析(7)- Java 层的 Binder 机制

    声明 其实对于Android系统Binder通信的机制早就有分析的想法,记得2019年6.7月份Mr.Deng离职期间约定一起对其进行研究的,但因为我个人问题没能实施这个计划,留下些许遗憾- 文中参考 ...

  10. 什么是多态,JAVA 中多态的实现机制

    什么是多态,JAVA 中多态的实现机制 首先声明啊,这里的多态不是生物学和物理学上的多态性,这个是指编程语言中的多态. 官方说明: 多态(英语:polymorphism)指为不同数据类型的实体提供统一 ...

最新文章

  1. 程序员最喜爱的12个Android应用开发框架二(转)
  2. 计算机CPU哪家好,2019年电脑cpu排行榜_电脑CPU哪个好 电脑CPU排行榜2019
  3. Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念区分
  4. 前端学习(2039)vue之电商管理系统电商系统之优化运行server的Eslint警告
  5. 2018/01/08JAVA 基础 / 接口与继承:[Q]:若父类Hero提供了一个有参的构造方法,但是没有提供无参的构造方法。子类应该怎么处理?...
  6. 在spring管理的类的要注意问题
  7. root android手机型号,兼容支持各种型号手机的Root权限获取方法
  8. CEBX格式的文档如何转换为PDF格式文档、DOCX文档?
  9. vue-scroller回到顶部
  10. Mysql里有2000w数据,redis中只存20w数据,如何保证redis中的数据都是热点数据
  11. ZooKeeper典型应用场景
  12. Spring框架学习记录二:装配Bean
  13. 【已解决】微星主板开启msi fast boot后不能进BIOS
  14. 【美影】通灵男孩诺曼.Paranorman
  15. Redhat7.5升级openssh到8.2p1
  16. 那些警示良言——老百姓也是圣贤
  17. 高斯消去法解线性方程组C++实现
  18. 智能手表能测新冠?你的Fitbit可能是一个全功能脉搏血氧计
  19. Python撩妹实战——教你用微信每天给女朋友说晚安
  20. Hamming Weight的算法分析

热门文章

  1. 开源的物联网技术平台thingsboard安装测试及使用步骤
  2. 工具型产品的设计感想
  3. SQL注入***的种类和防范手段
  4. Android之崩溃日志本地存储与远程保存
  5. Redis面经:重新梳理了 5 种数据类型的用法和应用场景
  6. Java 实战篇-JDK9新特性
  7. vector java 复制_孙悟空的身外身法术使用了Java设计模式:原型模式
  8. 16kb等于多少b_一篇文章讲透MySQL为什么要用B+树实现索引
  9. 10年老电脑如何提速_电脑上如何提取图片中的文字?教你3个方法,10秒轻松搞定...
  10. PHP学习笔记五(命名空间)