lightning mdb 源代码分析(4)—MVCC/COW
本博文将描述MVCC和cow技术以及LMDB中如何使用以及实现这两种技术。
COW(Copy On Write):
COW技术背后的思想是拖延技术,基本方法是假如有多个调用者需要访问的资源,在其初始化的时候是不能区分的,即对于多个调用者来说,这资源就是一样的。这样就可以给每个
调用者一个指向资源的指针即可。这种方法一直持续到调用者需要进行修改所需要访问的资源时,在这个时候,调用者将被分配到一份真正私有的资源拷贝,这样调用者对资源的任意
改动对于其它调用者来说都是不可见的。所有的以上操作对于调用者来说是透明的,这种方法最大的好处就是假如调用者不修改资源,私有拷贝就不会被创建。因此这种技术对于读大于
写的应用场景来说特别合适,比如说虚拟内存与分页、数据库、string对象等等,都使用此技术以提升系统性能。
MVCC(Multiversion concurrency control):
MVCC是数据库系统实现并发控制和一般系统中实现事务性内存控制的一种技术,主要用于并发控制,使用MVCC将读不会阻塞写,写不会阻塞读,只有两个线程写同一行数据可能导致冲突,
因此可以提供最高的并发性。MVCC对于并发写同一区域的数据可能导致冲突要求事务回滚或者互相等待资源导致死锁。
对于数据库系统来说,若一个用户正在读数据的同时,另一个用户正在写同一个数据,则读用户可能读到写到一半的数据或者不一致的数据,因此数据库系统都会使用并发控制。最简单的方式就是
写时阻塞所有读,这就是封锁技术。MVCC的方式是每个用户看到的数据是其连接上数据库时的快照,所有写操作对数据的改变其他数据库用户都不能看到,除非改变已经完成(即事务已提交)。
在MVCC中数据的更新使用delete(标记)+insert实现,因此对于同一行数据可能在数据库多个地方存在不同版本,旧数据和新数据不在同一个地方(不是就地更新),但只有最后一个版本是最新的,
之前的版本对于之前的事务有效。MVCC的好处是对于读数据来说,哪怕数据在整个事务过程中被别的用户修改删除,其读到的数据就是刚开始使用数据库时的那份数据。另外就是其不需要及时删除
旧数据,这样避免了系统来回换页导致性能下降。对于文档型数据库来说,还可以优化为数据存储在连续区块,delete+insert可以不更新里面部分数据,这样对于后续组装数据提供最大便利。MVCC
提供了即时的一致性视图,读写隔离,不需要进行封锁,因此可以提高并发性。
MVCC的图示:
图1:事务T1改变数据V1,将其改为数据V2,在堆中,数据如下图

图2:事务T3改变了V2,将其改为V3,在堆中,数据如下图:目前事务T2还在活动中,所以V1和V2属于recently dead状态,而不是真的dead状态。

图3:从可视性而言,事务T0只能看到数据V1。因为它早于事务T1启动。

图4:事务T1提交后,事务T2启动,此时事务T3尚未启动,故T2可以看到T1提交后的数据V2。

图5:事务T3提交后,事务T4启动,故T4只能看到数据V3。

图6: 前面说过,当还有事务活动中访问数据V1和V2,V1和V2的状态是recently dead。
当T0和T2都结束,已经没有事务在访问数据V1和V2了,此时V1和V2为dead状态,所以V1和V2都成为VACUUM的处理对象了。

以上几图以postgresql的MVCC实现为例描述了不同事务间读写操作过程以及其访问的数据。对于同时更新来说,主要多了
更新冲突检测,若更新存在读写依赖冲突则,更新失败,事务必须回滚,若存在互相依赖,则会解锁某一个事务,以避免死锁。
MVCC/COW在LMDB中的实现
LMDB对MVCC加了一个限制,即只允许一个写线程存在,从根源上避免了写写冲突,当然代价就是写入的并发性能下降。因为只有
一个写线程,所以不会不需要wal日志、读写依赖队列、锁队列等一系列控制并发、事务回滚、数据恢复的基础工具。MVCC的基础
就是COW,对于不同的用户来说,若其在整个操作过程中不进行任何的数据改变,其就使用同一份数据即可,若需要进行改变,比如
增加、删除、修改等,就需要在私有数据版本上进行,修改完成提交之后才给其他事务可见。
LMDB中,数据操作的基本单元是页,因此cow也是以页为单位,对应函数是mdb_page_touch,mdb_page_copy,copy真正实现页面复制,
touch调用copy完成复制,然后修改pgno后插入到B+Tree当中,这样对于此次事务,后续的操作访问的数据页就是最新的数据页面,而非
事务启动时对应的数据页面,且此页面与其他页面的关联关系仅在本事务页面列表中可见,对其他事务不可见。
实际上通过以上两个函数也实现了MVCC的核心,对于读写的控制,通过mdb_txn_begin控制,在其中,事务启动时会检查读写锁的情况,
若事务需要更新数据,则会被阻止,若只是读数据,则不管是否有写事务存在,读锁都可以获得。
MVCC的一个副作用就是对于存在大量写的应用,其数据版本很多,因此旧数据会占用大量空间,postgresql解决此问题通过vacuum命令,
LMDB中通过freedb解决,即将不再使用的旧的数据页面空间插入到一颗b-Tree当中,这样旧空间在所有事务不再访问之后就可以被LMDB
使用,从而避免了需要定期执行清理操作。当然其副作用是数据只能保持最新不能恢复到任意时刻,未执行vacuum之前,保存所有版本的数据库
可以恢复到任意时刻。
本文参考了如下资料,在此一并表示感谢。
https://en.wikipedia.org/wiki/Multiversion_concurrency_control
http://www.kuqin.com/system-analysis/20120319/319108.html
http://blog.chinaunix.net/uid-20726500-id-4040024.html
http://www.cnblogs.com/gaojian/p/3295951.html
lightning mdb 源代码分析(4)—MVCC/COW的更多相关文章
- lightning mdb 源代码分析(1)
lighting mdb(lmdb) 是一个高性能mmap kv数据库,基本介绍和文档参见symas官网,本文将尝试分析其源代码结构以理解数据库设计的关键技术. 本系列文章将尝试从以下几个方面进行分析 ...
- lightning mdb 源代码分析系列(3)
本系列前两章已经描述了系统架构以及系统构建的基础内存映射,本章将详细描述lmdb的核心,外存B+Tree的操作.本文将从基本原理.内存操作方式.外存操作方式以及LMDB中的相关函数等几方面描述LMDB ...
- lightning mdb 源代码分析(5)-事务控制
本博文系列前面已经探讨了LMDB的系统架构.MMAP映射.B-Tree操作等部分,本文将尝试描述LMDB中的事务控制的实现. 事务的基本特征: 事务是恢复和并发控制的基本单位.它是一个操作序列,这些操 ...
- lightning mdb 源代码分析(2)
本系列前一篇已经分析了lightningmdb的整体架构和主要的数据结构.本文将介绍一下MMAP原理以及lmdb中如何使用它. 1. Memory Map原理 内存映射文件与虚拟内存有些类似,通过内存 ...
- HBase源代码分析之HRegion上MemStore的flsuh流程(二)
继上篇<HBase源代码分析之HRegion上MemStore的flsuh流程(一)>之后.我们继续分析下HRegion上MemStore flush的核心方法internalFlushc ...
- android-plugmgr源代码分析
android-plugmgr是一个Android插件加载框架,它最大的特点就是对插件不需要进行任何约束.关于这个类库的介绍见作者博客,市面上也有一些插件加载框架,但是感觉没有这个好.在这篇文章中,我 ...
- Twitter Storm源代码分析之ZooKeeper中的目录结构
徐明明博客:Twitter Storm源代码分析之ZooKeeper中的目录结构 我们知道Twitter Storm的所有的状态信息都是保存在Zookeeper里面,nimbus通过在zookeepe ...
- 转:SDL2源代码分析
1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...
- 转:RTMPDump源代码分析
0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...
随机推荐
- sharepoint更新多行文本webparth
前台 <script> function Copy() { var value = document.getElementById("<%=BodyBox.ClientID ...
- Cannot change version of project facet Dynamic web module to 2.5
在工程目录下有一个.settings文件夹,打开org.eclipse.wst.common.project.facet.core.xml做如下修改:<installed facet=" ...
- iOS 推荐一个下载用的第三方库
AFNetworking有下载功能,但是下载功能比较基本,要实现复杂下载功能需要自己写一些代码.今天在github上找到了一个下载功能的开源项目,非常不错,链接如下:https://github.co ...
- (转)SQL Server 的事务和锁(一)
SQL Server 的事务和锁(一) 最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁: 1 2 3 4 5 6 7 8 9 1 ...
- codeforces 489B. BerSU Ball 解题报告
题目链接:http://codeforces.com/problemset/problem/489/B 题目意思:给出 n 个 boys 的 skills 和 m 个 girls 的 skills,要 ...
- poj 2013 Symmetric Order 解题报告
题目链接:http://poj.org/problem?id=2013 设长度非递减的字串序列为s[1]...s[n].设计递归子程序print(n),其中n为字串序号,每分析1个字串,n=n-1. ...
- HDU 5745 La Vie en rose (DP||模拟) 2016杭电多校联合第二场
题目:传送门. 这是一道阅读理解题,正解是DP,实际上模拟就能做.pij+1 指的是 (pij)+1不是 pi(j+1),判断能否交换输出即可. #include <iostream> # ...
- 如何识别是visual studio下头的哪种类型程序
可以通过文件来判断 比如MFC, 那它就会包括xxxview.cpp文件. win32又分为win32项目和console(即控制台应用程序),看主函数 win32控制台应用程序的主函数为_tmain ...
- vector data() [c++11]
Example 12345678910111213141516171819202122 // vector::data #include <iostream> #include <v ...
- java equals 和 "==" 比较
java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(== ...