2PC(Two-phase commit protocol),中文叫二阶段提交。
二阶段提交是一种强一致性设计,2PC 引入一个事务协调者的角色来协调管理各参与者(也可称之为各本地资源)的提交和回滚,二阶段分别指的是准备(投票)和提交两个阶段。
XA 是由 X/Open 组织提出的分布式事务的规范,XA 规范主要定义了(全局)事务管理器(TM)和(局部)资源管理器(RM)之间的接口。本地的数据库如 MySQL 在 XA 中扮演的是 RM 角色。
XA 一共分为两阶段:
- 第一阶段(prepare):即所有的参与者 RM 准备执行事务并锁住需要的资源。参与者 ready 时,向 TM 报告已准备就绪。
- 第二阶段 (commit/rollback):当事务管理者(TM)确认所有参与者(RM)都 ready 后,向所有参与者发送 commit 命令。
目前主流的数据库基本都支持 XA 事务,包括 MySQL、Oracle、SQL Server、Postgre。
XA 事务由一个或多个资源管理器(RM)、一个事务管理器(TM)和一个应用程序(ApplicationProgram)组成。
如果有任何一个参与者 prepare 失败,那么 TM 会通知所有完成 prepare 的参与者进行回滚。
XA 事务的特点是:
- 简单易理解,开发较容易
- 对资源进行了长时间的锁定,并发度低
三阶段提交又称 3PC,相对于 2PC 来说增加了 CanCommit 阶段和超时机制。
如果段时间内没有收到协调者的 commit 请求,那么就会自动进行 commit,解决了 2PC 单点故障的问题。但是性能问题和不一致问题仍然没有根本解决。
下面我们还是一起看下三阶段流程的是什么样的?
第一阶段:CanCommit 阶段。这个阶段所做的事很简单,就是协调者询问事务参与者,你是否有能力完成此次事务。
如果都返回 yes,则进入第二阶段。有一个返回 no 或等待响应超时,则中断事务,并向所有参与者发送 abort 请求。
第二阶段:PreCommit 阶段。此时协调者会向所有的参与者发送 PreCommit 请求,参与者收到后开始执行事务操作,并将 Undo 和 Redo 信息记录到事务日志中。
参与者执行完事务操作后(此时属于未提交事务的状态),就会向协调者反馈“Ack”表示我已经准备好提交了,并等待协调者的下一步指令。
第三阶段:DoCommit 阶段。在阶段二中如果所有的参与者节点都可以进行 PreCommit 提交,那么协调者就会从“预提交状态”转变为“提交状态”。
然后向所有的参与者节点发送"doCommit"请求,参与者节点在收到提交请求后就会各自执行事务提交操作,并向协调者节点反馈“Ack”消息,协调者收到所有参与者的 Ack 消息后完成事务。
相反,如果有一个参与者节点未完成 PreCommit 的反馈或者反馈超时,那么协调者都会向所有的参与者节点发送 abort 请求,从而中断事务。
③SAGASaga 是这一篇数据库论文 saga 提到的一个方案。其核心思想是将长事务拆分为多个本地短事务,由 Saga 事务协调器协调,如果正常结束那就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作。
把上面的转账作为例子,一个成功完成的 SAGA 事务时序图如下:
SAGA 事务的特点:
- 并发度高,不用像 XA 事务那样长期锁定资源
- 需要定义正常操作以及补偿操作,开发量比 XA 大
- 一致性较弱,对于转账,可能发生 A 用户已扣款,最后转账又失败的情况
2PC 是数据库层面的,而 TCC 是业务层面的分布式事务,就像我前面说的分布式事务不仅仅包括数据库的操作,还包括发送短信等,这时候 TCC 就派上用场了!
TCC 的 3 个阶段:
- Try 阶段:尝试执行,完成所有业务检查(一致性), 预留必须业务资源(准隔离性)
- Confirm 阶段:确认执行真正执行业务,不作任何业务检查,只使用 Try 阶段预留的业务资源,Confirm 操作要求具备幂等设计,Confirm 失败后需要进行重试。
- Cancel 阶段:取消执行,释放 Try 阶段预留的业务资源,也可以理解为可以理解为把预留阶段的动作撤销了。Cancel 阶段的异常和 Confirm 阶段异常处理方案基本上一致,要求满足幂等设计。
把上面的转账作为例子,通常会在 Try 里面冻结金额,但不扣款,Confirm 里面扣款,Cancel 里面解冻金额。
一个成功完成的 TCC 事务时序图如下:
TCC 特点如下:
- 并发度较高,无长期资源锁定
- 开发量较大,需要提供 Try/Confirm/Cancel 接口
- 一致性较好,不会发生 SAGA 已扣款最后又转账失败的情况
- TCC 适用于订单类业务,对中间状态有约束的业务
本地消息表其实就是利用了 各系统本地的事务来实现分布式事务。