并行与分布式系统中的分布式事务并发控制:多版本时间戳排序(MVTO)算法
在分布式数据库中,多个客户端可能并发地读写相同的数据项,若不加控制会导致不一致。MVTO(Multiversion Timestamp Ordering)是一种经典的分布式并发控制算法,它通过为每个写操作创建数据项的新版本,并利用时间戳来调度读写操作,从而保证可串行性(serializability),同时避免读写冲突。
题目描述
假设有一个分布式键值存储系统,数据项分布在多个节点上。每个事务(由一组读写操作组成)在发起时被分配一个唯一的时间戳。系统需要处理并发事务,保证:
- 可串行性:事务的并发执行效果等价于按时间戳顺序串行执行。
- 避免脏读:事务不能读取未提交的数据。
- 避免不可重复读:同一事务内对同一数据项的多次读取应得到相同值。
MVTO算法需要为每个数据项维护多个版本(每个写操作创建一个新版本),并根据事务时间戳选择合适的版本进行读取,同时确保写操作不会破坏时间戳顺序。
解题过程循序渐进讲解
步骤1:理解MVTO的基本数据结构
每个数据项(例如键K)关联一个版本链,每个版本包含:
value:该版本存储的值。wts:写入该版本的事务的时间戳。rts:读到该版本的所有事务的最大时间戳(初始等于wts)。
每个事务T_i在启动时被分配一个唯一时间戳ts(T_i)(通常单调递增)。分布式系统中可使用逻辑时钟(如Lamport时钟)或混合逻辑-物理时钟生成全局有序时间戳。
步骤2:MVTO的读操作规则
当事务T_i(时间戳为ts(T_i))要读取数据项K时:
- 在
K的版本链中,找到满足wts ≤ ts(T_i)的最大wts的版本(即事务时间戳之后第一个更晚的版本的前一个版本)。 - 读取该版本的值。
- 更新该版本的
rts为max(rts, ts(T_i))(表明有更晚的事务读了这个版本)。
为什么这样选择版本? 这保证了事务读取的是在它开始之前已提交的、时间戳最接近的写操作所写的值,从而符合时间戳顺序的串行等效。
步骤3:MVTO的写操作规则
当事务T_i要写入数据项K(设新值为v)时:
- 找到
K的版本链中满足wts ≤ ts(T_i)的最大wts的版本,记其rts为rts_max。 - 如果
ts(T_i) < rts_max,则中止T_i(因为已有更晚的时间戳的事务读过这个值,如果T_i写入,会破坏那些事务读到的值)。 - 否则,创建
K的一个新版本,设置value = v、wts = ts(T_i)、rts = ts(T_i),并插入版本链(按wts排序)。
为什么需要检查rts? 如果ts(T_i) < rts_max,意味着已经有时间戳更大的事务(在T_i之后开始)读了一个旧版本,如果允许T_i写入新版本,那么那些更晚的事务本应该读到T_i写的新值(按时间戳顺序),但实际上读了旧值,违反了可串行性。
步骤4:事务提交与版本清理
- 事务
T_i完成后(提交或中止),如果是提交,则其写入的所有新版本变为已提交版本,可被后续读操作看到。 - 版本链中,若某版本
V的rts < wts'(其中wts'是链中下一个版本的wts),则V可被垃圾回收(因为不会有事务再读它)。
步骤5:分布式环境下的挑战与优化
在分布式系统中,数据项可能被分区存储在不同节点。MVTO需要:
- 全局时间戳:使用跨节点的单调递增时间戳服务(如TrueTime、Hybrid Logical Clocks)或时间戳Oracle。
- 版本链的存储:每个数据项的主副本节点维护其版本链。读操作只需访问主副本;写操作需先读主副本检查
rts,通过后再写入新版本。 - 并发控制:节点内对每个数据项的版本链的访问需加锁(如读写锁)以确保原子性。
优化:可引入“快照读”(snapshot read)——事务开始时获取一个时间戳,所有读操作都基于该时间戳读取相应版本,避免在事务过程中因rts更新而选择不同版本。
举例说明
假设数据项K初始版本为V0:value=5,wts=1,rts=1。
- 事务
T2(ts=2)写K=10:找到V0(wts=1,rts=1),因2 ≥ 1,创建V1:value=10,wts=2,rts=2。 - 事务
T3(ts=3)读K:找到V1(wts=2 ≤ 3),读值10,更新V1.rts = max(2,3)=3。 - 事务
T1(ts=1)写K=7:找到V0(wts=1,rts=1),因1 < 3(rts=3来自T3的读),中止T1。
最终,版本链为V0(wts=1)→ V1(wts=2),执行等价于串行顺序T2 → T3。
总结
MVTO通过多版本避免了读-写阻塞,读操作总可立即完成(选择合适的版本),提高了并发度。但写操作可能因时间戳顺序冲突而中止,且需要维护版本链的存储开销。在分布式环境中,全局时间戳的生成和版本链的分布式管理是关键挑战。该算法是许多现代分布式数据库(如CockroachDB、YugabyteDB)的并发控制基础之一。