海量存储系列之四

单机事务:

其实在上面介绍ACID的时候

我们已经提到了一种最简单的实现方式,就是锁的实现方式。

从原理来看,事务是个变态而复杂的事情。其实如果是序列化的话呢,那么实现起来一定是非常简单的。

但问题就在于,这样性能实在比较低,于是,就有了非常多的方案,为了能哪怕减少一个地方的锁,或者降低一个地方的锁的级别,就付出大量的时间和代码加以实现。

那么,让我们以崇敬的心情,去拜读一下他们的劳动成果吧~



在上一篇中,我们谈了事务管理的四个核心要素,其中有两个要素是和性能紧密相关的,其实也就是需要涉及到锁的,一个是隔离性,一个是一致性。

一致性问题和隔离性问题,我们都可以归结为一个问题,他们都用于定义,什么时候数据可被共享,什么时候数据必须被独占。而这些决策,就最终决定了整个数据库系统的并行度,也就直接的决定了多线程并发时的性能指标。

如果要改一大批数据,又必须保证这些数据要么都出现,要么都不出现,这时候就有个难题了:因为这些数据不可能在同一个时间被选出,更不可能在同一个时间被更改。

于是就必须想个办法来假装达到这个状态,于是我们就需要一种方法,使得针对不同数据的更改,不同人(或机器)不打架。而如果出现对相同数据的更改,则要将更新进行排队。

这个排队可供选择的方法,就我知道的有:1,排他锁。2. 读写锁。3. Copy on write(MVCC) .4. 队列。5. 内存事务。这些方式。

从性能来说,排他锁最慢,而读写因为读可以并发,所以效率稍高,但写和读不能同时进行。3. Copy on write(MVCC) 则读取和写入之间可以互相不影响,所以效率更高。队列这种方式,内存时效果很好,省去中断上下文切换的时间。内存事务,目前还在研究阶段,具备很大潜力的东西。

排他锁,队列和内存事务,在目前的数据库中用的相对较少,我们就不在这里说了。

这里主要说两种实现,一种是读写锁,一种是MVCC.

先说读写锁,也是隔离性中“读已提交,可重复读”两种实现中最重要的底层实现方式。

简单来说,就是如果一个人在事务中,那么他所有写过的数据,所有读过的数据,都给他来个锁,让其他小样儿都只能等在外面,直到数据库能确定所有更改已经全部完成了,没有剩下什么半拉子状态的时候,就解开所有的锁,让其他人可以读取和写入。Hoho,就是这个了。

那么MVCC呢,其实是对读写锁的一个改进,有一批大牛们,说你们这读写锁,写的时候不能读,读的时候不能写,并行度太低了,我要做个更牛B的,写不阻塞读,读不阻塞写的东西来超越你们。

于是他们想起了copy-on-write.鼓捣了个MVCC数据库出来。。。

题外话,现在的甲骨文,之所以能在数据库领域保持优势地位,有个很重要的原因也是因为他们是很早就在商业数据库系统中实现了MVCC的数据写入引擎。

所以他们的Thomas Kyte 技术副总裁也就有了在他们的最牛逼的oracle专家编程里面有了吹嘘的资本 XD .

这里我们要着重的介绍一下MVCC,因为这东西看起来非常的精妙而美丽。。。现在大量的分布式类存储中,也都在借鉴这套模式中的很多部分来增加自己的并行度,以提升性能。比如megaStore.比如percolator。

我们在读写锁的实现中,提到了写读的相互阻塞问题,MVCC则使用copy-on-write来解决这个问题。

如果一个人在事务中,会先申请一个事务ID,这个ID是自增的,每个事务都有他自己的唯一的ID,那么他写过的数据,都会被转变为一次带有当前事务ID的新数据,在读取的时候,则只会读取小于等于自己事务ID的数据。这样实现的东东,语义上来说,与可重复读就一样了。而如果读小于等于全局ID的数据,那么这样的实现,就是读已提交了。

一般来说,MVCC只实现了四个级别中的第二级和第三级,其他的就没有啦,不过这两个是我们最常见的级别。所以也就大家同乐,同乐了~

有了这个东西,我们的一致性也就很容易保证了,因为一个事物和他对应的版本号对应,又有更改后的数据和更改前的数据,如果要提交,那么就只需要很简单的让更改后的数据生效可见即可,这样我们可以将大量的更新中要做的事情,都在事务过程中进行,这样,比原有的基于读写锁的必须在commit时候一起做掉来说,commit这个操作就轻量化了很多,于是,就可以支持更多的人(或机器)持有事务状态了。

很美妙吧?

我一致认为这是oracle当年的核心竞争力,不过现在基本上是个数据库就用了这一套,我们就不在多嘴啦~

解决了一致性和隔离性,剩下的是原子性和持久性,原子性么,一般来说就是要么都成功,也就是新版本数据都让他生效,要么就都失败,也就是让和自己事务ID对应的所有修改都无效即可。也很好就解决掉了。持久性。这个就是后面我们要在写入模型里面介绍的东西了,基本上来说就是写磁盘策略的事情。

到这里,我们单机ACID的实现大概思路,就给大家介绍过了。下一个章节,我们还要用很多的文字,来向大家介绍在分布式场景中我们面临的事务的难题,以及“我所知道的”百花齐放的解决方法。

本文来源于"阿里中间件团队播客",原文发表时间" 2011-12-10"

时间: 2024-10-28 05:38:34

海量存储系列之四的相关文章

海量存储系列之八

首先来回答一个问题:为什么在磁盘中要使用b+树来进行文件存储呢? 原因还是因为树的高度低得缘故,磁盘本身是一个顺序读写快,随机读写慢的系统,那么如果想高效的从磁盘中找到数据,势必需要满足一个最重要的条件:减少寻道次数. 我们以平衡树为例进行对比,就会发现问题所在了: 先上个图 这是个平衡树,可以看到基本上一个元素下只有两个子叶节点 抽象的来看,树想要达成有效查找,势必需要维持如下一种结构: 树的子叶节点中,左子树一定小于等于当前节点,而当前节点的右子树则一定大于当前节点.只有这样,才能够维持全局

海量存储系列之十一

上一期我们主要在介绍hash相关的切分方式,那么这次我们来看一下有序结构的切分 有序结构的拆分,目前主要就是使用树或类似树的结构进行拆分,这里主要就是指HBase和MongoDB. 使用树结构切分,带来的好处就如hbase和mongoDB的宣传标语一样,可以无缝的实现自由扩展.但反过来,带来的问题其实也不少,下面我们一起来看一看吧. 首先复习B树知识http://qing.weibo.com/1765738567/693f0847330008ii.html 在B树中,最关键的处理逻辑是如果单个节

海量存储系列之九

终于来到了COLA树系,这套东西目前来看呢,确实不如LSM火,不过作为可选方案,也是个值得了解的尝试,不过这块因为只有一组MIT的人搞了个东西出来,所以其实真正的方案也语焉不详的.从性能来说,tokuDB的写入性能很高,但更新似乎不是很给力,查询较好,占用较少的内存. http://www.mysqlperformanceblog.com/2009/04/28/detailed-review-of-tokutek-storage-engine/ 这里有一些性能上的指标和分析性文字.确实看起来很心

海量存储系列之十二

本章,我们主要来讨论数据的管理和扩容中最重要的一个部分,数据迁移. 数据迁移是数据运维中最为重要的一个部分,在前面的文章中已经提到过,作为有状态的数据节点,在互联网行业的主要追求就是,无限的水平扩展能力,这种水平扩展,主要用于解决两类问题,一类是磁盘空间不足的问题,一类是性能不足的问题. 为了达到这种能力,一般来说主要也就是这样一个思路,尽可能的让数据不动,只通过规则变动的方式来完成扩容,如果这种方式无法满足要求,那么再通过移动数据的方式,来满足其他的一些需求. 下面来进行下分析. 只通过变动规

海量存储系列之十三

在上一章中,我们主要介绍了规则引擎中最重要的一个部分,自动扩容,在今天的章节,我们主要还是介绍一下我们在淘宝TDDL中的工程实践吧. 首先从原理开始吧. 规则引擎是什么呢? 对应在上述例子里面,其实就是DBNum = pk % 3 这个规则. 他的变化可能很多,比如对于一致性hash则变为一个if - else 的表达式(见前面) 也可能有其他的变化. 所以,我们要回归本源,问一个问题,什么是规则引擎? 抽象来看,规则引擎在做的事情是,根据一组输入条件(例如主键id,或者用户id+时间,或者一个

海量存储系列之七

在上一个章节,我们阐述了分布式场景下,事务的问题和一些可能的处理方式后,我们来到了下一章节 Key-value存储 这一章,我们将进入k-v场景,其实,在大部分场景下,如果某个产品宣称自己的写读tps超过其他存储n倍,一般来说都是从k-v这个角度入手进行优化的,主要入手的点是树的数据结构优化和锁的细化,一般都能在一些特定的场景获得5-10倍的性能提升.由此可见key-value存储对于整个数据存储模型是多么的重要. 好吧,那么我们来进入这个章节,用最简单和浅显的话语,阐述这些看起来很高深的理论吧

海量存储系列之一

一个数据库,我们可以抽象的认为由下面的一个逻辑结构组成,刨除意义不大的视图,存储过程,外键限制等之后,我们就剩下了下面的这张图: 从API来说,也就是SQL,结构化查询语言,这个东东我们后面再去细说,先来看看这个关系代数模型. 之所以要从这里开始,主要的原因是因为,这是最受到关注的一个部分,自大从一开始做分布式数据层开始,被人问得最多的问题就是:1. 切分以后如何做join.2.如何进行分布式事务.. 可惜,现在我也没有一个方法能做到100%让您满意..因为,没有银弹,只有取舍. 取舍的原则,也

海量存储系列之六

上次我们讲到,单机事务个我们面临的问题,下面我们来说一些我所知的解决的方法. 在我开始做淘宝数据层的时候,被问得最多的无非也就是:如何做事务,如何做join.至今仍然如此,我一般都会简单而明确的跟对方说:没有高效的实现方法. 虽然没有高效的实现,但实现还是有的.作为引子,我们先来介绍一下这种实现的方式. 我们仍然以上一次讲到的bob和smith为例子来说明好了. 开始的时候.Bob要给smith100块,那么实际上事务中要做的事情是 事务开始时查询bob有多少钱.如果有足够多的钱让bob的账户

海量存储系列之五

在上一章节,我们一起浏览了如何进行单机事务操作.下面我们来看一下分布式场景中我们碰到的问题吧. 需要说明的一点是,这里涉及到的权衡点非常的多.就我短短的工作经验里面,也只是能够简单的涉猎一部分,因为在事务这个领域,目前大家都在尝试提出各种各样的不同的方法,而在taobao,我们目前也没有完美的解决这个问题,更多的是在权衡,在金钱和开发成本之间,做出选择. 那么,我们就先从问题开始,来看一下原来的事务出了什么问题. 在事务中,有ACID四种属性.(见上篇文章) 在分布式场景中,我们看引入了什么因素