更多精彩内容请关注
微信公众号:LifeSmile个人网站:www.lifesmile.cn代码实战地址:https://github.com/shenhuan1006/spring-cloud-rocketmq-transaction
简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
CAP 原则又称 CAP 定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在 C 和 A 之间做出选择。
BASE 理论指的是基本可用 Basically Available,软状态 Soft State,最终一致性 Eventual Consistency,核心思想是即便无法做到强一致性,但应该采用适合的方式保证最终一致性。
BA:Basically Available 基本可用,分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。 S:Soft State 软状态,允许系统存在中间状态,而该中间状态不会影响系统整体可用性。 E:Consistency 最终一致性,系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。 BASE 理论本质上是对 CAP 理论的延伸,是对 CAP 中 AP 方案的一个补充。
现在有一个情况,当用户创建一个订单,库存已经扣减成功(锁成功),但是讲订单插入数据库时报错。这个时候扣减的库存应该回滚。
目前的实现方式是无法将扣减的库存回滚,所以引入分布式事务。
技术栈:SpringBoot+jta+atpmikos可以实现
这个举个例子,比如说咱们团建。
第一个阶段,李哥(事务管理器)下周六我们去烧烤,去吗?这个时候李哥开始等待每个人的回答,如果所有人都说ok,那么就可以决定去。如果这个阶段里,任何一个人回答说,我有事不去了,李哥(事务管理器)会取消这次活动。如果都同意就进行第二阶段
第二个阶段,那下周六大家就一起去烧烤了
所以这个就是所谓的XA事务,两阶段提交,有一个事务管理器的概念,负责协调多个数据库(事务管理器)的事务,事务管理器先问问各个数据库你准备好了吗?如果每个数据库都回复ok,那么就正式提交事务,在各个数据库上执行操作;如果任何一个数据库回答不ok,那么就回滚事务。
存在的问题
同步阻塞:当参与事务者存在占用公共资源的情况,其中一个占用了资源,其他事务参与者就只能阻塞等待资源释放,处于阻塞状态。单点故障:一旦事务管理器出现故障,整个系统不可用数据不一致:在阶段二,如果事务管理器只发送了部分 commit 消息,此时网络发生异常,那么只有部分参与者接收到 commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。不确定性:当协事务管理器发送 commit 之后,并且此时只有一个参与者收到了 commit,那么当该参与者与事务管理器同时宕机之后,重新选举的事务管理器无法确定该条消息是否提交成功。Try、Confirm、Cancel
TCC 对比 XA解决了其几个缺点
解决了协调者单点,由主业务方发起并完成这个业务活动。业务活动管理器也变成多点,引入集群。同步阻塞:引入超时,超时后进行补偿,并且不会锁定整个资源,将资源转换为业务逻辑形式,粒度变小。数据一致性,有了补偿机制之后,由业务活动管理器控制一致性三个阶段:
Try阶段:这个阶段说的是对各个服务的资源做检测以及对资源进行锁定或者预留
Confirm阶段:这个阶段说的是在各个服务中执行实际的操作
Cancel阶段:如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,就是执行已经执行成功的业务逻辑的回滚操作
这种方案使用少。因为这个事务回滚实际上是严重依赖于你自己写代码来回滚和补偿了,会造成补偿代码巨大。
比如说我们,一般来说跟钱相关的,跟钱打交道的,支付、交易相关的场景,我们会用TCC,严格严格保证分布式事务要么全部成功,要么全部自动回滚,严格保证资金的正确性,在资金上出现问题
国外的ebay搞出来的这么一套思想
这个大概意思是这样的
A系统在自己本地一个事务里操作同时,插入一条数据到消息表接着A系统将这个消息发送到MQ中去B系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息B系统执行成功之后,就会更新自己本地消息表的状态以及A系统消息表的状态如果B系统处理失败了,那么就不会更新消息表状态,那么此时A系统会定时扫描自己的消息表,如果有没处理的消息,会再次发送到MQ中去,让B再次处理这个方案保证了最终一致性,哪怕B事务失败了,但是A会不断重发消息,直到B那边成功为止这个方案说实话最大的问题就在于严重依赖于数据库的消息表来管理事务,这个会导致如果是高并发场景咋办呢?咋扩展呢?所以一般确实很少用
该方案与本地消息最大的不同是去掉了本地消息表,其次本地消息表依赖消息表重试写入 mq 这一步由本方案中的轮询 prepare 消息状态来重试或者回滚该消息替代。其实现条件与余容错方案基本一致。目前市面上实现该方案的只有阿里的 RocketMq。