分布式事务

一、分布式事务的定义

在谈到分布式事务之前,首先讲事务的定义。

本地事务:对一个数据库里,执行两个或者两个以上的操作的时候,要么全部失败,要么全部成功,也就是说它的数据要保持是一致的。事务的特征,是ACID(原子性、一致性、隔离性、持久性,主要讲的是针对单个数据库的操作。

分布式事物:在多个数据源的情况下,在任何时间,任何地点、任何方式访问的数据都是一致的。
举例,下订单时,订单库、商品库、支付库的数据要同步。

二、为什么要有分布事务,为什么数据会不一致?

因为业务场景的需要,数据、缓存、队列、模块存在不同的机器上或执行单元上。

举例,转帐,从建设银行转到工商银行,假设建设银行的系统的数据在a库当中,工商银行的系统的数据存在b库中,当发起一个转账操作时,要访问这两个数据库,如果不用分布式事物保障b库加钱和a库减钱是同个原子操作,假设转1亿元,减钱成功、加钱失败,结果会怎样?

举例,假设网上买商品,下订单时,减库存和支付不在同一个库中,如果这两个操作不是同个原子操作,减库成功,支付失败,那可能就让用户白得商品。下个几千笔,可能就会让卖家破产了。

三、分布式事务实现分类

1、刚性分布式事务

什么是刚性分布式事物?
任何时候数据都是一致的,数据是强一致性的,数据特征是CAP模型CP特性,用XA模型来保障实现。

为什么CAP模型的CP
从CAP模型(一致性、可用、分区容错)角度来看,只能同时保持两种特性,C是强一致性,P是这里就分布式网络,所以是满足CP特征的。

XA模型怎么能保障数据一性?

以组织大伙爬山为例,会有二个环节:

第一个,确认环节,首先组织者会发一封邮件给所有的人确认,后天我们8:00去爬山,如果同意的请回复1,不同意请回复2。如果大家回复1,就表示大家都同意了,如果有人回复2,那就活动取消。

第2个环节,执行爬山,组织者就会准备一些什么吃的喝的东西。以供大家补充体力,然后大家同时开始爬山。如果当中某一个人在爬山的过程当中,爬到半山腰脚扭了,怎么办?那就有由其他的人背着他走,反正死也要把这个山爬完。

XA是一种规范,由AP、RM、TM组成,AP可以简单的理解执行方(app应用)接口,类似每个爬山的人,RM资源方(数据库)接口,类似补充能源的食物,TM事务管理,负责事务的协调控制,类似上面的组织爬山的组织者。

首先TM会对AP做一个预提交的动作,当大家都回复准备好了之后,TM就会对资源做真实的提交,这就是二阶段提交(类似上面爬山二个环节),来保障大家的做法都是同步的。

缺点:就是TM会劫持数据库资源,对所有的数据库加锁,就像是上面爬山例子中,在第2阶段执行,如果有一个人没有来,那其他所有的人都要等着这个人来。白白浪费了大家的时间。所以在高并发的场景下,对性能有要求的,是不怎么合适的。

2、柔性分布式事务

2.1 什么是柔性分布式事务?
数据的一致性不是什么时候都一致,当处理完成之后,再保证一致,达到最终一致。

在cap模型中,数据一致性(c)弱一些,又是网络分区,ca是折中妥协,所以是AP特性。是一种base模型(基本可用、柔性状态、最终一致性)

本质思考,柔性事务是对XA模型的妥协,它通过降低强一致性要求,来提高系统的并发数。
就如上面的爬山例子当中,不需要大家一起爬,
只要最终大家都爬上山顶,就算达到目的了。
爬得快就可以晚点爬或早点爬,爬完做其它事。

2.2 怎么实现柔性分布事务?

2.2.1 用TCC模型实现

分成三步,try,confirm,cancel,资源锁的控制交由业务控制,全部由业务代码实现,无复制,所有建议不采纳此方式。

2.2.2 用saga模型实现

起源于1987年一位专家发表的一篇saga论文,
大致的思想是把分布式事务拆成一个个的本地事务,每个模块都有相应的执行操作和补偿机制(confirm、cancel),原来正向环节减5,后面的执行环节失败了,那就加5,做补尝

举例,以订单支付为例,假设分为下订单、减库存、支付等环节,每个环节是单独数据库,这三个要是一个原子操作,用柔性分布式事物来做的话,先把每个正向环节写一段逆向环节的逻辑与之对应(如正向是加5、逆向减5),然后把三个做成本地事务,假设支付环节遇到异常了,此环节就会调用本地事务回滚,此环节后面的环节,减库存和下订单,再来调用相对应的逆向逻辑。

大致的设计思路,用两张表,为主从表,主表记录分布事务id,时间、状态,从表记录分布事务id,本地事务id、本地事务正向方法、本地事务、顺序、本地状态。

当所有的事务都调用成功,更新为主表状态为成功,并把主从表里所有的记录删掉,当某环节执行异常时,根据此事务的id,找到表中之前的所有逆向(补偿)方法,按顺序执行这些方法。

2.2.3 用队列异步实现

还记XA模型吗?用队列来模拟二阶段提交,
利用有些队列的消息可以为半成功状态,来做二阶段提交的预提交,用队列的生产者和消费者把两段保持原子操作的逻辑联起来。

先逻辑A作为一个预提交,把此状态放到队列里存成半成功状态,当队列返回给ack,表示队列更新成功,当逻辑A提交真正成功时,再更新半成功状态为真正成功,然后逻辑B拿到队列的真正成功状态再去执行自己的逻辑。

你可能感兴趣的:(分布式事务)