分布式事务

事务:

事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据库中,一个事务由一组SQL语句组成。事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

事务的四大特性:

1.原子性:事务中所有的操作是不可再分割的原子单位,事务中所有的操作要么全部执行成功,要么全部执行失败

2.一致性:事务执行后,数据库状态应该与其他业务规则保持一致,如转账业务中,无论事务执行成功与否,参与的两个账号余额之和是不应发生改变的

3.隔离性:隔离是指并发操作中,不同的事务应该隔离开来,事务之间不能存在干扰

4.持久性:一旦事务提交成功,事务中所有的数据操作都必须持久化到数据库中,即使提交事务后,数据库马上崩溃,重启之后也应该保证数据恢复;

什么是分布式事务:

一个业务需要同时操作多个数据库的情况下,而且保持ACID的特性,一般应用于微服务的多服务处理。 

分布式事务_第1张图片
如上图:

在订单服务中大概有这几个步骤:
1.支付服务,修改支付订单状态
2.订单服务,订单状态修改为已支付
3.库存服务,减掉库存
4.积分服务,为该用户送积分
以上四个步骤中,在分布式系统中,是一个整体,也是一个分布式事务,要么全部执行成功,要么就全部执行失败这就是分布式事务;

CAP定理:
分布式事务_第2张图片
思考问题:张三去美团下单,美团下单到派单,并且扣除优惠券100元,张三在美团上点了外卖,然后下订单,然后在通知外卖小哥接单。
分布式事务_第3张图片
1.体现C一致性:在整个分布式系统中,一致性体现这笔订单,必须通知到外卖小哥且必须扣除100元优惠卷
2.体现A可用性:在整个分布式系统中,可用性体现在张三下单的时候,如果订单服务或者卡卷服务宕机瘫痪了,这个时候也不能影响到张三下单(一般使用集群部署即可)
3.体现P分区容错性:在整个分布式系统中,分区容错是体现在张三下单的时候,突然订单服务和卡卷服务之间发生网络中断了,这个时候也不能影响到张三下单;

分布式事务_第4张图片
CAP解决方案:
在分布式系统中,出现网络故障P,整个系统的数据任然保持一致性C,满足三者的这种方案是做不到的,相对可以实现的方案业界常用的做法就是三选二;
分布式事务_第5张图片

1:CAP中的AP:保证高可用性,牺牲了一致性C,保证了高可用;
上面图片中,保证订单服务可以正常访问,保证卡券服务可以正常访问,是牺牲了数据的一致性,张三下单成功,但是不扣除100元优惠券。在这种情况下:张三下订单成功后再去查看100元,居然还存在。如何解决呢?一般做法是:当网络恢复正常的情况下,订单服务重试请求卡券服务,再扣除100元优惠券。使用消息队列来做。

2.CAP中的CP:最终一致性,牺牲了可用性,保证了数据一致性;
即为了保证数据的强一致性,当张三来下单的时候,提示: 系统维护中,等服务或网络恢复正常后,张三再来下单。

3.CAP中的CA:可以实现吗?当然是不可以的,因为网络故障是一定存在的,我们没有办法去控制网络,所以P是必须要容忍的

说明: 不要P分区容错性,即不允许网络出现故障,这是不可能实现的。所以在分布式系统中,是不存在CA的,即使单体系统也做不到CA,因为单体系统也会出现单点故障问题。你可能说我可以用集群,但是一旦做了集群就由网络问题。

什么是BASE理论:
分布式事务_第6张图片

1.基本可用:

假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
1.响应时间上的损失: 正常情况下的搜索引擎 0.5 秒即返回给用户结果,而  基本可用  的搜索引擎可以在 1 秒作用返回结果。

2.功能上的损失: 在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单,但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。

2.软状态:

1.相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种 “硬状态”。

2.软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。

3.最终一致性:

系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值。

Zookeeper的CAP原理:
分布式事务_第7张图片
首先ZK使用的是CP原理:即牺牲了可用性,保证了数据一致性

ZK的数据同步原理:如上图所示,client1注册给了server1,server1同步给了server2,server2广播同步给了各个follower,为了保证数据的一致性,只有整个过程都成功了,client1才会收到注册成功的通知;

当leader出现网络故障的情况下:
分布式事务_第8张图片
当leader重启或者网络故障的情况下,整个zk就会重新选举,在选举期间,client不能注册的,zk不可用,所以牺牲了可用性;

只有等整个系统成功选举之后,系统才恢复注册,故zk保证了数据的一致性,牺牲了可用性,CP有一个致命的缺点,就是一个大型的分布式系统中,网络是非常复杂的,leader也是非常容易出现网络故障的,所以非常容易引发雪崩现象,所以这就是很多大型互联网公司都不选择zk的原因;

Nacos的CAP原理:
分布式事务_第9张图片
Nacos的原理是AP:即保证了可用性,牺牲了一致性
数据同步原理:如client1注册给了server1,server1直接告诉client1注册成功,剩下的就是server1同步给server2,为了保证服务的可用性,他们都是异步同步的方式;

常见的分布式解决方案:
1.seata 阿里的分布式事务框架
2.消息队列(最终一致性)
3.saga
4.XA
5.TCC
他们都有一个共同点:都是两阶段2PC,两阶段是指完成整个分布式事务,划分为两个步骤去完成;

阶段一:

分布式事务_第10张图片
阶段一流程:

1. 询问 协调者向所有参与者发送事务请求,询问是否可执行事务操作,然后等待各个参与者的响应。
2. 执行 各个参与者接收到协调者事务请求后,执行事务操作(例如更新一个关系型数据库表中的记录),并将
UndoRedo 信息记录事务日志中。
3. 响应 如果参与者成功执行了事务并写入 UndoRedo 信息,则向协调者返回 YES 响应,否则返回 NO
响应。当然,参与者也可能宕机,从而不会返回响应。

阶段二:
提交操作:
分布式事务_第11张图片
提交流程:

1. commit 请求 协调者向所有参与者发送 Commit 请求。
2. 事务提交 参与者收到 Commit 请求后,执行事务提交,提交完成后释放事务执行期占用的所有资源。
3. 反馈结果 参与者执行事务提交后向协调者发送 Ack 响应。
4. 完成事务 接收到所有参与者的 Ack 响应后,完成事务提交

回滚操作:
如果某些参与者执行事务失败、宕机或与协调者之间的网络中断,那么协调者就无法
收到所有参与者的 YES 响应,或者某个参与者返回了 No 响应,此时,协调者就会进入回退流程,对事务进行回
退。
分布式事务_第12张图片
回滚流程:

1. rollback 请求 协调者向所有参与者发送 Rollback 请求。
2. 事务回滚 参与者收到 Rollback 后,使用 Prepare 阶段的 Undo 日志执行事务回滚,完成后释放事务执行
期占用的所有资源。
3. 反馈结果 参与者执行事务回滚后向协调者发送 Ack 响应。
4. 中断事务 接收到所有参与者的 Ack 响应后,完成事务中断。

2PC存在的问题:

1. 同步阻塞 参与者在等待协调者的指令时,其实是在等待其他参与者的响应,在此过程中,参与者是无法进行其他操作的,也就是阻塞了其运行。 倘若参与者与协调者之间网络异常导致参与者一直收不到协调者信
息,那么会导致参与者一直阻塞下去。
2. 单点 在 2PC 中,一切请求都来自协调者,所以协调者的地位是至关重要的,如果协调者宕机,那么就会
使参与者一直阻塞并一直占用事务资源。
如果协调者也是分布式,使用选主方式提供服务,那么在一个协调者挂掉后,可以选取另一个协调者继续后续的服
务,可以解决单点问题。但是,新协调者无法知道上一个事务的全部状态信息(例如已等待 Prepare 响应的时长
等),所以也无法顺利处理上一个事务。
3. 数据不一致 Commit 事务过程中 Commit 请求/Rollback 请求可能因为协调者宕机或协调者与参与者网
络问题丢失,那么就导致了部分参与者没有收到 Commit/Rollback 请求,而其他参与者则正常收到执行了
Commit/Rollback 操作,没有收到请求的参与者则继续阻塞。这时,参与者之间的数据就不再一致了。
当参与者执行 Commit/Rollback 后会向协调者发送 Ack,然而协调者不论是否收到所有的参与者的 Ack,该事务
也不会再有其他补救措施了,协调者能做的也就是等待超时后像事务发起者返回一个“我不确定该事务是否成
功”。
4. 环境可靠性依赖 协调者 Prepare 请求发出后,等待响应,然而如果有参与者宕机或与协调者之间的网络
中断,都会导致协调者无法收到所有参与者的响应,那么在 2PC 中,协调者会等待一定时间,然后超时后,
会触发事务中断,在这个过程中,协调者和所有其他参与者都是出于阻塞的。这种机制对网络问题常见的现
实环境来说太苛刻了

阿里的Seata框架 AT模式:
Seata的三大角色:

Seata 的架构中,一共有三个角色:
1.TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
2.TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
3.RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。

AT 模式是一种无侵入的分布式事务解决方案。
阿里seata框架,实现了该模式。在 AT 模式下,用户只需关注自己的“业务 SQL”,用户的 “业务 SQL” 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。

Seata的执行流程:
一阶段图:
分布式事务_第13张图片
一阶段流程:
在一阶段,Seata 会拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,
在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。

二阶段流程图:

分布式事务_第14张图片
二阶段提交流程:
二阶段如果是提交的话,因为“业务 SQL”在一阶段已经提交至数据库, 所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。

二阶段回滚流程图:
分布式事务_第15张图片
二阶段回滚流程:
二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据。回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。

重点:Seata的生命周期
分布式事务_第16张图片
在这里插入图片描述
global_table:保存全局事务信息
branch_table: 保存分支事务信息
lock_table: 保存锁信息
生命周期流程:
1.TM 请求 TC 开启一个全局事务。TC 会生成一个 XID 作为该全局事务的编号。XID,会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。当一进入事务方法中就会生成XID , global_table 就是存储的全局事务信息 ,
2.RM 请求 TC 将本地事务注册为全局事务的分支事务,通过全局事务的 XID 进行关联。当运行数据库操作方法,branch_table 存储事务参与者
3.TM 请求 TC 告诉 XID 对应的全局事务是进行提交还是回滚。
4.TC 驱动 RM 们将 XID 对应的自己的本地事务进行提交还是回滚。

流程:
1.订单接口执行下单和扣减库存操作;
分布式事务_第17张图片
2.seata数据库生成数据,其中Xid保证用来关联保证是一个全局事务
分布式事务_第18张图片
3.锁表信息,使得事务之间的相互隔离,防止出现脏读,幻读,不可重复读等一些情况的发生
分布式事务_第19张图片
4.undo_log表存信息:
分布式事务_第20张图片
解析日志信息:就可以看到before image和after image的数据了
分布式事务_第21张图片
执行到此后:相当于第一阶段已执行完成
分布式事务_第22张图片
解析到了我们的sql,将它存入before image 然后执行sql,然后再存入after image,此时生成了我们的undo_log日志

提交操作:
分布式事务_第23张图片
分布式事务操作成功,则TC通知RM异步删除undolog

回滚事务:
分布式事务_第24张图片

分布式事务操作失败,TM向TC发送回滚请求,RM 收到协调器TC发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚。

Seata的整体流程:
分布式事务_第25张图片
TCC模式:
分布式事务_第26张图片

你可能感兴趣的:(分布式,数据库,java)