分布式事务以及几种实现方式
两阶段提交/2PC事务/TC事务
为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法
分布式系统中每个节点能知道自己的事务是否成功,但是无法知道其他节点的事务是否成功,所以需要引入一个协调者
两阶段提交分为两阶段:
Prepare准备阶段:协调者向所有的参与者询问是否可以参与事务提交,参与者能提交回复协调者YES,不能提交或者响应超时回复NO
Commit提交阶段:如果第一阶段汇总所有参与者都返回 Yes 响应,协调者向所有参与者发出提交请求,所有参与者提交事务,否则回滚
二阶段提交优点:尽量保证了数据的强一致,但不是 100% 一致。
二阶段提交缺点:
- 单点故障,由于协调者的重要性,一旦协调者发生故障,参与者会一直阻塞,尤其是在第二阶段,协调者发生故障,那么所有的参与者都处于锁定事务资源的状态中,而无法继续完成事务操作。
- 同步阻塞,由于所有节点在执行操作时都是同步阻塞的,当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
- 数据不一致,在第二阶段中,协调者向参与者发送提交事务,发生局部错误。接到提交事务请求的参与者会执行提交事务,未接收到提交事务的参与者无法提交事务。从而导致分布式系统中的数据不一致。
适合于同一应用对多个数据源的操作,比如分库操作
三阶段提交/3PC事务(非阻塞)
CanCommit准备阶段:询问参与者是否可以参与提交事务,参与者返回Yes或者No
PreCommit确认阶段:如果全部Yes那么参与者就执行事务,否则参与者中断事务,操作完成之后返回ACK确认
DoCommit提交阶段:所有参与者返回ACK,提交事务,否则中断事务
改进了两阶段提交的单点故障和同步阻塞,如果协调者挂掉会选举一个新的协调者
三阶段提交的问题和二阶段的 数据不一致 是一样的
如何解决分布式事务导致的数据不一致情况
最终一致性分布式事务方案
本地消息表(基于本地数据库和MQ)
本地消息表的核心思想是将分布式事务拆分成本地事务进行处理。该方法需要额外维护一张消息表
- A系统执行完自己的本地事务之后,往中间消息表中插入一条消息,标记一个消息状态,并发送一条MQ给B系统
- B系统接收到MQ消息之后开始执行自己的本地事务
- 如果B系统的事务执行成功,那么就通过RPC调用修改中间消息表的状态为完成或者删除该消息
- 否则执行失败,B系统事务回滚,等待A系统再次发送MQ到B系统
- 做一个监控机制,防止就是系统Bug导致B系统消费不成功,方便人为及时介入
MQ消息事务(基于RocketMQ)
A系统执行自己的本地事务,并发送 MQ 消息,B系统接收消息,执行自己的本地事务。
补偿事务 TCC
- Try 阶段:对业务系统做检测及资源预留。
- Confirm 阶段:对业务系统做确认提交,Try 阶段执行成功并开始执行 Confirm 阶段时,默认 Confirm 阶段是不会出错的。即:只要 Try 成功,Confirm 一定成功。
- Cancel 阶段:在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
基于 TCC 实现的分布式事务框架:
ByteTCC,github.com/liuyangming
tcc-transaction:github.com/changmingxi