分布式事务解决方案

    xiaoxiao2021-04-12  80

    1、什么是分布式事务

    分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

    2、分布式事务的产生的原因

    2.1、数据库分库分表

    当数据库单表一年产生的数据超过1000W,那么就要考虑分库分表,具体分库分表的原理在此不做解释,以后有空详细说,简单的说就是原来的一个数据库变成了多个数据库。这时候,如果一个操作既访问01库,又访问02库,而且要保证数据的一致性,那么就要用到分布式事务。

                                                 

    2.2、应用SOA化

    所谓的SOA化,就是业务的服务化。比如原来单机支撑了整个电商网站,现在对整个网站进行拆解,分离出了订单中心、用户中心、库存中心。对于订单中心,有专门的数据库存储订单信息,用户中心也有专门的数据库存储用户信息,库存中心也会有专门的数据库存储库存信息。这时候如果要同时对订单和库存进行操作,那么就会涉及到订单数据库和库存数据库,为了保证数据一致性,就需要用到分布式事务。

                                                                 

    以上两种情况表象不同,但是本质相同,都是因为要操作的数据库变多了!

    3、事务的ACID特性

    3.1、原子性(A)

    所谓的原子性就是说,在整个事务中的所有操作,要么全部完成,要么全部不做,没有中间状态。对于事务在执行中发生错误,所有的操作都会被回滚,整个事务就像从没被执行过一样。

    3.2、一致性(C)

    事务的执行必须保证系统的一致性,就拿转账为例,A有500元,B有300元,如果在一个事务里A成功转给B50元,那么不管并发多少,不管发生什么,只要事务执行成功了,那么最后A账户一定是450元,B账户一定是350元。

    3.3、隔离性(I)

    所谓的隔离性就是说,事务与事务之间不会互相影响,一个事务的中间状态不会被其他事务感知。

    3.4、持久性(D)

    所谓的持久性,就是说一单事务完成了,那么事务对数据所做的变更就完全保存在了数据库中,即使发生停电,系统宕机也是如此。

    4、分布式事务的应用场景

    4.1、支付

    最经典的场景就是支付了,一笔支付,是对买家账户进行扣款,同时对卖家账户进行加钱,这些操作必须在一个事务里执行,要么全部成功,要么全部失败。而对于买家账户属于买家中心,对应的是买家数据库,而卖家账户属于卖家中心,对应的是卖家数据库,对不同数据库的操作必然需要引入分布式事务。

    4.2、在线下单

    买家在电商平台下单,往往会涉及到两个动作,一个是扣库存,第二个是更新订单状态,库存和订单一般属于不同的数据库,需要使用分布式事务保证数据一致性。

    5、常见的分布式事务解决方案

    5.1、基于XA协议的两阶段提交

    XA是一个分布式事务协议,由Tuxedo提出。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理如下:

                                                          

    总的来说,XA协议比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。但是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,往往并发量很高,XA无法满足高并发场景。XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回导致主库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得非常狭隘。

    5.2、事务消息

    所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操作成功成功并且对外发消息成功,要么两者都失败,开源的RocketMQ就支持这一特性。

    具体的关于一些事务消息的东西,我这边也提供了2偏自己认为比较好的文章

    https://www.itcodemonkey.com/article/13548.html

    https://www.jianshu.com/p/04bad986a4a2

    事务消息缺点:

       事务消息也有自己的瓶颈,使用事务消息前提是服务之间没有相互依赖性。下面的需求就不适用用事务消息:电商一笔订单完成,并扣除该用户的现金余额。订单的完成是依赖现金余额的,总不能都没有现金或者现金不够就订单完成v吧。像这种场景,事务消息就不适用了,订单事务和现金事务几乎要一起提交、回滚的,并不是订单事务先提交后去保证现金事务提交

    5.3、TCC编程模式

    上面的事务消息是解决分布式事务的一个方案,但事务消息也有自己但一个瓶颈,就是要使用事务消息,必须保证服务A,和服务B在业务上没有相互依赖d

    所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,以前下单动作一般就是先将订单状态变为已下单状态,如何就是将库存相应的减掉。tcc就是相当于对了一个中间阶段,try阶段会将订单变成一个中间状态-下单中,库存这边就是将会增加一个冻结库存数量对字段,库存数量减掉,并且冻结库存数量相应对增加。confirm状态才是进行我们一开始想象对操作,将订单改为已经正常下单,库存数量减少,冻结库存为0。当try阶段失败的时候cancel阶段就开始起作用了,cancel的作用就是还原到try之前的状态。

    tcc的核心思想:

    1,try阶段是为confim阶段提前做一个预执行(预测试),提前锁定一些资源,提前测试一些环境是否正常,比如数据库,redis之类的中间件是否正常

    2,各个try阶段都成功之后,才执行相应的confirm阶段,当try阶段完成时,我们认为confirm会大概率完成

    3,try阶段失败时,cancel阶段会返回try阶段执行之前的状态

    上面就是对于tcc模式的一个概括性的总结,但很多细节性但东西都是空的,比如下面的一些问题

    tcc模式的问题:

    1,怎么知道哪些try阶段成功哪些失败了?,如果都成功了,如何通知可以执行confirm阶段了

    2,如果大概率成功的confirm阶段,cancel阶段执行失败了怎么办?

    3,如果在try阶段,cancel阶段,机器突然挂了怎么办?

    。。。

    上面的一些问题就是要一个个去解决,不过现在国内的一些tcc框架(ByteTCC,TCC-transaction,Himly。)已经有成熟的了,不用自己花大量的时间去做一个tcc框架。

    针对的上面的问题,一些框架的做法:

    1,tcc框架会利用相关的通信技术,获取各个阶段的状态,通知各个阶段可以执行,或者不能执行

    2,tcc框架会利用日志记录各个分布式事务相关操作状态,当cancel,confirm阶段失败时首先会进行重试(所以这里要做好幂等),如果真的一直没有成功,一般会进行事务补偿

    3,第二条也说了框架会把活动的日志以文件的形式,或者数据库的形式保存,具体看框架的时候,这样即使失败了,当重启的时候又会继续挂机之前的流程

    附上好文章的地址https://www.cnblogs.com/jajian/p/10014145.html

    6、总结

    分布式事务,本质上是对多个数据库的事务进行统一控制,按照控制力度可以分为:不控制、部分控制和完全控制。不控制就是不引入分布式事务,部分控制就是各种变种的两阶段提交,包括上面提到的消息事务+最终一致性、TCC模式,而完全控制就是完全实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数据一致性减弱了,完全控制则是牺牲了性能,保障了一致性,具体用哪种方式,最终还是取决于业务场景。作为技术人员,一定不能忘了技术是为业务服务的,不要为了技术而技术,针对不同业务进行技术选型也是一种很重要的能力!

    本人:

    分布式事物,无非就是增加一层中间件,我忘记在哪里看到的一句话,无论什么问题都是通过增加一层中间件解决的。分布式事物也就是在原先的事物上增加一层控制器,保持两个基本的事物保持一致。换句话就是分布式事物=基础事物+中间件(jms,管理层。。。。。)

    转载请注明原文地址: https://ju.6miu.com/read-667100.html

    最新回复(0)