2PC和3PC协议

2PC two-phase-commit 即两阶段提交

2PC和3PC协议
1.Coordinator协调者发送vote-request给所有的参与者,如果参与者任务可以提交则返回vote-commit,否则返回vote-abort 
2.当所有的参与者都返回vote-commit时候,Coordinator发送global_commit全部提交,否则发送global-abort,全部取消


1.如果参与者挂了(后面恢复),协调者正常,则不会影响数据一致性,
2.如果参与者挂了(后面恢复),协调者正常,恢复后参与者如果发现有未执行完的事务操作,直接取消,然后再询问 Coordinator 目前我应该怎么做,协调者就会比对自己的事务执行记录和该参与者的事务执行记录,告诉他应该怎么做来保持数据的一致性。
3.协调者挂了,参与者正常,则会重新找一个协调者询问所有参与者的最后那条事务的执行情况,他就可以知道是应该做什么样的操作了。所以,这种情况不会导致数据不一致。


如果参与者和协调者同时挂了
1.第一阶段挂了,新选出来的协调者Coordinator,会询问各个参与者的情况,然后再做决定是commit还是abort,因为还没有commit,所以不会出现一致性问题
2.如果是在第二阶段挂了,但是协调者还没有发送相应的操作,这个时候新选出来的协调者Coordinator,会询问各个参与者的情况,然后再做决定是commit还是abort,因为还没有commit,所以不会出现一致性问题
3.如果是在第二阶段挂了,但是协调者挂之前,已经发送相应的操作,这时候新选择出来的协调者也不知道上一个协调者做了什么操作,这种情况下,新的 Coordinator 被选出来之后,如果他想负起 Coordinator 的责任的话他就只能按照之前那种情况来执行 commit 或者 roolback 操作。这样新的 Coordinator 和所有没挂掉的参与者就保持了数据的一致性,我们假定他们执行了 commit。但是,这个时候,那个挂掉的参与者恢复了怎么办,因为他已经执行完了之前的事务,如果他执行的是 commit 那还好,和其他的机器保持一致了,万一他执行的是 roolback 操作呢?这不就导致数据的不一致性了么?虽然这个时候可以再通过手段让他和 Coordinator 通信,再想办法把数据搞成一致的,但是,这段时间内他的数据状态已经是不一致的了

简单总结一下 2PC 的优缺点:

优点:原理简洁清晰、实现方便;
缺点:同步阻塞、单点问题、某些情况可能导致数据不一致。
关于这几个缺点,在实际应用中,都是对2PC 做了相应的改造:

同步阻塞:2PC 有几个过程(比如 Coordinator 等待所有参与者表决的过程中)都是同步阻塞的,在实际的应用中,这可能会导致长阻塞问题,这个问题是通过超时判断机制来解决的,但并不能完全解决同步阻塞问题;
Coordinator 单点问题:实际生产应用中,Coordinator 都会有相应的备选节点;
数据不一致:这个在前面已经讲述过了,如果在第二阶段,Coordinator 和参与者都出现挂掉的情况下,是有可能导致数据不一致的。


所以,2PC协议中,如果出现协调者和参与者都挂了的情况,有可能导致数据不一致。为了解决这个问题,衍生出了3PC。

3PC three-phase-commit 三阶段提交,最关键要解决的就是 Coordinator 和参与者同时挂掉导致数据不一致的问题,所以 3PC 把在 2PC 中又添加一个阶段,这样三阶段提交就有:CanCommit、PreCommit 和 DoCommit 三个阶段

2PC和3PC协议

第一阶段CanCommit
1.协调者发送CanCommit请求,询问是否可以执行事务提交,并等待参与者的响应返回
2.如果所有参与者都返回YES。则表示可以执行事务,否则不执行事务

第二阶段PreCommit阶段
执行事务预提交:如果 Coordinator 接收到各参与者反馈都是Yes,那么执行事务预提交
1.协调者向所有参与者发送PreCommit请求,并进入prepared阶段
2.所有参与者接收到PreCommit,会执行事务,并将undo和redo添加进事务日志中
3.各参与者向协调者返回事务执行结果返回ACK响应,

中断事务:如果任何一个参与者向 Coordinator 反馈了 No 响应,或者在等待超时后,Coordinator 无法接收到所有参与者的反馈,那么就会中断事务。
1.发送中断请求:Coordinator 向所有参与者发送 abort 请求;
2.中断事务:无论是收到来自 Coordinator 的 abort 请求,还是等待超时,参与者都中断事务。


第三阶段doCommit阶段
假如协调者接收到所有的参与者的ACK响应
1.发送提交请求:假如协调者接收到所有的参与者的ACK响应,那么将从预提交阶段到提交阶段,并向所有参与者发送doCommit请求
2.事务提交:参与者接收到doCommit请求后,提交事务,并在完成后释放资源
3.反馈事务提交结果:参与者提交完事务后,会向协调者发送ACK消息
4.协调者接收到所有的ACK消息,完成事务


中断事务:假设 Coordinator 正常工作,并且有任一参与者反馈 No,或者在等待超时后无法接收所有参与者的反馈,都会中断事务
1.发送中断事务:向所有的参与者发送abort事件
2.事务回滚,所有接收到abort命令的参与者,利用undo事务日志进行回滚,并回滚后,释放资源
3.反馈事务回滚结果:参与者完成回滚后,向协调者发送ACK消息。
4.协调者接收到所有的参与者的ACK消息,中断事务

3PC 虽然解决了 Coordinator 与参与者都异常情况下导致数据不一致的问题,3PC 依然带来其他问题:比如,网络分区问题,在 preCommit 消息发送后突然两个机房断开,这时候 Coordinator 所在机房会 abort, 另外剩余参与者的机房则会 commit。

而且由于3PC 的设计过于复杂,在解决2PC 问题的同时也引入了新的问题,所以在实际上应用不是很广泛。