事务就是将对某一数据的多个操作视为原子操作,统一成功,同一失败。单体项目中,使用数据库的事务即可,但在分布式架构下,单体项目的数据库事务就没有用武之地了。
XA 方案
两阶段提交方案。使用的是数据库的资源管理器(RM)和事务管理器(TM)。
第一阶段,告知准备提交。第二阶段,进行提交,若有不能提交的部分,则告知回滚。
TCC 方案
TCC 方案就是 Try、 Confirm、 Cancel。
先尝试,对各个服务的资源进行锁定。随后开始执行操作。当操作执行中出现问题时,进行回滚(补偿机制,根据业务代码,把执行成功的进行回滚)。
本地消息表
- A 系统在自己本地一个事务里操作同时,插入一条数据到消息表。
- 接着 A 系统将这个消息发送到 MQ 中去;
- B 系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息;
- B 系统执行成功之后,就会更新自己本地消息表的状态以及 A 系统消息表的状态;
- 如果 B 系统处理失败了,那么就不会更新消息表状态,那么此时 A 系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到 MQ 中去,让 B 再次处理;
- 这个方案保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 那边成功为止。
该方案严重依赖数据库的消息表来管理事务,高并发场景下不现实。
可靠消息最终一致性方案
- A 系统先发送一个消息到 mq,如果这个消息发送失败那么就直接取消操作别执行了;
- 如果这个消息发送成功过了,那么接着执行本地事务,如果成功就告诉 mq 发送确认消息,如果失败就告诉 mq 回滚消息;
- 如果发送了确认消息,那么此时 B 系统会接收到确认消息,然后执行本地的事务;
- mq 会自动定时轮询所有消息回调你的接口,问你,这个消息是不是本地事务处理失败了,所有没发送确认的消息,是继续重试还是回滚?一般来说这里你就可以查下数据库看之前本地事务是否执行,如果回滚了,那么这里也回滚吧。这个就是避免可能本地事务执行成功了,而确认消息却发送失败了。
- 这个方案里,要是系统 B 的事务失败,就重试,自动不断重试直到成功,如果实在是不行,要么就是针对重要的资金类业务进行回滚。
最大努力通知方案
- 系统 A 本地事务执行完后,发送消息到MQ。
- 有专门消费 MQ 的最大努力通知服务,这个服务消费 MQ 然后写入数据库中进行记录,接着调用系统 B 的接口。
- 要是系统 B 执行成功就结束。系统 B 执行失败,就最大努力定时尝试重新调用系统 B ,反复N 次,如果一直无法执行就放弃。