分布式事务简介
本文最后更新于:3 年前
前言
事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性。分布式事务则是尝试在多节点的环境下实现这些语义。
分布式事务涉及的知识内容较多,本篇博客并没有将其彻底整理清楚,只是简单记录了一下 6.824 课程所学。
内容
对于分布式事务,可以将其细化为并发控制和原子提交两个子问题。前者是在说如何保证并发事务的串行隔离性,后者是在说当数据分片分布在不同的节点上时,如何保证事务在不同节点上提交与否的原子性。
并发控制
对于事务的并发控制模型,一般有两个方向:悲观事务和乐观事务。前者适合于数据竞争严重且重试代价大的场景,后者适用于数据竞争不严重且重试代价不大的场景。
悲观事务
在事务执行过程中对事务所用到的数据都上锁。这里的锁从事务中第一次用到对应数据时开始,直到事务结束时才释放。
2PL(2-Phase-Lock)就是一种典型的悲观事务方法,但并不是到事务结束时才释放所有锁,而是事务过程中一旦不再使用某对象即可释放该对象的锁。因此,6.824 课程中介绍的 2PL 严格来说是 S2PL(Strict-2-Phase-Lock),即所有锁都是在事务结束的同时才释放的。S2PL 相比 2PL 的性能更差,但能够避免级联终止的发生,具体可以参考此 博客。
不论是 2PL 还是 S2PL,都有可能导致死锁,因此一般要从两个方面入手来避免死锁:死锁检测、死锁预防
- 死锁检测:为相互等待的事务之间维护一张 graph, 检测 graph 中是否有环。如果检测到优化,则根据一定的策略选择终止一个事务,打破循环等待。
- 死锁预防:按照一定顺序进行加锁,锁超时则终止等。
S2PL 严格意义上不能解决幻读的问题,因为其加的都是行锁,所以其并不能实现串行隔离性,这一点与 6.824 课程中的介绍似乎有些许出入,等到之后有时间再认真研究一番。
乐观事务
在事务执行过程中获取事务所用到的数据时并不上锁,直到计算完毕提交时才加锁对数据进行验证,若无变化则提交,否则 abort 或重新获取最新数据并计算。
由于分布式乐观事务在提交之前获取数据进行计算时并不需要加锁,因此一般也可以通过结合 RDMA 等技术来显著提升性能。
原子提交
在分布式事务中,参与事务的所有节点必须全部执行 Commit 操作或全部执行 Abort 操作,即他们需要在”执行 Commit 还是 Abort”这一点上达成一致(其实就是共识)。理论上有许多原子提交协议:2PC 和 3PC 等等。
原子提交协议和共识协议:
- 目的相同:
- 共识问题:解决的是如何在分布式系统中的多个节点之间就某个提议达成共识。
- 原子提交问题:解决的是参与分布式事务的所有节点在”执行 Commit 还是 Abort”这一点上达成共识。
- 范围不同:前者要求所有节点达成共识,后者要求大多数未故障的节点达成共识。
有关 2PC, 3PC, TCC, SAGA 等原子提交协议的具体内容,可以参考此 博客。
对于业务上的分布式事务,还有 Seata 和基于 MQ 的分布式事务实现等等,花样很多,但实现各异。他们不是本文的重点,感兴趣自行谷歌即可。
对于数据库内核中的分布式事务实现,一般都是通过 2PC 的方式。为什么不用 3PC 呢?2PC 严格来说是保证了 safety 但牺牲了较多的 liveness(部分场景下资源会被永远锁定),而且正常工作时需要发两轮 RPC 来提交一个事务,其性能是被很多人诟病的一点;3PC 虽然提高了 liveness(资源锁定一定会在有限时间内被解除),但其是以牺牲 safety 为代价的,同时正常工作时需要发三轮 RPC 来提交一个事务,性能更差,因此很多人认为使用 3PC 是实现分布式事务的一条歪路,工业界也几乎很少有人使用 3PC,这一点 PingCAP 的 CTO 在分布式之美论坛上也提到过。
事实上,不论是 Spanner 还是 TiDB,他们的方式都是通过将协调者和参与者都分别组成共识组的方式来避免单点故障,从而在保证 safety 的基础上提升 liveness(由于协调者节点的单点故障被共识组规避掉,参与者的资源锁定一定会在有限时间内被解除),当然,由于每一个操作和决定都需要在共识组中进行同步,不可避免的其性能也会更差,但相比 3PC,其至少没有牺牲 safety,这一点非常关键,因为只要保证了 safety,至少我们可以通过 scale out 的方式来提升性能。
对于 2PC,业界和学术界针对不同的数据模型也有一些特定的优化,比如针对 KV 模型的 Percolator 算法等,它可以将 2PC 在部分场景下优化为 1PC 并结合 Async Commit 的方式来提升性能,这里之后有时间再进行研究吧。
业界也有一些替换 2PC 的声音,可以参考此 博客。
总结
本篇博客简单记录了 6.824 课程中分布式事务的内容,同时进行了一点点分析和拓宽,以做记录。