• 沒有找到結果。

基于 MVCC 的分布式事务

在文檔中 分布式系统原理介绍 (頁 53-56)

2 分布式系统原理

2.7 基于 MVCC 的分布式事务

实现分布式事务除了使用类似“两阶段提交”协议等方式外,另一种简单高效的方式就是使用 MVCC(Multi-version Cocurrent Control,多版本并发控制)技术[3][5]。MVCC 技术最初也是在数据库 系统中被提出,但这种思想并不局限于单机的分布式系统,在分布式系统中同样有效。

2.7.1 MVCC 简介

顾名思义,MVCC 即多个不同版本的数据实现并发控制的技术,其基本思想是为每次事务生成 一个新版本的数据,在读数据时选择不同版本的数据即可以实现对事务结果的完整性读取。在使用 MVCC 时,每个事务都是基于一个已生效的基础版本进行更新,事务可以并行进行,从而可以产生 一种图状结构。

图 2-14 MVCC 示例

如图 2-14 所示,基础数据的版本为 1,同时产生了两个事务:事务 A 与事务 B。这两个事务都 各自对数据进行了一些本地修改(这些修改只有事务自己可见,不影响真正的数据),之后事务 A 首先提交,生成数据版本2;基于数据版本 2,又发起了事务 C,事务 C 继续提交,生成了数据版 本3;最后事务 B 提交,此时事务 B 的结果需要与事务 C 的结果合并,如果数据没有冲突,即事务 B 没有修改事务 A 与事务 C 修改过的变量,那么事务 B 可以提交,否则事务 B 提交失败。

MVCC 的流程过程非常类似于 SVN 等版本控制系统的流程,或者说 SVN 等版本控制系统就是 使用的MVCC 思想。

事务在基于基础数据版本做本地修改时,为了不影响真正的数据,通常有两种做法,一是将基 础数据版本中的数据完全拷贝出来再修改,SVN 即使用了这种方法,SVN check out 即是拷贝的过 程;二是每个事务中只记录更新操作,而不记录完整的数据,读取数据时再将更新操作应用到用基 础版本的数据从而计算出结果,这个过程也类似SVN 的增量提交。

Version 1 Version 2 Version 3

Version X

Version 4 事务 A

事务 B

事务 C

事务 B 合并

2.7.2 分布式 MVCC

分布式MVCC 的重点不在于并发控制,而在于实现分布式事务。这里首先给出一个简化的分布 式事务的问题模型,之后对MVCC 的讨论基于该问题展开。假设在一个分布式系统中,更新操作以 事务进行,每个事务包括若干个对不同节点的不同更新操作。更新事务必须具有原子性,即事务中 的所有更新操作要么同时在各个节点生效,要么都不生效。假设不存在并发的事务,即上一个事务 成功提交后才进行下一个事务。

例如,用(site, k, op, oprd)表示在 site 节点上对变量 k 进行 op 操作,操作数为 oprd。那么一 个典型的事务可能是{(site_A, var1, add, 10), (site_B, var2, sub, 1), (site_A, var3, set, 2)},这个事务在 site_A 上将变量 var1 加 10,将变量 var3 设置为 2,在 site_B 上将变量 var2 减 1。

基于MVCC 的分布式事务的方法为:为每个事务分配一个递增的事务编号,这个编号也代表了 数据的版本号。当事务在各个节点上执行时,各个节点只需记录更新操作及事务编号,当事务在各 个节点都完成后,在全局元信息中记录本次事务的编号。在读取数据时,先读取元信息中已成功的 最大事务编号,再于各个节点上读取数据,只读取更新操作编号小于等于最后最大已成功提交事务 编号的操作,并将这些操作应用到基础数据形成读取结果。

例2.7.1:假设系统中有两个节点 A、B。节点 A、节点 B 状态如下表 节点 操作 事务序号 A set var1 = 1 1

A set var2 = 2 1 A set var1 = var1 + 2 2 B set var3 = 2 1 B set var4 = 1 2

1. 若此时全局元信息中的最大的生效事务序号为 1,则在节点 A 上:var1=1,var2=2,在节点 B 上:var3 =2;

2. 若此时全局元信息中的最大的生效事务序号为 2,则在节点 A 上:var1= 1+2=3,var2=2,在节 点B 上:var3=2,var4=1;

从这个例子可以看出,每个节点上保存了对数据的更新操作,也就是数据的增量(delta),从而 可以在读取数据时将应用不同的更新操作得出不同的数据版本。上例中,计算编号小于等于1 的事 务操作得出的数据即为版本号为1 的数据,计算编号小于等于 2 的事务操作得出的数据即为版本号 为2 的数据。在新事务执行过程中,虽然更新操作已经逐步记录到各个节点,但只要全局元信息不 修改,始终不会读到没有生效的事务数据,从而实现了全局一致性。另外,由于数据具有多个版本,

可以自然实现对历史版本数据的读取。

上述方法的一个重要问题是,随着执行的事务越来越多,各个站点保存的更新操作会越来越多,

读取数据时需要应用的更新操作也越来越多。工程中可以对此周期性的启动合并操作,将历史上不 再需要的版本合并为一个更新操作。例如,对例2.7.1 中事务序号小于等于 2 的操作进行合并,合并 后的节点状态如下表:

节点 操作 事务序号 A set var1 = 3 2

A set var2 = 2 2 B set var3 = 2 2 B set var4 = 1 2

这里合并后事务序号设置为合并使用的事务序号。如果节点中存在序号大于2 的操作,则需要 保留这些操作不参与合并。

2.7.3 工程投影

2.7.3.1 Megastore 中的 MVCC

Megastore 利用了 Big Table 中数据的多版本特性实现分布式的更新事务。每个事务更新的都是 不同版本(timestamp)的 Big Table 数据,在读取数据时利用 timestamp 过滤,从而不会读到正在进 行的尚未生效的事务数据。其原理与本节中介绍完全一致,不再赘述。

2.7.3.2 Doris*中的 MVCC

在Doris*系统中,数据按批量进行更新,每个批量的数据都可以认为是一个事务,必须同时原 子性的生效。为此,Doris*将每条数据附带了一个导入的版本号,在读取数据时根据元数据中已生 效的版本号与数据上的导入版本号做过滤,从而不读取正在更新的尚未生效的数据,实现了分布式 事务更新。其详细流量与本节中介绍的一致。

2.8 Paxos 协议

在文檔中 分布式系统原理介绍 (頁 53-56)