java分布式事务,及解决⽅案
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、在线下单
买家在电商平台下单,往往会涉及到两个动作,⼀个是扣库存,第⼆个是更新订单状态,库存和订单⼀般属于不同的数据库,需要使⽤分布式事务保证数据⼀致性。
java技术介绍百度百科
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就⽀持这⼀特性,具体原理如下:
1、A系统向消息中间件发送⼀条预备消息
2、消息中间件保存预备消息并返回成功
3、A执⾏本地事务
4、A发送提交消息给消息中间件
通过以上4步完成了⼀个消息事务。对于以上的4个步骤,每个步骤都可能产⽣错误,下⾯⼀⼀分析:
步骤⼀出错,则整个事务失败,不会执⾏A的本地操作
步骤⼆出错,则整个事务失败,不会执⾏A的本地操作
步骤三出错,这时候需要回滚预备消息,怎么回滚?答案是A系统实现⼀个消息中间件的回调接⼝,消息中间件会去不断执⾏回调接⼝,检查A事务执⾏是否执⾏成功,如果失败则回滚预备消息
步骤四出错,这时候A的本地事务是成功的,那么消息中间件要回滚A吗?答案是不需要,其实通过回调接⼝,消息中间件能够检查到A执⾏成功了,这时候其实不需要A发提交消息了,消息中间件可以⾃⼰对消息进⾏提交,从⽽完成整个消息事务
基于消息中间件的两阶段提交往往⽤在⾼并发场景下,将⼀个分布式事务拆成⼀个消息事务(A系统的
本地操作+发消息)+B系统的本地操作,其中B系统的操作由消息驱动,只要消息事务成功,那么A操作⼀定成功,消息也⼀定发出来了,这时候B会收到消息去执⾏本地操作,如果本地操作失败,消息会重投,直到B操作成功,这样就变相地实现了A与B的分布式事务。原理如下:
虽然上⾯的⽅案能够完成A和B的操作,但是A和B并不是严格⼀致的,⽽是最终⼀致的,我们在这⾥牺牲了⼀致性,换来了性能的⼤幅度提升。当然,这种玩法也是有风险的,如果B⼀直执⾏不成功,那么⼀致性会被破坏,具体要不要玩,还是得看业务能够承担多少风险。
5.3、TCC编程模式
所谓的TCC编程模式,也是两阶段提交的⼀个变种。TCC提供了⼀个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,如果更新订单失败,则进⼊Cancel阶段,会去恢复库存。总之,TCC就是通过代码⼈为实现了两阶段提交,不同的业务场景所写的代码都不⼀样,复杂度也不⼀样,因此,这种模式并不能很好地被复⽤。
6、总结
分布式事务,本质上是对多个数据库的事务进⾏统⼀控制,按照控制⼒度可以分为:不控制、部分控
制和完全控制。不控制就是不引⼊分布式事务,部分控制就是各种变种的两阶段提交,包括上⾯提到的消息事务+最终⼀致性、TCC模式,⽽完全控制就是完全实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数据⼀致性减弱了,完全控制则是牺牲了性能,保障了⼀致性,具体⽤哪种⽅式,最终还是取决于业务场景。作为技术⼈员,⼀定不能忘了技术是为业务服务的,不要为了技术⽽技术,针对不同业务进⾏技术选型也是⼀种很重要的能⼒
本⽂链接:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。