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* <b>not</b> check the families for validity.** @param familyMap Map of kvs per family* @param localizedWriteEntry The WriteEntry of the MVCC for this transaction.* If null, then this method internally creates a mvcc transaction.* @return the additional memory usage of the memstore caused by the* new entries.*/private long applyFamilyMapToMemstore(Map<byte[], List<KeyValue>> familyMap,MultiVersionConsistencyControl.WriteEntry localizedWriteEntry) {long size = 0;boolean freemvcc = false;try {if (localizedWriteEntry == null) {localizedWriteEntry = mvcc.beginMemstoreInsert();freemvcc = true;}for (Map.Entry<byte[], List<KeyValue>> e : familyMap.entrySet()) {byte[] family = e.getKey();List<KeyValue> 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);}}return size;}
读操作
HRegion.java中通过private ConcurrentHashMap<RegionScanner, Long> 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<KeyValue> 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() throws IOException {long readPoint = MultiVersionConsistencyControl.getThreadReadPoint();// We want to ignore all key-values that are newer than our current// readPointwhile(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;}
2) Memstore.java中MemStoreScanner对象的getNext方法:
HBase中MVCC的实现机制及应用情况相关推荐
- 解决问题的反馈机制_谈谈HBase中的Nonce机制
最近在读hbase源码关于rpc的一些实现细节,想正好趁此机会和大家分享一下我理解到的hbase关于Nonce机制的实现. Nonce机制的来源 Nonce这个词由来已久,且在各个领域都会有相对应的名 ...
- mysql mvcc机制rc_Mysql中MVCC的使用及原理
数据库默认隔离级别:RR(Repeatable Read,可重复读),MVCC主要适用于Mysql的RC,RR隔离级别 创建一张存储引擎为testmvcc的表,sql为: CREATE TABLE t ...
- 从HBase中移除WAL?3D XPoint技术带来的变革
最近,Intel在HBase社区提交了一个标题为"WALLess HBase on Persistent Memory"的问题单,将3D XPoint技术引入到HBase中,并且移 ...
- hbase中为何不能向表中插入数据_Hbase快速入门(超精炼总结)
基本概念: HBase是列簇式Key-Value存储系统,构建在HDFS之上的.支持随机插入和删除. 总结Hbase的架构核心,就两个字"有序" . 磁盘的读写,随机与顺序,相差3 ...
- HBase建表高级属性,hbase应用案例看行键设计,HBase和mapreduce结合,从Hbase中读取数据、分析,写入hdfs,从hdfs中读取数据写入Hbase,协处理器和二级索引
1. Hbase高级应用 1.1建表高级属性 下面几个shell 命令在hbase操作中可以起到很到的作用,且主要体现在建表的过程中,看下面几个create 属性 1. BLOOMFILTER 默认是 ...
- Hbase中的Column Family(转载)
1. 概述 HBase是一帮家伙看了Google发布的一片名为"BigTable"的论文以后,犹如醍醐灌顶,进而"山寨"出来的一套系统. 由此可见: 1. 几乎 ...
- Phoenix 原理 以及 Phoenix在HBase中的应用
一.前言 业务使用HBase已经有一段时间了,期间也反馈了很多问题,其中反馈最多的是HBase是否支持SQL查询和二级索引,由于HBase在这两块上目前暂不支持,导致业务在使用时无法更好的利用现有的经 ...
- HBase中MemStore flush的源码解析
flush请求的发出: HRegion会调用requestFlush()触发flush行为,flush发生在每一处region可能发生变化的地方,包括region有新数据写入,客户端调用了put/in ...
- HBase中RegionServer宕机恢复介绍
HBase采用类LSM的架构体系,数据写入并没有直接写入数据文件,而是会先写入缓存(Memstore),在满足一定条件下缓存数据再会异步刷新到硬盘.为了防止数据写入缓存之后不会因为RegionServ ...
- hbase中为何不能向表中插入数据_大数据HBase理论实操面试题
1.HBase的特点是什么? 1)大:一个表可以有数十亿行,上百万列: 2)无模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态的增加,同一张表中不同的行可以有截然不同的列: 3)面向列: ...
最新文章
- html滑块数值怎么显示,显示HTML5滑块值旁边的百分比
- 处理图片(updated)
- windows10风格 springboot activiti 整合项目框架源码 shiro 安全框架 druid 数据库连接池...
- ACL 2021 | ConSERT:基于对比学习的句子语义表示迁移框架
- Java多线程 - 线程组
- Vivado中RTL封装IP流程
- OpenXLSX 中文字段读取问题
- 20181027_任务
- 10天学会phpWeChat——第一天:核心框架的目录结构
- c# 判断两个集合是否有交集
- 学MySQL,这篇万字总结,真的够用了
- 不同手机型号图文预览_手机支持型号汇总
- 猎豹网c 语言程序设计,[C/C++基础] 猎豹网校 C++ Primer初级/中级/高级合集发布 猎豹网校Primer视频教程...
- R语言 最新TwoSampleMR、MRInstruments包安装教程
- xctf crackme
- ui测试怎么做?依据文档有哪些_软件开发流程涉及到哪些文档?其中有你需要了解的外包开发中的猫腻...
- ghd oracle,ghd ORACLE双管卷发棒怎么样?具有离子夹外型、卷发棒功能简直是手残少女救星...
- Linux环境go项目启动提示/usr/bin/ld: cannot find -lxxx
- 实时渲染大赛太卷了,来看提前交卷的优秀参赛作品
- Specified VM install not found: type Standard VM, name jre7
热门文章
- matlab软件及基础实验第8单元,知到高等数学与MATLAB启蒙第八单元章节测试答案...
- java虚拟机的数据_Java虚拟机运行时数据区域
- 蓝桥杯2015年第六届C/C++B组第六题-加法变乘法
- Dart基础第4篇:运算符、条件判断、类型转换
- MS CRM 2011 如何向自定义Ribbon按钮传递参数
- python3使用requests和requests_toolbelt上传文件
- 笔记6:Django基础
- 判断字符是否包含有特殊字符
- 支付宝玉伯:我心目中的优秀API
- 是驴是骡,遛一遛就知道了