学习分布式事务总结

1.什么是分布式事务

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

1.1 CAP 理论:

而对于分布式中的问题的解决方案,CAP原则出现,描述如下:

一致性(Consistency):
像A节点写入一条信息之后,同一时刻,在其他节点都可以读到这条信息

可用性(Availability):
多布一些节点A,B,C…,任何时刻,用户访问,都应该以可预期的结果返回,而不是浏览器报错,404,500,页面丢失…等用户体验不好的情况发生

分区容忍性(PartitionTolerance):
当各系统模块间通信出现问题时,设计一个策略,使系统仍可对外提供满足一致性或可用性

1.2 三种组合:

分布式系统中,为了提高强一致性,应该使用更少的节点,这样更容易同步消息,而为了提高可用性,不得不增加节点,保证高可用,矛盾,所以需要取舍:

CA:
保证可用性和一致性,放弃分区:除非不是分布式架构,或者应用在一个永不会通信故障的网络中(理想),只有个别场景符合,当前的互联网架构显然不符合使用
CP:
保证一致性和分区容忍性,放弃可用性:当节点间不可通信时,进行阻塞,直到通信恢复,期间无法再对外提供服务,用户体验不好,如A转账给B,只有A扣款成功并B收款成功,整个事务才算完成,显然耗费资源
AP:
保证可用性和分区容忍性,放弃强一致性(使用最终一致性):给出一个用户可以忍受的时间,时间内达成数据的最终一致性,比如跨行转账,并不是立刻到账,可能是明天,或者2小时内到账

2.分布式事务的应用场场景

2.1、支付

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

2.2、在线下单

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

3.解决方案

1 维护本地消息
2 使用rocketmq事务消息
3 两阶段提交协议(2PC)
4 TCC事务补偿机制

3.1 维护本地消息表

分布式事务就是跨多个系统的事务,可以拆分为多个子系统的本地事务;
分布式事务=A系统本地事务 + B系统本地事务 + 消息通知;
准备: A系统维护一张消息表log1,状态为未执行,B系统维护2张表,未完成表log2,已完成表log3,消息中间件用两个topic,topic1是A系统通知B要执行任务了,topic2是B系统通知A已经完成任务了,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYvD3V6c-1589900542287)(media/15898986340586/15898997437993.jpg)]
1.用户在A系统里领取优惠券,并往log1插入一条记录
2.由定时任务轮询log1,发消息给B系统
3.B系统收到消息后,先检查是否在log3中执行过这条消息,没有的话插入log2表,并进行发短信,发送成功后删除log2的记录,插入log3
4.B系统发消息给A系统
5.A系统根据id删除这个消息
学习分布式事务总结
我们假设网络中断:
1.在1处中断:此时我们插入优惠券和log1用的本地事务,即使发消息失败,有定时任务轮询,会再次发送
2.在2处中断:当B系统发短信后,通知A系统失败,因为A系统有定时任务轮询,会重复再发一次,所以B系统会先检查log3,如果已经执行过了,就不发短信了,再次给A系统发送执行完成的消息,

实现最终事务一致要求:
预留资源成功理论上要求正式执行成功,如果执行失败会进行重试,要求业务执行方法实现幂等,每次执行的结果不变;
**优点:**开发简单,mq性能较高
**缺点:**业务耦合,因为频繁轮询数据库,增大了数据库负载,此时数据库的性能瓶颈尤为明显,不适合大高并发场景,中等的规模还是可以满足的

3.2 使用rocketmq事务消息

3.3 基于消息中间件的两阶段提交

往往用在高并发场景下,将一个分布式事务拆成一个消息事务(A系统的本地操作+发消息)+B系统的本地操作,其中B系统的操作由消息驱动,只要消息事务成功,那么A操作一定成功,消息也一定发出来了,这时候B会收到消息去执行本地操作,如果本地操作失败,消息会重投,直到B操作成功,这样就变相地实现了A与B的分布式事务
学习分布式事务总结
虽然上面的方案能够完成A和B的操作,但是A和B并不是严格一致的,而是最终一致的,我们在这里牺牲了一致性,换来了性能的大幅度提升。当然,这种玩法也是有风险的,如果B一直执行不成功,那么一致性会被破坏。

3.4 TCC事务补偿机制

所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,如果更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是通过代码人为实现了两阶段提交,不同的业务场景所写的代码都不一样,复杂度也不一样,因此,这种模式并不能很好地被复用。
学习分布式事务总结
Try
下单业务由订单服务和库存服务协同完成,在try阶段订单服务和库存服务完成检查和预留资源。
订单服务检查当前是否满足提交订单的条件(比如:当前存在未完成订单的不允许提交新订单)。
库存服务检查当前是否有充足的库存,并锁定资源。
Confirm
订单服务和库存服务成功完成Try后开始正式执行资源操作。
订单服务向订单写一条订单信息。
库存服务减去库存。
Cancel
如果订单服务和库存服务有一方出现失败则全部取消操作。
订单服务需要删除新增的订单信息。
库存服务将减去的库存再还原。
优点:最终保证数据的一致性,在业务层实现事务控制,灵活性好。XA两阶段提交资源层面的,而TCC实际上把资源层面二阶段提交上提到了业务层面来实现。有效了的避免了XA两阶段提交占用资源锁时间过长导致的性能地下问题。
缺点:开发成本高,每个事务操作每个参与者都需要实现try/confirm/cancel三个接口。
注意:TCC的try/confirm/cancel接口都要实现幂等性,在为在try、confirm、cancel失败后要不断重试;它让多个系统保证了原子性操作,因此成本还是比较高的

4.总结

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