NuoDB
by NuoDB

多版本并发控制第1部分:概述

问候,技术精湛的人!我是NuoDB的工程师之一。我大部分时间都在实现和调试NuoDB的原子层上。在过去的一年中,我一直在生活和呼吸分布式事务一致性。最近,我有机会直接与NuoDB的客户和用户互动,经常出现的问题之一是,面对多个节点上数量惊人的同时更新,我们如何保持一致性。答案是,实际上,我们有一个在分布式上下文中工作的多版本并发控制(MVCC)实现。但是,要完全意识到这一点,必须对MVCC有一个体面的了解。

我是一个大的并发书呆子,而且我以前也曾当过老师,所以我抓住机会来解释技术知识。因此,我将通过在MVCC上发布一系列入门来开始写博客。首先,我将抽象地描述MVCC,然后再深入探讨NuoDB如何利用MVCC语义来实现完全事务型分布式数据库。因此,不用多说,我将介绍MVCC。

还有MVCC吗?

数据库是简单的灵魂。他们想要摄取您的数据,珍惜它们并以您需要的任何形式将其返回给您(程序员)。出于实用性考虑,任何有价值的数据库都应允许同时处理尽可能多的请求。 SQL是一种声明性语言。这意味着您的平均SQL语句不决定如何执行该语句,而只是列出执行该语句时数据库应在其中操作的参数。这意味着与数据库交互的程序员将对特定细节的控制权转让给数据库本身。这是一件好事。真的这意味着应用程序逻辑与数据存储的细节分离了。其结果是数据库本身需要能够管理多个并发客户端。具体而言,数据库需要处理多个事务(来自多个客户端)正在同时读取和写入同一数据的情况。

那些研究常规并发代码的读者可能会看这句话,并说“为什么不使用读/写锁?”。这是一个合理的要求,多年来,许多数据库(以某种形式或另一种形式)采用了这种要求。但是,这种方法存在严重的问题。即,那个读者阻碍了作家,而作家阻碍了读者。这些当然是读/写锁的语义,并不太令人震惊。但是,这些语义对于任何事务数据库都可能严重影响性能。

考虑一个有两种交易的系统。其中一项是大型的长期阅读交易,正在建立某种报告(或进行某些新型分析)。这些人一次只能跑一个。另一种事务是运行时间短的用户操作。几次读取和两次写入。说是订单要求或其他内容。这些家伙可能有成千上万。读/写锁定的问题在于,如果长时间运行的事务的读取数据集与任何短期运行的事务的写入数据集之间完全重叠,则短期事务可能必须阻塞,直到长时间运行的事务完成为止。在当今如此疯狂的互联网络世界中,即使长时间运行的事务实际上只运行了几秒钟,订单处理中的这种延迟也是无法接受的。因此,问题仍然是要有尽可能高的并发性和合理的等待时间保证。理想情况下,仅当事务确实在为另一个事务争夺更新特定行的“权利”时才应该阻塞(实际上,阻塞只是数据库并发控制机制可以采用的一种方法)。在上面的信封示例中,长时间运行的交易永远不会导致短期运行的交易受阻。除非两个短时事务实际上正在更新同一行,否则它们不会相互干扰/阻塞。当读/写锁定使我们失败时,我们如何实现这一壮举?答案(至少对于NuoDB和许多现代数据库而言)是多版本并发控制。

什么是MVCC?

太棒了,您可能会说,现在我知道MVCC应该解决什么问题。 “如何解决?”答案在名字里。 DB不仅简单地为给定记录提供了一个预定的存储点,并对其进行了一系列精美的锁定,它还使给定记录具有了多个同时版本。更新现在正在安装新版本的行。因此,作者正在争权将新版本添加到该行的最高版本中,而读者可以读取任何可见版本。在上面的示例中,这意味着长时间运行的读取事务永远不会锁定任何内容。因此,它不会导致任何短期交易被阻止。并且,只有当两个(或多个)事务争夺对特定行版本的更新权限时,它们才能相互干扰。如果维护一个可见性信息,以便对于给定的事务,可以发现某行的哪些版本可见,则可以使用MVCC来实现数据库的快照。实际上,当事务开始时,它将“冻结”记录版本的集合作为其可见集合。现在,从逻辑上讲,对这些版本的更新是在该事务读取后进行的(即使执行该事务的线程实际上并未读取该行版本)。支持MVCC语义所需要的全部是:允许您存储同一记录的不同版本的记录存储系统,允许某种锁定的系统,通过该锁定其他事务知道正在同时更新记录,以及一种允许一种将记录版本号转换为事务ID,以便可以进行可见性计算。

SQL和MVCC

 给定MVCC系统,它可以用于实现SQL语义。 SQL提供了各种“隔离级别”,这些“隔离级别”基本上是一个旋钮,允许程序员拨入所需的一致性级别(假设一致性越差,性能就越高)。在MVCC的背景下,这意味着当一个事务达到另一个事务正在更新的记录时,所采取的措施取决于隔离级别。在最低的一致性级别上,可以允许事务在更新事务提交之前读取更新(“脏读取”)。难看,但是很快。下一级别的一致性将防止脏读,并且只会读取根据交易可见性计算出的版本。这就是“一致阅读”。更新更加复杂。命中经历未提交更新的记录版本的更新尝试有两个选择,它可能会吓跑并立即失败,或者可以等待更新事务完成并根据提交状态做出决定。低隔离级别将很快失效,因为从逻辑上讲,它们会看到事务的更新。高隔离度/一致性级别将需要阻止(或根据您的喜好重试),直到知道记录的最终状态为止。

希望这使您对MVCC感兴趣。