分布式事务的实现原理详解
两阶段提交的执行过程就跟它的名字一样分为两个阶段,投票阶段和提交阶段,在投票阶段中,协调者(Coordinator)会向事务的参与者(Cohort)询问是否可以执行操作的请求,并等待其他参与者的响应,参与者会执行相对应的事务操作并记录重做和回滚日志,所有执行成功的参与者会向协调者发送 AGREEMENT 或者 ABORT 表示执行操作的结果。 ![]() two-phase-commit-voting-phase 当所有的参与者都返回了确定的结果(同意或者终止)时,两阶段提交就进入了提交阶段,协调者会根据投票阶段的返回情况向所有的参与者发送提交或者回滚的指令。 ![]() two-phase-commit-commit-phase 当事务的所有参与者都决定提交事务时,协调者会向参与者发送 COMMIT 请求,参与者在完成操作并释放资源之后向协调者返回完成消息,协调者在收到所有参与者的完成消息时会结束整个事务;与之相反,当有参与者决定 ABORT 当前事务时,协调者会向事务的参与者发送回滚请求,参与者会根据之前执行操作时的回滚日志对操作进行回滚并向协调者发送完成的消息,在提交阶段,无论当前事务被提交还是回滚,所有的资源都会被释放并且事务也一定会结束。 两阶段提交协议是一个阻塞协议,也就是说在两阶段提交的执行过程中,除此之外,如果事务的执行过程中协调者永久宕机,事务的一部分参与者将永远无法完成事务,它们会等待协调者发送 COMMIT 或者 ROLLBACK 消息,甚至会出现多个参与者状态不一致的问题。 ![]() two-phase-commit-problems 3PC 为了解决两阶段提交在协议的一些问题,三阶段提交引入了超时机制和准备阶段,如果协调者或者参与者在规定的之间内没有接受到来自其他节点的响应,就会根据当前的状态选择提交或者终止整个事务,准备阶段的引入其实让事务的参与者有了除回滚之外的其他选择。 ![]() Three-phase_commit_diagra 当参与者向协调者发送 ACK 后,如果长时间没有得到协调者的响应,在默认情况下,参与者会自动将超时的事务进行提交,不会像两阶段提交中被阻塞住;上述的图片非常清楚地说明了在不同阶段,协调者或者参与者的超时会造成什么样的行为。 XA 事务 MySQL 的 InnoDB 引擎其实能够支持分布式事务,也就是我们经常说的 XA 事务;XA 事务就是用了我们在上一节中提到的两阶段提交协议实现分布式事务,其中事务管理器为协调者,而资源管理器就是分布式事务的参与者。 ![]() two-phase-commit-and-xa-transaction 到这里,其实我们已经能够清晰地知道 MySQL 中的 XA 事务是如何实现的: 资源管理器提供了访问事务资源的能力,数据库就是一种常见的资源管理器,它能够提交或者回滚其管理的事务; 事务管理器协调整个分布式事务的各个部分,它与多个资源管理器通信,分别处理他们管理的事务,这些事务都是整体事务的一个分支。 ![]() distributed-transaction-and-transactions 正如两阶段提交协议中定义的,MySQL 提供的 XA 接口可以非常方便地实现协议中的投票和提交阶段,我们可以通过一下的流程图简单理解一下 MySQL XA 的接口是如何使用的: ![]() mysql-xa-transaction-states XA 确实能够保证较强的一致性,但是在 MySQL XA 的执行过程中会对相应的资源加锁,阻塞其他事务对该资源的访问,如果事务长时间没有 COMMIT 或者 ROLLBACK,其实会对数据库造成比较严重的影响。 Saga 两阶段提交其实可以保证事务的强一致性,但是在很多业务场景下,我们其实只需要保证业务的最终一致性,在一定的时间窗口内,多个系统中的数据不一致是可以接受的,在过了时间窗口之后,所有系统都会返回一致的结果。 Saga 其实就一种简化的分布式事务解决方案,它将一系列的分布式操作转化成了一系列的本地事务,在每一个本地事务中我们都会更新数据库并且向集群中的其他服务发送一条的新的消息来触发下一个本地的事务;一旦本地的事务因为违反了业务逻辑而失败,那么就会立刻触发一系列的回滚操作来撤回之前本地事务造成的副作用。 LLT 相比于本地的数据库事务来说,长事务(Long Lived Transaction)会对一些数据库资源持有相对较长的一段时间,这会严重地影响其他正常数据库事务的执行,为了解决这一问题,Hector Garcia-Molina 和 Kenneth Salem 在 1987 发布了论文 Sagas 用于解决这一问题。 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |