分布式事务2PC 3PC

505 阅读4分钟

前言

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

2PC 两阶段提交协议

image-20211013201803294

2PC是典型的强一致性、中心化的原子提交协议,中心化是指模型中具有1个中心化的协调者,和多个和参与者

协调者:事务协调者。协调者会向参与者发送消息去判断事务是否可正常执行,如果参与者返回YES,则会进一步发送commit消息,让参与者进行事务提交。

参与者:每个独立出来的业务模块,比如订单服务,支付服务。参与者会在本地进行事务的预提交,即执行事务,但是不提交。如果成功,则向协调者发送YES的消息,告诉协调者,该事务可以正常执行;否则发送NO的消息。协调者知道NO了之后,则会发送abort消息(中断指令),让参与者进行事务回滚。

执行流程:

第一阶段:投票

  1. 当请求发过来时,事务协调者会向所有的参与者发送事务预提交请求。
  2. 参与者接受到来自协调者的预提交请求后,会在本地进行事务的预提交,在这个阶段,会写bin/undo log,为后续的提交操作和回滚操作做准备。在本阶段的事务是不会提交的。如果事务可以正常执行,则会向协调者发送YES;否则发送NO

第二阶段:提交/回滚

  1. 如果协调者接受到参与者是YES的消息,则会发送commit消息,告诉参与者可以进行事务提交;如果其中接收到一个NO的消息或者遇到超时情况没有收到参与者的消息反馈,则会向所有参与者发送abort请求,要求参与者中断事务,执行rollback回滚操作。
  2. 参与者根据从协调者那里收到的消息,执行提交或者回滚操作。

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阶段,参与者进行提交,因为经过了前面两个阶段,大概率是执行成功的,因此即使超时了,也会执行提交操作,如果误杀了,就通过脚本补偿的方式弥补