三阶段提交三阶段提交协议(Three-phase commit protocol,3PC),是二阶段提交(2PC)的改进版本。与两阶段提交不同的是,三阶段提交有两个改动点:
- 引入超时机制。同时在协调者和参与者中都引入超时机制。
- 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。
即 3PC 把 2PC 的准备阶段再次一分为二,这样三阶段提交就有 CanCommit、PreCommit、DoCommit 三个阶段。
CanCommit 阶段CanCommit 阶段其实和 2PC 的准备阶段很像。协调者向参与者发送 commit 请求,参与者如果可以提交就返回 Yes 响应,否则返回 No 响应。
- 事务询问:协调者向参与者发送 CanCommit 请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
- 响应反馈:参与者接到 CanCommit 请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回 Yes 响应,并进入预备状态。否则反馈 No
PreCommit 阶段协调者根据参与者的反应情况来决定是否可以记性事务的 PreCommit 操作。根据响应情况,有以下两种可能。
- 假如协调者从所有的参与者获得的反馈都是 Yes 响应,那么就会执行事务的预执行。
- 发送预提交请求:协调者向参与者发送 PreCommit 请求,并进入Prepared 阶段。
- 事务预提交:参与者接收到 PreCommit 请求后,会执行事务操作,并将undo 和 redo 信息记录到事务日志中。
- 响应反馈:如果参与者成功的执行了事务操作,则返回 ACK 响应,同时开始等待最终指令。
- 假如有任何一个参与者向协调者发送了 No 响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
- 发送中断请求:协调者向所有参与者发送 abort 请求。
- 中断事务:参与者收到来自协调者的 abort 请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
doCommit 阶段该阶段进行真正的事务提交,也可以分为以下两种情况。
- 执行提交
- 发送提交请求:协调接收到参与者发送的 ACK 响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送 doCommit 请求。
- 事务提交:参与者接收到 doCommit 请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
- 响应反馈:事务提交完之后,向协调者发送 ACK 响应。
- 完成事务:协调者接收到所有参与者的 ACK 响应之后,完成事务。
- 中断事务:协调者没有接收到参与者发送的 ACK 响应(可能是接受者发送的不是 ACK 响应,也可能响应超时),那么就会执行中断事务。
- 发送中断请求:协调者向所有参与者发送 abort 请求
- 事务回滚:参与者接收到 abort 请求之后,利用其在阶段二记录的undo 信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
- 反馈结果:参与者完成事务回滚之后,向协调者发送 ACK 消息
- 中断事务:协调者接收到参与者反馈的 ACK 消息之后,执行事务的中断。
在 doCommit 阶段,如果参与者无法及时接收到来自协调者的 doCommit 或者 rebort 请求时,会在等待超时之后,会继续进行事务的提交。即当进入第三阶段时,由于网络超时等原因,虽然参与者没有收 到 commit 或者 abort 响应,事务仍然会提交。
三阶段提交不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的 abort 响应没有及时被参与者接收到,那么参与者在等待超时之后执行了 commit 操作,这样就和其他接到 abort 命令并执行回滚的参与者之间存在数据不一致的情况。 |