所有文章
https://www.cnblogs.com/lay2017/p/12078232.html
正文
2pc事务提交协议在实现的角度已经能够在大多数场景满足事务的要求了,但是2pc存在明显的性能问题。而且一旦造成阻塞的连锁反应,可能就是整个系统崩溃的结果。3pc在2pc的基础上做了一些问题处理。
三阶段事务提交协议
canCommit阶段
如图所示,第一个被注意到的明显比2pc多出了一个阶段canCommit。
3pc将2pc的preCommit预提交阶段再拆分成了canCommit和preCommit两个阶段。2pc的preCommit阶段需要我们执行完耗时的业务代码,然后进行事务的预提交,这时候我们才能知道事务预提交是否可以成功,如果这时候超时,那么前面的业务代码就很白费。
所以,preCommit拆分之后,就把事务超时问题先提前询问一次,也就是canCommit阶段需要完成的事情。canCommit阶段默认会返回yes,表示可以进行事务提交,不需要在乎耗时的业务代码。
简单来说,canCommit阶段就是做了一次超时校验。
preCommit阶段
如果在canCommit阶段中并没有超时问题,那么意味着各个数据源认为事务提交是顺利的,于是进入第二个阶段preCommit。
preCommit阶段如2pc的其实差不多,同样是执行业务代码,最后不真正的提交事务,通常是写入事务日志中,做了一次预提交的操作。并返回状态给事务管理器。
2pc的无限制等待造成阻塞的结果,在3pc中被加入了等待超时时间,也就是如果长时间不反悔preCommit的结果,就认为它是失败的。
doCommit阶段
preCommit阶段做了预提交,预提交可能超时,可能成功,可能失败。成功当然是好的,所有数据源进行真正的提交事务即可。如果失败,那么回滚事务即可,这与2pc没有区别。
3pc中,在preCommit有了超时问题,所以doCommit阶段发现超时了就会发送rollback指令,让所有数据源回滚。
但是事务管理器如果发送指令的时候出现网络故障呢?3pc中默认事务参与者(数据源通常)在等待preCommit阶段结束到doCommit开始接收通知也有超时时间,如果超过时间未收到通知,那么就认为收到的是提交事务的指令,参与者自己提交事务。
总结
2pc的阻塞问题非常严重,3pc在此基础上提出了一个超时的概念。为此,也把preCommit阶段拆分成了canCommit和preCommit两个步骤,由此产生3pc。
3pc设置的超时点主要有:
1)canCommit阶段,事务管理器等待参与者响应超时,超时则中断事务;
2)preCommit阶段,事务管理器等待参与者影响超时,超时则回滚事务;
3)doCommit阶段,参与者等待事务管理器的commit或者rollback指令,超时则默认自动commit;
但是纵观整个3pc流程,其实3pc依旧没有解决doCommit阶段网络故障导致的数据不一致问题,反而因为超时机制导致事务自动提交以后,出现了真正的数据一致性问题,连2pc的最终一致性都没有做到。
综合2pc、3pc来看,2pc虽然有严重的效率问题,但是非高并发系统完全可以使用。3pc虽然解决了阻塞问题,一定程度上解决了阻塞的连锁反应,但带来的一致性问题却让人难以接受。
所以,3pc并没有本质上改良2pc,并不是一个好的解决方案。