2PC
将事务分为两个阶段提交:
- 询问
- 执行
这种分布式事务方案,比较适合在单块应用中,跨多个库的分布式事务。但会严重依赖于服务本身来搞定复杂的事务,效率很低,不适合高并发的场景。
TCC
Try
对各个服务的资源做检测,对资源进行锁定或预留Confirm
在各个服务中执行实际的操作Cancel
如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,即执行已操作成功的业务逻辑的回滚操作
这种方案很少使用,因为这个事务的回滚实际上严重依赖于代码来回滚和补偿,会造成补偿代码巨大
本地消息表
- A系统在本地一个事务里操作的同时,插入一条数据消息表
- A系统将消息发送到MQ
- B系统收到消息后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个continue,保证不会重复处理消息
- B执行成功后,会更新自己本地消息表状态以及A系统消息表的状态
- 如果B执行失败,就不会更新消息表状态,那么A系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到MQ中,让B去处理
保证了最终一致性,哪怕B事务失败了,但A会不断重发消息,直到B成功为止。这种做法严重依赖于数据库的消息表来管理事务,实际也比较少用
可靠消息最终一致性方案
- A发送一个Prepared消息到MQ,如果Prepared消息发送失败,就直接取消操作,不执行了
- 如果成功了,执行本地事务,成功就告诉MQ发送确认消息,失败就告诉MQ回滚消息
- 如果发送了确认消息,B会接收到确认消息,然后执行本地事务
- MQ定时轮询A执行本地成功还是失败,有没有没发送确认的消息,是重试还是回滚
- 如果A回滚了,则执行回滚;如果B失败了,一直重试
这种方法交由MQ来把控,消息先送到B端但不执行,如果A成功了,MQ通知B执行,否则回滚,因此A需要实现一个check接口来让MQ决定是成功还是失败。
最大努力通知
- A本地事务执行完后,发送一个消息到MQ
- 有一个专门消费MQ的最大努力通知服务,会消费MQ,然后写入数据库记录下来,这个调用B的接口。
- 如果B执行成功就ok;如果B执行失败,就尽最大努力通知服务定时尝试重新调用系统B