NuoDB
by NuoDB

MVCC.第3部分:微小,一致性和可见性

欢迎,令人思想核武器,到MVCC的第3部分概述!在 part 1,我们阐述了MVCC的基础知识,并描述了MVCC如何能够高于传统读/写锁的并发性更高(即使是每行)。在 part 2,我们探讨了MVCC如何在存在交错的读取和更新的情况下工作。这篇文章将涵盖与MVCC保持交易一致性的可见性和微妙之处。

什么是可见性?

我们雇用MVCC的全部原因是增加并发金额我们可以在数据库中合理地支持。这是好的,因为它意味着更高的性能。然而,这意味着系统必须推理大约两个(或更多)的事务同时执行,同时保持一个事务在逻辑上的错觉'在另一个事件之前发生'。在MVCC系统中,可以在表中安装给定记录的多个版本,并且读取事务可能必须计算哪个记录版本是“可见”的,因此应该在事务读取该记录时返回。给定具有多个版本的记录,事务需要弄清楚哪些事务安装了这些版本。通过该信息,任何事务都可以决定在逻辑启动时安装哪个版本。该版本是逻辑上可见的版本。

考虑一个具有大型桌子的系统(数百万行),以及一系列聚合所有行的事务(说明它们)。在执行时,许多短事务即可进入并更新这些行(由于用户操作)。从逻辑上讲,长期运行的事务'在'所有更新之前发生(这是一个快照一致性相当于所有事务的序列排序的情况),因此将有长跑事务读取的错误是错误的长期运行事务后发生的事务更新(假设它正在运行的孤立级别,该级别授权一致的读取行为)。

可见性计算需要几件事:我们需要一种方法来弄清楚哪个事务安装了给定的记录版本(或至少一些高水标记);我们还需要一种对所有最近的交易进行排序,以便我们可以建立部分顺序。第一部分很简单,一些系统实际上使用TransactionID作为版本号,但是,它是一个这样做,能够说能够说出这个行的X由事务创建Y'是重要的。鉴于数据库始终开启,并且可能已经运行了数周/月/岁时,交易数量可能是巨大的。因此,响应可能是更像是在事务y之前发生的事务创建的“这一行的版本x”。第二个要求更加微妙。交易的部分顺序是关于三堆的交易。第一桩是肯定发生的交易(从交易的角度来看,完成了可见性计算);第二桩是肯定发生的交易(思考从长期运行交易的角度犯下短期交易);第三桩是仍然活跃的交易,我们无法做出决定。

此订单不同于严格的序列化(对于那些可能关心的人),它是关于在我们可以“枢转”周围的活动中创造独特的点。这更像是“序列化”的概念,而不是“序列化”,因为可见性并不关心在彼此之前或之后发生的事务顺序,只是他们在前或之后发生的。对于需求一致的读取的隔离级别,唯一的可见记录版本是由交易安装的可见记录版本,该事务肯定是“在执行计算”的事务之前发生的。

一个例子

为了进一步说明可见性,我将采用一个例子。假设具有两个表的数据库。一个地图员工计数划分。另一个地图将划分ID映射到销售数量。现在假设这是销售期结束,一些新的销售人员已被雇用。因此,有两个事务运行以更新这些值(一个要击中员工计数,一个达到销售数量)。让我们假设还有另一个交易,该交易正在收集指标,其中一个是每个员工的平均销售人数。可能的交错如下:

交错更新+读取

 

事务2在交易1仍然处于活动状态时启动,并且交易3开始后开始交易2开始。所以没有明确的“发生在”的关系。因此,它在交易2的肩部上弄清楚哪些值是可见的。让我们假设交易2将读取最新的承诺值。如果它确实这样,它将读取400个销售人员的销售人员计数。这意味着它将计算每位员工的一半销售额,就好像它与所有新的或所有旧值进行了计算。此数字可用于计算奖金,因此将其正确(或至少一致)非常重要。因此,只需阅读最新的承诺值不足以实现读一致性。注意,如果事务2执行一点较慢并阅读交易3提交后读取销售额,则会得到不同的结果。

一般来说,一致性不能依赖于交易执行交织的变幻堂,这提出了应该是什么能力的问题?考虑到相同的交易排序,可见性计算需要一致。也就是说,只要交易1和3都与事务2并发,它必须进行相同的可见性计算。一般来说,应该可见的唯一版本是由交易本身写的,也可以看到的版本,或者被认为是“之前发生的交易”。这基本上意味着在我们的交易开始之前提交的交易。所有其他交易都是可疑的。

在上面的示例中,这意味着交易2,用于一致读取,应该只读取记录100和71的版本。如果稍后再次运行交易2,则将读取两个记录的版本2。一个好的拇指规则是,如果在结束(提交呼叫)重写可见性计算时,事务始终读取的事务将导致所有读取记录的相同记录版本,就像在初始读取时完成的那样。当然,上面的例子纯粹是说明性的。交易1和3可能应该是相同的交易(原子性违规)。但主要点是为了说明可见性不仅仅阅读最新的承诺版本。

新插入的记录

还有一个额外的微妙。如果记录只有一个版本,该怎么办?也就是说,它刚刚安装了另一个交易。应该是可见的吗?同样,对用户期望的隔离级别有一些依赖性,但如果在进行事务后插入行,则该行可以正确地被视为“不可见”,因此根本不会被读取。

我希望有点清除可见性。保持调整忠诚的读者,作为第4部分即将到来,我将描述分布式MVCC,特别强调Nuodb。

看一眼 Part 1Part 2, 和 Part 4 in this MVCC series.