两阶段提交(2PC) 是 Oracle Tuxedo 系统提出的 XA 分布式事务协议的其中一种实现方式。
XA协议中有两个重要角色:事务协调者和事务参与者
既然叫两阶段提交,肯定是分为两个阶段。
Java 生态下可以使用atomikos来快速实现两阶段提交的分布式事务。
第一阶段
顺利的情况下
- 事务协调者的节点会首先向所有的参与者节点发送 Prepare(预备) 请求。
- 在接到 Prepare(预备) 请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。
- 参与者执行成功,暂时不提交事务,向事务协调节点返回 done(完成) 消息。
- 进入第二阶段
出错时
在XA的第一阶段,如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。
- 事务协调者的节点会首先向所有的参与者节点发送 Prepare(预备) 请求。
- 在接到 Prepare(预备) 请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。
- 参与者执行失败,返回失败消息。
- 协调者中断事务
中断事物
任何一个参与者向协调者反馈了 No 响应,或者在等待超时之后,协调者尚无法接收到所有参与者的反馈响应,那么就会中断事物。
- 发送回滚请求。协调者向所有参与者节点发出 Rollback 请求。
- 事物回滚。参与者收到Rollback请求之后,会利用其在阶段一种记录的 Undo 信息来执行事务回滚操作,并在完成回滚之后释放在整个事物执行期间占用的资源。
- 反馈事物回滚结果。参与者在完成事物回滚之后,向协调者发送 Ack 消息。
- 中断事务
第二阶段
在XA分布式事务的第二阶段,如果事务协调节点在之前所收到都是正向返回,那么它将会向所有事务参与者发出Commit请求。
接到Commit请求之后,事务参与者节点会各自进行本地的事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。
当事务协调者接收到所有事务参与者的“完成”反馈,整个分布式事务完成。
缺点
-
两阶段提交涉及多次节点间的网络通信,通信时间长!且在整个过程中,所有节点都处于阻塞状态,所有节点所持有的资源(例如数据库数据,本地文件等)都处于锁定状态
-
单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
-
数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。