分布式系统的挑战:分布式事务
Posted 吃土都不吃土豆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式系统的挑战:分布式事务相关的知识,希望对你有一定的参考价值。
1、prepare阶段:redo持久化到磁盘,并将回滚段置为prepared状态,此时binlog不做操作。
上图其实并不太直观,举一个实际例子。当我们要执行update语句时,完成的操作流程图如下:
当应用启动一个分布式事务时,它向协调者请求一个全局唯一的事务ID。
应用在每个参与者上启动单节点事务,并在单节点事务上捎带上这个全局事务ID。所有的读写都是在这些单节点事务中各自完成的。如果在这个阶段出现任何问题(例如,节点崩溃或请求超时),则协调者或任何参与者都可以中止。
当应用准备提交时,协调者向所有参与者发送一个准备请求,并打上全局事务ID的标记。如果任意一个请求失败或超时,则协调者向所有参与者发送针对该事务ID的中止请求。
参与者收到准备请求时,需要确保在任意情况下都的确可以提交事务。这包括将所有事务数据写入磁盘(出现故障,电源故障,或硬盘空间不足都不能是稍后拒绝提交的理由)以及检查是否存在任何冲突或违反约束。
当协调者收到所有准备请求的答复时,会就提交或中止事务作出明确的决定(只有在所有参与者投赞成票的情况下才会提交)。协调者必须把这个决定写到磁盘上的事务日志中,如果它随后就崩溃,恢复后也能知道自己所做的决定。这被称为提交点(commit point) 。
一旦协调者的决定落盘,提交或放弃请求会发送给所有参与者。
上述完整的实现原理存在两个不可撤销的动作:
参与者投“是”后所有的操作不得再做拒绝。通过向协调者回答“是”,节点承诺,只要请求,这个事务一定可以不出差错地提交。换句话说,参与者放弃了中止事务的权利,但没有实际提交。
协调者做“提交”后所有的动作必须成功。如果这个请求失败或超时,协调者必须永远保持重试,直到成功为止。没有回头路:如果已经做出决定,不管需要多少次重试它都必须被执行。如果参与者在此期间崩溃,事务将在其恢复后提交,由于参与者投了赞成,因此恢复后它不能拒绝提交。
如果在propose阶段一个节点做了拒绝,则协调器需要向所有节点执行abort命令以此释放占用的锁,此时满足原子性要么整体成功要么整体失败的要求。
两阶段提交的缺陷
可以看到两阶段提交的核心是协调器(coordinator),这就避免不了单点故障问题。假设协调器也是集群,单节点故障可以通过下一章要说的共识之主节点选择来解决,但上一章提到了无法保证数据强一致性,恢复后对已有事务的执行阶段仍无法做到强一致性,这意味着一旦单节点的主协调器发送故障,会出现一些意外之外的错误。前几篇文章中强调了一点:无论如何都不要过分相信网络。如果在2PC执行阶段发生故障又会如何呢?
如果在Propose阶段协调器发送奔溃或者网络分区,由于所有节点的事务未提交,数据并未生效,参与者可以安全的终止事务。
如果在Commit阶段某些节点已经收到Commit指令,随后协调器发生奔溃或者网络分区导致消息不可达,其他未提交的节点会因为事务未提交而发生数据不一致的情况。除非协调器从故障中恢复并能判断事务未完成状态,否则就会发现严重的数据不一致问题,同时也不满足事务的原子性要求。再回到上一章提到的预写日志的方式,待协调器恢复后读取完成状态存疑的事务,重新提交未完成的事务便可将事务继续执行到完成状态。如果存在数据丢失,则参与者会一直保持独占锁,直到管理员对事务进行判断手动执行提交或者回滚。
三阶段提交
通过分析发现两阶段提交会受到协调器的限制,所以2PC也被称为阻塞原子提交协议。为了使原子提交协议变成非阻塞的,一种被称为三阶段提交(3PC)算法被提出用以取代两阶段提交。三阶段提交在两阶段提交的基础上增加了CanCommit阶段,并引入了超时机制。一旦事务参与者迟迟没有收到协调者的Commit请求,就会自动进行本地commit,这样相对有效地解决了协调者单点故障,同时也解决了阻塞提交的问题。
结合2PC遇到如果在Commit阶段某些节点已经收到Commit指令,随后协调器发生奔溃或者网络分区导致消息不可达,由于在PreCommit阶段存在参与者投了“否”的操作,在Commit阶段超时时间结束后如果仍然没有收到协调器abort操作的话,会执行自动提交。这就引入了数据不一致的问题。
同时3PC不能处理网络分区的问题。考虑在PreCommit之前参与者被一分为二,新的协调者接管了voter3,不同的协调者可能做出不一致的决定,最终导致数据不一致问题。
3PC假定了一个有界的网络延迟和节点规定时间内响应,考虑到目前大多数网络具有无限延迟和进程暂停的情况,3PC无法保证原子性。在具有无限延迟的网络中,超时并不是一种可靠的故障检测机制,以为即使节点没有奔溃,请求也可能由于网络问题而超时,所以尽管大家都清楚2PC因为协调者故障导致的阻塞问题,但仍然被广泛使用。
分布式事务的限制
分布式事务解决了多个参与者相互达成一致的现实问题,但从2PC和3PC的实现来看,引入了非常严重的运维问题,同时高昂的网络开销造成的严重性能下降,在实际生活生产中也因此而毁誉参半。尽快已经提出了许多启发式决策,但这只是分布式事务在解决应急场景下的一种承诺,无法作为常规手段使用,数据强一致性在DB层面仍无法保证做到完美,越来越多的技术与应用开始从最终一致性来保障分布式事务的执行,譬如TCC协议——一个从应用层来感知最终提交成功与否并从业务层面进行回滚的模型,以及柔性事务——一个从MQ进行异步消息传递以此来解决阻塞和解耦的事件处理机制。
以上是关于分布式系统的挑战:分布式事务的主要内容,如果未能解决你的问题,请参考以下文章