java 实现mvcc_HBase中MVCC的实现机制及应用情况
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的实现机制及应用情况相关推荐
- java和net共同点,Java和.NET中的垃圾回收机制比较
相同点: 都采用了分代的机制. 都支持并发GC. 都没有采用引用计数方式,而是采用了追踪技术. .NET中,可以通过代码GC.Collect() 强制要求CLR进行垃圾回收(由于垃圾回收是异步的,CL ...
- java 参数传递_java中方法的参数传递机制
无论是什么语言,要讨论参数传递方式,就得从内存模型说起,主要是我个人觉得从内存模型来说参数传递更为直观一些.闲言少叙,下面我们就通过内存模型的方式来讨论一下Java中的参数传递. 这里的内存模型涉及到 ...
- Java中的等待/通知机制(wait/notify)
为什么80%的码农都做不了架构师?>>> 当一个线程修改了一个对象的值,另外一个线程需要感知到这个变化,并且做出相应的操作时,可以使用Java中的等待/通知机制去实现这个功能. ...
- Java中事件监听机制
Java中事件监听机制 一.事件监听机制的定义 要想了解Java中的事件监听机制,首先就要去了解一下在Java中事件是怎样去定义的呢!在使用Java编写好一个界面后,我们就会对界面进行一些操作,比如, ...
- Java中如何实现代理机制(JDK、CGLIB)
代理分为两种: 1.静态代理 2.动态代理 动态代理又分为两种:jdk 实现 :Cglib 实现 3.Java中如何实现代理机制(JDK.CGLIB) JDK动态代理:代理类和目标类实现了共同的接 ...
- java map扩容机制_java中ConcurrentHashMap的扩容机制是怎样的?详细解析
大家都知道java中有很多的基础知识,需要大家花费一定的时间去消化.关于java中ConcurrentHashMap 的扩容机制不知道大家是否了解过,其实内容也是很好理解的,一起来看看吧. 首先,我们 ...
- Java Jvm 中的垃圾回收机制中的思想与算法 《对Java的分析总结》-四
Java中的垃圾回收机制中的思想与算法 <对Java的分析总结>-四 垃圾回收机制 中的思想与算法 引用计算法 给对象中添加一个引用计数器,每当一个地方引用它的时候就将计数器加1,当引用失 ...
- mysql mvcc机制rc_Mysql中MVCC的使用及原理
数据库默认隔离级别:RR(Repeatable Read,可重复读),MVCC主要适用于Mysql的RC,RR隔离级别 创建一张存储引擎为testmvcc的表,sql为: CREATE TABLE t ...
- Android系统中的Binder通信机制分析(7)- Java 层的 Binder 机制
声明 其实对于Android系统Binder通信的机制早就有分析的想法,记得2019年6.7月份Mr.Deng离职期间约定一起对其进行研究的,但因为我个人问题没能实施这个计划,留下些许遗憾- 文中参考 ...
- 什么是多态,JAVA 中多态的实现机制
什么是多态,JAVA 中多态的实现机制 首先声明啊,这里的多态不是生物学和物理学上的多态性,这个是指编程语言中的多态. 官方说明: 多态(英语:polymorphism)指为不同数据类型的实体提供统一 ...
最新文章
- 程序员最喜爱的12个Android应用开发框架二(转)
- 计算机CPU哪家好,2019年电脑cpu排行榜_电脑CPU哪个好 电脑CPU排行榜2019
- Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念区分
- 前端学习(2039)vue之电商管理系统电商系统之优化运行server的Eslint警告
- 2018/01/08JAVA 基础 / 接口与继承:[Q]:若父类Hero提供了一个有参的构造方法,但是没有提供无参的构造方法。子类应该怎么处理?...
- 在spring管理的类的要注意问题
- root android手机型号,兼容支持各种型号手机的Root权限获取方法
- CEBX格式的文档如何转换为PDF格式文档、DOCX文档?
- vue-scroller回到顶部
- Mysql里有2000w数据,redis中只存20w数据,如何保证redis中的数据都是热点数据
- ZooKeeper典型应用场景
- Spring框架学习记录二:装配Bean
- 【已解决】微星主板开启msi fast boot后不能进BIOS
- 【美影】通灵男孩诺曼.Paranorman
- Redhat7.5升级openssh到8.2p1
- 那些警示良言——老百姓也是圣贤
- 高斯消去法解线性方程组C++实现
- 智能手表能测新冠?你的Fitbit可能是一个全功能脉搏血氧计
- Python撩妹实战——教你用微信每天给女朋友说晚安
- Hamming Weight的算法分析
热门文章
- 开源的物联网技术平台thingsboard安装测试及使用步骤
- 工具型产品的设计感想
- SQL注入***的种类和防范手段
- Android之崩溃日志本地存储与远程保存
- Redis面经:重新梳理了 5 种数据类型的用法和应用场景
- Java 实战篇-JDK9新特性
- vector java 复制_孙悟空的身外身法术使用了Java设计模式:原型模式
- 16kb等于多少b_一篇文章讲透MySQL为什么要用B+树实现索引
- 10年老电脑如何提速_电脑上如何提取图片中的文字?教你3个方法,10秒轻松搞定...
- PHP学习笔记五(命名空间)