2PC

将事务分为两个阶段提交:

  1. 询问
  2. 执行

image.png

这种分布式事务方案,比较适合在单块应用中,跨多个库的分布式事务。但会严重依赖于服务本身来搞定复杂的事务,效率很低,不适合高并发的场景。

TCC

  • Try对各个服务的资源做检测,对资源进行锁定或预留
  • Confirm在各个服务中执行实际的操作
  • Cancel如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,即执行已操作成功的业务逻辑的回滚操作

这种方案很少使用,因为这个事务的回滚实际上严重依赖于代码来回滚和补偿,会造成补偿代码巨大

本地消息表

  1. A系统在本地一个事务里操作的同时,插入一条数据消息表
  2. A系统将消息发送到MQ
  3. B系统收到消息后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个continue,保证不会重复处理消息
  4. B执行成功后,会更新自己本地消息表状态以及A系统消息表的状态
  5. 如果B执行失败,就不会更新消息表状态,那么A系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到MQ中,让B去处理

保证了最终一致性,哪怕B事务失败了,但A会不断重发消息,直到B成功为止。这种做法严重依赖于数据库的消息表来管理事务,实际也比较少用

可靠消息最终一致性方案

  1. A发送一个Prepared消息到MQ,如果Prepared消息发送失败,就直接取消操作,不执行了
  2. 如果成功了,执行本地事务,成功就告诉MQ发送确认消息,失败就告诉MQ回滚消息
  3. 如果发送了确认消息,B会接收到确认消息,然后执行本地事务
  4. MQ定时轮询A执行本地成功还是失败,有没有没发送确认的消息,是重试还是回滚
  5. 如果A回滚了,则执行回滚;如果B失败了,一直重试

这种方法交由MQ来把控,消息先送到B端但不执行,如果A成功了,MQ通知B执行,否则回滚,因此A需要实现一个check接口来让MQ决定是成功还是失败。

最大努力通知

  1. A本地事务执行完后,发送一个消息到MQ
  2. 有一个专门消费MQ的最大努力通知服务,会消费MQ,然后写入数据库记录下来,这个调用B的接口。
  3. 如果B执行成功就ok;如果B执行失败,就尽最大努力通知服务定时尝试重新调用系统B