分布式事务
XA两段提交(低效率)-21 XA JTA分布式事务解决方案
- 两个角色:事务协调者、事务参与者
- 两个阶段
- 投票阶段:协调者将通知事务参与者准备提交或取消事务,然后进入表决过程。参与者将告知协调者自己的决策:同意(事务参与者本地事务执行成功,但未提交)或取消(本地事务执行故障);
- 提交阶段:收到参与者通知后,协调者再向参与者发出通知,根据反馈情况决定各参与者是否要提交还是回滚
- 优点: 尽量保证了数据的强一致,适合对数据强一致要求很高的关键领域。
- 缺点: 牺牲了可用性,对性能影响较大,不适合高并发高性能场景,如果分布式系统跨接口调用,目前 .NET 界还没有实现方案。
TCC三段提交(2段,高效率[不推荐(补偿代码)])
- try comfirm cancel
- 主要就是先检查一下子,再提交。 检查没问题了提交应该就没问题,但也有可能出问题,try的时候没问题,但comfirm的时候网络一下中断了,这样的情况出现概率要比两段提交出错概率大
- 需要保证操作是幂等的,try那一下子和comfirm那一下子得到的结果是相同的
- 优点: 跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些
缺点: 缺点还是比较明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。
本地消息(MQ+Table)
- 消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。
- 消息消费方,需要处理这个消息,并完成自己的业务逻辑。
- 此时如果本地事务处理成功,表明已经处理成功了,给消息生产方发送确认消息成功执行的通知
- 如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。
- 优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。在 .NET中 有现成的解决方案。
缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。
事务消息(RocketMQ[alibaba])—>以RocketMQ为例
本地事务给mq服务器发送half消息(该消息mq订阅方收不到)
- mq服务器能收到,然后发一个确认收到
- 本地事务执行和mq消息发送是一个事务,如果事务成功执行并提交,肯定会发送一个commit信息给mq服务器,这时这个消息mq服务器会传给mq订阅方,告诉他完成相应的操作
- 如果没收到消息(本地事务超时或者执行失败回滚了没发消息),mq服务器会隔一段时间查询一下本地事务的状态。如果发现是事务已经失败了,就不管了,如果发现事务只是超时还在进行中,就隔一会再确认一下。
Seata(alibaba)
AT模式
at模式中主要有三个角色:
- 事务协调器:负责维护事务状态,并决定事务的提交和回滚
- 事务管理者:控制全局事务的边界,责发起事务提交或回滚
- 事务参与者:负责本地事务的注册、本地事务状态的汇报(投票),并负责本地事务的提交或回滚
他的核心就在于:任何提交的业务数据的更新一定有相应的回滚日志存在,而且该模式下保证业务数据的更新和回滚日志的写入在同一个 本地事务 中提交。
seata运行流程:
在使用之前要保证,每个数据库都有一张undo_log表
- 执行业务操作时,会把数据源换成seata里面的proxyDataSource
- 换了数据源之后,在开展业务时会进行两个操作,这两个操作捆绑在一个事务中
- 正常业务流程
- 日志记录
- 这个事务具体开展流程是:
- 保存源快照undo_log
- 执行业务sql
- 保存新快照redo_log
- 生成行锁(先把它锁定,在分布式事务没结束之前那谁也不要改这行数据)
- 提交本地事务
- 本地事务没问题了,事务中修改那行数据锁定,然后向tc汇报我这边事务运行情况
- 所有的事务参与者汇报事务执行成功,tc通知大家都没问题,可以删除undo_log了,且取消行锁
- 有一个事务参与者汇报事务执行失败,tc通知大家都回滚,根据undo_log回滚,因为原本行锁锁上了,所以undo_log回滚之后一定是正确的数据
他在运行的过程中,事务正常提交,业务正常运行,不像两阶段提交那样还需要等待,所以效率高。
TCC模式
TCC模式原理就在于使用代码补偿,写三个方法,try(),comfirm(),cancel(),使用代偿业务的补偿以及事务管理器的协调来保证全局事务的一起提交和回滚。