一 两阶段提交方案(XA事务)
- 实现方式:
第一阶段为准备阶段,由事务管理器向各个事务询问是否可执行,所有的参与者准备执行事务并锁住需要的资源,所有参与者向事务管理器汇报准备好,如果有一个未准备好就取消;
第二阶段为提交阶段。当事务管理器确认所有参与者都Ready 后,向所有参与者发送COMMIT 命令。
- 缺点:
严重依赖数据库本身的事务XA实现,性能低下。
- 适用说明
适合单模块跨多数据库的场景,不适合高并发的场景,也不适合多个系统之间的调用,在现在分布式微服务潮流下,已很少使用。
二 TCC方案(业务逻辑补偿事务)
- 实现方式:
- 第一步 Try: 首先在业务逻辑代码中,进行预先操作,比如连接数据库,冻结需要扣减的资金,冻结库存数据等等;目的是为了确保在下一步数据操作是成功的;(资金冻结,库存冻结可能都不在本系统中,而是其他系统接口)
- 第二步 Confirm:进行实际的业务逻辑操作,进行真正的资金扣减,库存扣减等逻辑;(资金扣减,库存扣减可能都不在本系统中,而是其他系统接口)
- 第三步 Cancel:如果上述步骤出现了异常,那么就执行回退动作,回退也是通过业务逻辑补偿,比如回填资金,回填库存等(资金回填,库存回填可能都不在本系统中,而是其他系统接口);
- 缺点
- 与业务逻辑耦合非常紧密;
- 每个事务的处理代码非常复杂;
- 适用说明
适用在事务粒度非常细,而且业务数据要求非常严格的情况下,比如和钱相关的转账等。大多情况下不适用,因为和业务逻辑耦合非常紧密,需要开发人员自己写代码来补偿,补偿代码会非常之复杂且容易出错。除非必要,不建议适用。
三 本地消息表方案(ebay的MQ事务方案)
- 实现方式:
capture_20190729145426349.jpg
- 系统A在本地数据库增加要给消息表;
- 执行本地事务后,往本地消息表插入一条消息记录;记录有状态(待消费,已消费),同时在zk中设置节点并监听;
- 本地消息表发送消息到MQ;
- 系统B从MQ消费消息,消费时,先插入系统B本地消息表,然后执行系统B本地事务。
- 系统B删除zk中对应节点,触发了A系统的监听;
- 系统A修改消息表中对应消息状态;
- 若系统B执行事务失败或者事务执行太久或者未收到消息,则:
- 系统A开启一个定时轮询,对在一定时间内消息表中状态未改变的消息进行重发操作;
- 系统B需要做好消息处理接口幂等性;
- 缺点:
因为涉及到数据库消息表的读写,所以在性能上有不足,在高并发场景下不大适用。
三 可靠消息最终一致性方案(类似rocketMQ事务方案)
- 实现方式:
capture_20190729145426349.jpg
- 系统A先发送prepare消息到MQ(若消息发送失败,则整体失败,这里主要是确保MQ可用);
2.系统A执行本地事务,事务成功告诉MQ确认消息,事务失败告诉MQ回滚消息;MQ收到确认消息,则触发系统B执行本地事务。- 系统B执行本地事务;(如果本地事务执行失败,那么就重复执行,直到成功。也可以系统B进行回滚,然后通过其他途径如zk告知A系统,让A系统重发消息或者进行回滚,也可以记录下来进行人工补偿)。
- 针对prepare消息,rocketmq3.2.6版本之前会定期轮询,然后回调系统A接口,让系统A反馈这个消息因为事务已经回滚/失败了还是成功了,如果是成功了,就进行消息确认,如果失败/回滚了,就进行消息回滚操作。rocketmq3.2.6之后版本无此功能。
- 适用场景
这是国内大多数互联网公司的使用的解决方案,如果不用rocketMQ事务方案,那么可以自己基于activitiMQ或者rabbitMQ封装来实现。
网友评论