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方法:

转发自:http://www.cnblogs.com/panfeng412/p/mvcc-implementation-mechanism-in-hbase.html

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

  1. 解决问题的反馈机制_谈谈HBase中的Nonce机制

    最近在读hbase源码关于rpc的一些实现细节,想正好趁此机会和大家分享一下我理解到的hbase关于Nonce机制的实现. Nonce机制的来源 Nonce这个词由来已久,且在各个领域都会有相对应的名 ...

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

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

  3. 从HBase中移除WAL?3D XPoint技术带来的变革

    最近,Intel在HBase社区提交了一个标题为"WALLess HBase on Persistent Memory"的问题单,将3D XPoint技术引入到HBase中,并且移 ...

  4. hbase中为何不能向表中插入数据_Hbase快速入门(超精炼总结)

    基本概念: HBase是列簇式Key-Value存储系统,构建在HDFS之上的.支持随机插入和删除. 总结Hbase的架构核心,就两个字"有序" . 磁盘的读写,随机与顺序,相差3 ...

  5. HBase建表高级属性,hbase应用案例看行键设计,HBase和mapreduce结合,从Hbase中读取数据、分析,写入hdfs,从hdfs中读取数据写入Hbase,协处理器和二级索引

    1. Hbase高级应用 1.1建表高级属性 下面几个shell 命令在hbase操作中可以起到很到的作用,且主要体现在建表的过程中,看下面几个create 属性 1. BLOOMFILTER 默认是 ...

  6. Hbase中的Column Family(转载)

    1. 概述 HBase是一帮家伙看了Google发布的一片名为"BigTable"的论文以后,犹如醍醐灌顶,进而"山寨"出来的一套系统. 由此可见: 1. 几乎 ...

  7. Phoenix 原理 以及 Phoenix在HBase中的应用

    一.前言 业务使用HBase已经有一段时间了,期间也反馈了很多问题,其中反馈最多的是HBase是否支持SQL查询和二级索引,由于HBase在这两块上目前暂不支持,导致业务在使用时无法更好的利用现有的经 ...

  8. HBase中MemStore flush的源码解析

    flush请求的发出: HRegion会调用requestFlush()触发flush行为,flush发生在每一处region可能发生变化的地方,包括region有新数据写入,客户端调用了put/in ...

  9. HBase中RegionServer宕机恢复介绍

    HBase采用类LSM的架构体系,数据写入并没有直接写入数据文件,而是会先写入缓存(Memstore),在满足一定条件下缓存数据再会异步刷新到硬盘.为了防止数据写入缓存之后不会因为RegionServ ...

  10. hbase中为何不能向表中插入数据_大数据HBase理论实操面试题

    1.HBase的特点是什么? 1)大:一个表可以有数十亿行,上百万列: 2)无模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态的增加,同一张表中不同的行可以有截然不同的列: 3)面向列: ...

最新文章

  1. html滑块数值怎么显示,显示HTML5滑块值旁边的百分比
  2. 处理图片(updated)
  3. windows10风格 springboot activiti 整合项目框架源码 shiro 安全框架 druid 数据库连接池...
  4. ACL 2021 | ConSERT:基于对比学习的句子语义表示迁移框架
  5. Java多线程 - 线程组
  6. Vivado中RTL封装IP流程
  7. OpenXLSX 中文字段读取问题
  8. 20181027_任务
  9. 10天学会phpWeChat——第一天:核心框架的目录结构
  10. c# 判断两个集合是否有交集
  11. 学MySQL,这篇万字总结,真的够用了
  12. 不同手机型号图文预览_手机支持型号汇总
  13. 猎豹网c 语言程序设计,[C/C++基础] 猎豹网校 C++ Primer初级/中级/高级合集发布 猎豹网校Primer视频教程...
  14. R语言 最新TwoSampleMR、MRInstruments包安装教程
  15. xctf crackme
  16. ui测试怎么做?依据文档有哪些_软件开发流程涉及到哪些文档?其中有你需要了解的外包开发中的猫腻...
  17. ghd oracle,ghd ORACLE双管卷发棒怎么样?具有离子夹外型、卷发棒功能简直是手残少女救星...
  18. Linux环境go项目启动提示/usr/bin/ld: cannot find -lxxx
  19. 实时渲染大赛太卷了,来看提前交卷的优秀参赛作品
  20. Specified VM install not found: type Standard VM, name jre7

热门文章

  1. matlab软件及基础实验第8单元,知到高等数学与MATLAB启蒙第八单元章节测试答案...
  2. java虚拟机的数据_Java虚拟机运行时数据区域
  3. 蓝桥杯2015年第六届C/C++B组第六题-加法变乘法
  4. Dart基础第4篇:运算符、条件判断、类型转换
  5. MS CRM 2011 如何向自定义Ribbon按钮传递参数
  6. python3使用requests和requests_toolbelt上传文件
  7. 笔记6:Django基础
  8. 判断字符是否包含有特殊字符
  9. 支付宝玉伯:我心目中的优秀API
  10. 是驴是骡,遛一遛就知道了