前言
2PC:两阶段提交协议,是比较早的分布式事务的模型。比如后面阿里的Seata也是基于2PC的进一步优化而来的。
2PC 两阶段提交协议

2PC是典型的强一致性、中心化的原子提交协议,中心化是指模型中具有1个中心化的协调者,和多个和参与者。
协调者:事务协调者。协调者会向参与者发送消息去判断事务是否可正常执行,如果参与者返回YES,则会进一步发送commit消息,让参与者进行事务提交。
参与者:每个独立出来的业务模块,比如订单服务,支付服务。参与者会在本地进行事务的预提交,即执行事务,但是不提交。如果成功,则向协调者发送YES的消息,告诉协调者,该事务可以正常执行;否则发送NO的消息。协调者知道NO了之后,则会发送abort消息(中断指令),让参与者进行事务回滚。
执行流程:
第一阶段:投票
- 当请求发过来时,事务协调者会向所有的参与者发送事务预提交请求。
- 参与者接受到来自协调者的预提交请求后,会在本地进行事务的预提交,在这个阶段,会写bin/undo log,为后续的提交操作和回滚操作做准备。在本阶段的事务是不会提交的。如果事务可以正常执行,则会向协调者发送YES;否则发送NO
第二阶段:提交/回滚
- 如果协调者接受到参与者是YES的消息,则会发送commit消息,告诉参与者可以进行事务提交;如果其中接收到一个NO的消息或者遇到超时情况没有收到参与者的消息反馈,则会向所有参与者发送abort请求,要求参与者中断事务,执行rollback回滚操作。
- 参与者根据从协调者那里收到的消息,执行提交或者回滚操作。
2PC主流的两种方案
XA
这里就不讲解了,传统xa就是案例上将的 prepare阶段事务没提交,需要由事务管理器来确认事务是否提交,这样导致传统2PC会一直持有资源锁,性能差
Seate
是由阿里中间件团队发起的开源项目 Fescar,后更名为Seata,它是一个是开源的分布式事务框架。由于篇幅过长,这里就不过多介绍,需要另开一篇进行分享。
2PC的缺点:
- 执行过程中,所有参与节点都是事务阻塞型的,当参与者占有公共资源时,其他第三方节点进入阻塞状态(数据库连接资源)效率低,资源占用大
- 不能100%保证事务,在第二次提交的时候,断网了
- 中心化带来的问题,如果协调者出现故障,参与者也会一致阻塞下去。
如果出现数据不一致的情况,需要进行相应的补偿措施。可以是人工补偿或是脚本定时去扫描补偿。
3PC 三阶段提交协议
为了解决资源占用的问题,引出了三阶段
第一阶段 can commit
不占用资源 协调者问发送canCommit消息,问参与者能不能做,能做参与者就返回yes,不能就no,没有真正的去执行事务(以前是要去占用资源)yes的话就执行pre 阶段,no的话或者等待超时,就执行事务中断,协调者向参与者发送abort请求
第二阶段 pre commit
pre commit 预提交,跟以前的一样 如果参与者成功的执行了事务操作,则返回ACK响应;
第三阶段 do commit
do commit 协调者接收到ack消息之后,向参与者发送doCommit消息,执行正式的事务提交,事务提交完了,参与者再向协调者发送ack响应。
如果参与者没有收到提交指令,还是会选择提交,并不会选择回滚
3PC和2PC的区别
二阶段只有协调者有超时机制,三阶段参与者和协调者都有超时机制,
协调者超时 :在can commit,pre commit中,如果收不到参与者的反馈,则发送中断指令
参与者超时:在pre commit阶段,参与者进行中断;do commit阶段,参与者进行提交,因为经过了前面两个阶段,大概率是执行成功的,因此即使超时了,也会执行提交操作,如果误杀了,就通过脚本补偿的方式弥补