Electronic Joint Business

Solution for E-Business

MVCC (一)概述

本文的作者是 Trek Palmer,他是 NuoDB 的工程师,负责实现及调试 NuoDB 的 Atom 层。在过去的一年中, Palmer 一直致力于分布式事务一致性方面的研究。在与客户的沟通中, Palmer 发现最常被问起的问题之一就是:如何在接受众多节点的更新的同时保持一致性。答案就是:分布式上下文中多版本并发控制(MVCC) 的实现。想要理解这一点,你必须对 MVCC 有相当的了解。Palmer 是并发方面的专家,也当过教师,所以他在博客上对 MVCC 做了一系列的详细的技术解释。1 2 MVCC 剑指何方? 数据库的设计思想很纯粹:攫取数据、保存数据、并按所需的格式返回数据。出于实用性考虑,任何数据库都应能同时处理尽可能多的请求。 SQL 是一种声明性语言。也就是说,像 average 这样的 SQL 语句并未规定它该如何执行,只是罗列了数据库执行语句时要操作的参数。当程序员与数据库交互时,细节部分被转交给了数据库本身。这是好事,意味着应用逻辑和数据存储的细节的分离。这样做的后果之一是,数据库本身要能管理多个并发客户端。特别是,数据库需要处理在不同事务(来自多个客户端)同时读取和写入同一数据片的情况。 如果你看过传统的并行代码,可能会问“为什么不使用读/写锁?”。这种想法是合理的,而且多年来也一直为一些数据库所使用。然而,它有个严重的问题。简单地说,读阻塞写,写阻塞读。读/写锁的语义本身就是如此,没什么特别惊讶的。然而,这些语义对任何事务型数据库的性能都会产生严重的不良影响。 思考一下,假如系统中有两种事务:一种是只读的长事务,用于创建报告或者数据分析。一般只有一两个并发用户。而另一些是与用户进行交互的短事务,比如说在线下单,这类交互通常包括两读和一写(或两写)。并发用户可能有成千上万。读/写锁的问题是,如果短事务的写操作与长事务的读操作之间有任何数据重叠,短事务会被阻塞,直到长事务完成。对习惯互联网消费的人来说,哪怕长事务只是造成订单延迟几秒钟,也是不能接受的。问题在于如何同时保证合理延迟和最高并发性。理想情况下,阻塞只应在事务真的影响另一事务更新数据行时才发生(实际上,阻塞只是可用的数据库并发控制机制之一) 。拿上面的例子来评估,情况应该是:长事务永远不应造成短事务阻塞;短事务之间除非更新到同一行,否则不应互相影响或阻塞。当读/写锁力不从心时,这一壮举该如何完成?对 NuoDB 和许多现代数据库来说, 答案是:多版本并发控制。 什么是 MVCC? 你可能会说,“很好,我了解 MVCC 要解决什么问题了,不过是如何解决的呢?” 答案就在它的名字中。对非 MVCC 数据库来说,每条既定记录都有其固定存储点,并在该存储点上进行着各种花销的锁,而 MVCC 数据库允许既定记录同时拥有多个版本。每次对数据行进行更新都会产生一个新版本。因此,写操作竞争的是往数据行最高版本之上添加新版本的权利,而读操作则可以读取任何可见版本。对上面的例子来说,这意味着只读的长事务永远不会锁定数据行。因此不会导致短事务被阻塞。而且,只有两个(或更多)短事务争相获得某个数据行版本的更新权利时,才会彼此干扰。如果在维护事务中的可见性信息的同时找出可见的数据行版本,MVCC 就可以实现数据库快照。实际上,当事务开始时,它会“冻结”一揽子数据记录版本作为其可见数据集。对这些版本进行更新逻辑上发生在事务读取该数据集之后(哪怕执行事务的线程没有实际读取该数据行版本) 。要支持 MVCC 语义你需要的是:记录存储系统,可以为同一记录保存不同版本;某种锁定系统,可以让其它事务知道记录被同步更新了;以及将记录版本号翻译为事务ID 的机制,以进行可见性计算。 SQL 和 MVCC MVCC 还可以用来实现 […]

,

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.