分布式事务的解决方案

首先什么是分布式事务,就是说事务的参与者,支持事务的服务器,资源服务器以及事务管理器都分布在不同的分布式系统的不同节点上。一个事务的执行需要这些不同节点上的小的事务的共同执行完成,要么全部成功,要么全部失败。

为什么要用分布式事务,这是由于分布式系统的出现而我们不得不去实现的一个东西,因为在原来的单体应用上,我们的一个业务流程全在一个系统中,服务之间是挨个调用的,只需要加一个@transactional注解即可解决事务的问题,而在分布式系统中,我们的一个操作可能会调用许多不同的模块,而这些模块都部署在不同的服务器上,需要这些服务每个都实现自己的事务,整体的业务的事务才能够成功,所以必须使用分布式事务来进行控制。

再来提一下分布式理论:

首先是cap理论,C(consistency)一致性,在同一时刻的不同节点中,对同一个数据的读取结果必须是一致的。 A(available)可用性,整个系统必须保持高可用性,某个节点故障后,系统还是能够响应客户端的请求。 P(partiton tolerance)分区容错性,就是指因为网络问题导致某个节点无法连接上,形成故障分区,这个是一定会出现的问题,无法避免。

所以一个系统只能在可用性和一致性上做取舍。

其次是base理论,basically available 基本可用,就是说系统出现了不可预知的故障,但是还可以使用,只是与正常的系统相比:1,响应时间上的损失,我也不是响应不了,但是要慢一点 2,功能上的损失,在高并发大流量的时候,系统可能会进行熔断降级,是一些服务无法使用,但是不影响你的基础的主要业务。 soft state 软状态,就是指在系统的整个大过程中,允许出现不同的节点之间拿到的同一个数据出现不一致的情况。 eventually consistent 最终一致性,就是通过一定时间的同步之后,各个节点上的副本数据必须保持一致性。

就是不要求强一致性,但是还是最后落脚点在一致性上,我给你时间去同步,但是不同永远同步不成功,说明系统最重要的还是需要实现一致性,以至于用时间或者是服务体验功能上去牺牲来成全它。

下面来介绍一下分布式事务的解决方法:

一,两阶段提交

首先这种协议有两个角色,事务的协调者和事务的参与者,事务的提交分为两个阶段,第一阶段(投票阶段):假设A是事务的协调者,B,C是事务的参与者,A首先将要执行的命令写入日志,然后发送一个准备的命令给B和C,B和C收到命令后,自己去执行然后判断自己自己是否能够提交,并将处理结果记录到日志系统中,然后将各自的处理结果发送给A。  第二阶段(决定阶段):A收到B和C的处理结果之后,判断是否所有的参与者都可以成功提交自己的事务,如果可以就发送commit命令,并将操作写入日志,如果有一个不可以则发起回滚命令,并记录日志,B和C收到命令之后,执行提交或者回滚的命令,并记录在自己的日志系统中,最后将执行的结果返回给A。

这种方式可能会存在的问题:1,单点故障,如果事务协调器节点出现故障,那么整个系统就无法进行事务操作了。  2,数据不一致,如果在二阶段的时候,事务协调器在发送提交或者回滚的命令之后,没多久网络出现了故障,致使有一部分节点没有收到命令,就会导致节点之间的数据不一致。  3,响应时间较长,整个事务的提交是串行化的执行过程,需要等待最后的响应结果,不适合高并发的场景。  4,不确定性,如果事务协调器发送完命令之后,是commit命令,如果有一个节点执行成功了,这时候事务协调器以及所有的节点都宕机了,系统重新选举出事务协调器之后就无法确定该条事务是否提交成功。

二,三阶段提交

这种协议的角色与二阶段提交是一致的,先来看下三阶段的具体流程,第一阶段(cancommit阶段):协调者询问事务参与者是否能完成此次事务,如果都返回yes,则进入第二阶段,如果有一个返回no或者等待响应超时,则事务中断,并向所有参与者发送回滚的命令。  第二阶段(precommit阶段):协调者会向所有的参与者发送precommit命令,参与者收到以后开始执行各自的事务操作,并将undo和redo信息记录到事务日志中,参与者完成各自的事务操作后,这时候不管成功与否都还没有提交,成功的会向事务协调器发送ack确认,我已准备好提交,等待事务协调器的下一步指示。  第三阶段(docommit阶段):如果收到了所有事务参与者的ack确认,那么协调者就会转变成提交状态,向所有的事务参与者节点发送docommit命令,参与者收到命令后就会进行各自事务的提交,并向协调者发送ack确认,协调者收到所有事务参与者的ack确认后,事务完成。如果有一个事务参与者未完成precommit命令,那么就向所有参与者发送回滚命令,事务失败。

三,补偿事务(TCC)

首先TCC就是try,commit和cancel三个单词的缩写,这就是一个应用层的两阶段提交,因为要使用这个必须在每个涉及到的模块中编入代码,自己写好这三种方法的具体实现,比如说用一个电商的系统进行举例,首先try阶段:就是用户下完订单以后,该模块会去调用需要配合订单模块实现的其他模块中的try接口,然后各个模块中的try方法去预留自己需要的系统资源,判断是否能够进行后续的具体业务操作,然后把成功与否告知事务协调者。  confirm或者cancel阶段:这个阶段开始真正去执行业务,不用做业务检查,就是用try阶段预留出来的资源,如果事务协调者发送提交命令就去各自操作,最后结果返回给事务协调者,如果是要进行回滚操作,就是调用cancel函数,进行失败的回滚操作,把预留的冻结的资源释放出来。

TCC事务与上面所述的二阶段提交的一些不同:1,首先解决了协调者单节点故障的问题,因为这是一个应用层的操作,就意味我的主要业务流程的应用可以使用一个集群部署多个服务器节点,这样增加了容错。  2,同步阻塞,因为引入了try阶段可以提前去冻结我需要操作的资源,这样锁死的资源的粒度就比较细小,不会造成全局的大范围上锁,使高并发比较适用。  3,保证了数据的一致性,有了补偿机制之后,由业务管理控制器统一控制一致性。

四,本地消息表

它的执行流程就是:首先是消息生产方需要创建一个消息表,记录消息的发送状态,消息表和业务数据要在一个事务里进行提交,然后消息经过消息队列发送给消息消费方,如果消息发送失败就会重新发送。然后消息的消费方需要去处理这条消息,并且完成自己的业务逻辑,如果是业务上面的失败就向消息发送方发送一个回滚的命令,通知生产方进行回滚操作,如果本地事务处理成功,就表明这个消息处理成功事务成功。如果处理失败就会重新执行。生产方和消费方会定时扫描消息表,把没有发送成功的数据再发送一遍或者把处理失败的消息再消费一遍。

五,消息事务

就是利用消息中间件将局部事务进行异步解耦,执行流程:首先发送prepare消息到消息中间件中,发送成功后开始执行自己的本地事务,如果执行成功,就commit提交,消息中间件将这条消息下发到后面需要继续执行的关联事务中(消费端),如果本地事务执行失败,就执行回滚操作,消息中间件就删除这条消息,消费端接到了这条消息就开始消费,如果消费失败就会进行不断重试。这种方案实现了最终一致性,也提高了事务执行的效率,我都默认我后面的事务会执行成功,如果我执行成功就提交,而且把事务消息放到消息中间件中就会增加流量的承载能力,适用于高并发场景。

六,最大努力通知

它的执行流程是:最先被调用的系统执行自己的本地事务,如果执行成功了,就把这条消息发送到消息中间件里,会有个服务专门对接消息中间件消费里面的消息,这个服务会调用下一个需要执行此业务流程的系统,要是下个系统执行成功了,就成功,如果执行失败,最大努力机制就会尝试重新调用这个系统,反复N次,如果还是失败就算了,对最终一致性要求不高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值