20230324整理

1.本地事务 ACID

在这里插入图片描述
事务的原子性是通过undo log来实现的。
事务的持久性是通过redo log来实现的。
事务的隔离性是通过 (读写锁 + MVCC)来实现的。
事务的一致性是通过原子性,持久性,隔离性来实现的!!!

2.redo日志(保证持久性)

Redo log的主要作用是用于数据库的崩溃恢复,用来保证事务的一致性。可以简单分为两部分,一是内存中重做日志换成(redo log buffer),是易失的,在内存中。二是重做日志文件,是持久的,保存在磁盘中。

在这里插入图片描述

第一步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
第二步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
第三步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,
对 redo log file采用追加写的方式.
第四步:定期将内存中修改的数据刷新到磁盘中

补充:整个过程是先记日志到内存,再定期同步刷新数据到磁盘。如果数据还没
刷新到磁盘就断电或者宕机,那么系统重启之后在读取redo log 恢复最新数据。
在这里插入图片描述

3.undo日志(保证原子性)

undo log主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。undo是一种逻辑日志,用于事务的回滚和MVCC。

undo日志,只将数据库逻辑地恢复到原来的样子,在回滚的时候,它实际上是做的相反的工作,比如一条INSERT ,对应一条 DELETE,对于每个UPDATE,对应一条相反的 UPDATE,将修改前的行放回去。undo日志用于事务的回滚操作进而保障了事务的原子性

在这里插入图片描述
在这里插入图片描述
从上图可以了解到数据的变更都伴随着回滚日志的产生:
(1) 产生了被修改前数据(zhangsan,1000) 的回滚日志
(2) 产生了被修改前数据(zhangsan,0) 的回滚日志

根据上面流程可以得出如下结论:
1、每条数据变更(insert/update/delete)操作都伴随一条undo log的生成,并且回滚日志必须先于数据持久化到磁盘上。
2、所谓的回滚就是根据回滚日志做逆向操作,比如delete的逆向操作为insert,insert的逆向操作为delete,update的逆向为update等

根据undo log 进行回滚
为了做到同时成功或者失败,当系统发生错误或者执行rollback操作时需要根据undo log 进行回滚
在这里插入图片描述
回滚操作就是要还原到原来的状态,undo log记录了数据被修改前的信息以及新增和被删除的数据信息,根据undo log生成回滚语句,比如:
(1) 如果在回滚日志里有新增数据记录,则生成删除该条的语句
(2) 如果在回滚日志里有删除数据记录,则生成生成该条的语句
(3) 如果在回滚日志里有修改数据记录,则生成修改到原先数据的语句

4.MVCC机制(保证隔离性)

MVCC (MultiVersion Concurrency Control) 叫做多版本并发控制机制。(它的主要实现思想是通过数据多版本来做到读写分离。从而实现不加锁读进而做到读写并行。
undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个隐藏字段trx_id和roll_pointer把这些undo日志串联起来形成一个历史记录版本链。MVCC机制的实现就是通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取同一条数据在版本链上的不同版本数据。

MVCC在mysql中的实现依赖的是undo log与read view
undo log:undo log 中记录某行数据的多个版本的数据。
read view:用来判断当前版本数据的可见性。

在这里插入图片描述

5.分布式事务

在这里插入图片描述
CAP的组合方式
1.AP
放弃一致性,追求分区容忍性和可用性。这是很多分布式系统设计时的选择。
通常实现 AP 都会保证最终一致性, BASE 理论就是根据 AP 来扩展的,一些业务场景比如:订单退款,今日退款成功,明日账户到账,只要用户可以接受在一定的时间内到账即可。
2.CP
放弃可用性,追求一致性和分区容错性,zookeeper 其实就是追求的强一致,又比如跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。
3.CA
放弃分区容忍性,即不进行分区,不考虑由于网络不通或结点挂掉的问题,则可以实现一致性和可用性。那么系统将不是一个标准的分布式系统,最常用的关系型数据就满足了 CA。

6.两阶段提交(2pc)

两阶段提交又称2PC(two-phase commit protocol),2pc是一个非常经典的强一致、中心化的原子提交协议。这里所说的中心化是指协议中有两类节点:一个是中心化协调者节点(coordinator)和N个参与者节点(partcipant)
在这里插入图片描述

第一阶段如上图所示,这个阶段被称为请求/表决阶段,就是在分布式事务的发起方在向分布式事务协调者(Coordinator)发送请求时,Coordinator首先会分别向参与者(Partcipant)节点A、参与者(Partcipant)节点B分别发送事务预处理请求,称之为Prepare,有些资料也叫"Vote Request"。说的直白点就是问一下这些参与节点"这件事你们能不能处理成功了",此时这些参与者节点一般来说就会打开本地数据库事务,然后开始执行数据库本地事务,但在执行完成后并不会立马提交数据库本地事务,而是先向Coordinator报告说:“我这边可以处理了/我这边不能处理”。
如果所有的参与这节点都向协调者作了“Vote Commit”的反馈的话,那么此时流程就会进入第二个阶段了

在这里插入图片描述
如果所有参与者节点都向协调者报告说“我这边可以处理”,那么此时协调者就会向所有参与者节点发送“全局提交确认通知(global_commit)”,即你们都可以进行本地事务提交了,此时参与者节点就会完成自身本地数据库事务的提交,并最终将提交结果回复“ack”消息给Coordinator,然后Coordinator就会向调用方返回分布式事务处理完成的结果。
在这里插入图片描述
相反,在第二阶段除了所有的参与者节点都反馈“我这边可以处理了”的情况外,也会有节点反馈说“我这边不能处理”的情况发生,此时参与者节点就会向协调者节点反馈“Vote_Abort”的消息。此时分布式事务协调者节点就会向所有的参与者节点发起事务回滚的消息(“global_rollback”),此时各个参与者节点就会回滚本地事务,释放资源,并且向协调者节点发送“ack”确认消息,协调者节点就会向调用方返回分布式事务处理失败的结果。

2pc总结:
1.性能问题。从流程上我们可以看得出,其最大缺点就在于它的执行过程中间,节点都处于阻塞状态。各个操作数据库的节点此时都占用着数据库资源,只有当所有节点准备完毕,事务协调者才会通知进行全局提交,参与者进行本地事务提交后才会释放资源。这样的过程会比较漫长,对性能影响比较大。

2.协调者单点故障问题。事务协调者是整个XA模型的核心,一旦事务协调者节点挂掉,会导致参与者收不到提交或回滚的通知,从而导致参与者节点始终处于事务无法完成的中间状态。

3.丢失消息导致的数据不一致问题。在第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就会导致节点间数据的不一致问题。

7.三阶段提交(3pc)

三阶段提交又称3PC,其在两阶段提交的基础上增加了CanCommit阶段,并引入了超时机制。一旦事务参与者迟迟没有收到协调者的Commit请求,就会自动进行本地commit,这样相对有效地解决了协调者单点故障的问题。
在这里插入图片描述
这个阶段类似于2PC中的第二个阶段中的Ready阶段,是一种事务询问操作,事务的协调者向所有参与者询问“你们是否可以完成本次事务?”,如果参与者节点认为自身可以完成事务就返回“YES”,否则“NO”。而在实际的场景中参与者节点会对自身逻辑进行事务尝试,其实说白了就是检查下自身状态的健康性,看有没有能力进行事务操作

在这里插入图片描述
在阶段一中,如果所有的参与者都返回Yes的话,那么就会进入PreCommit阶段进行事务预提交。此时分布式事务协调者会向所有的参与者节点发送PreCommit请求,参与者收到后开始执行事务操作,并将Undo和Redo信息记录到事务日志中。参与者执行完事务操作后(此时属于未提交事务的状态),就会向协调者反馈“Ack”表示我已经准备好提交了,并等待协调者的下一步指令。

否则,如果阶段一中有任何一个参与者节点返回的结果是No响应,或者协调者在等待参与者节点反馈的过程中超时(2PC中只有协调者可以超时,参与者没有超时机制)。整个分布式事务就会中断,协调者就会向所有的参与者发送“abort”请求。

在这里插入图片描述
在阶段二中如果所有的参与者节点都可以进行PreCommit提交,那么协调者就会从“预提交状态”-》“提交状态”。然后向所有的参与者节点发送"doCommit"请求,参与者节点在收到提交请求后就会各自执行事务提交操作,并向协调者节点反馈“Ack”消息,协调者收到所有参与者的Ack消息后完成事务。

相反,如果有一个参与者节点未完成PreCommit的反馈或者反馈超时,那么协调者都会向所有的参与者节点发送abort请求,从而中断事务。

总结:

相比较2PC而言,3PC对于协调者(Coordinator)和参与者(Partcipant)都设置了超时时间,而2PC只有协调者才拥有超时机制。这解决了一个什么问题呢?这个优化点,主要是避免了参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,无法释放资源的问题,因为参与者自身拥有超时机制会在超时后,自动进行本地commit从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围。

另外,通过CanCommit、PreCommit、DoCommit三个阶段的设计,相较于2PC而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的。

8.补偿事务(TCC)

TCC(Try-Confirm-Cancel)又称补偿事务。其核心思想是:“针对每个操作都要注册一个与其对应的确认和补偿(撤销操作)”。它分为三个操作:

Try阶段:主要做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作,它和后续的Confirm一起才能真正构成一个完整的业务逻辑。

Confirm阶段:做确认提交,Try阶段所有分支事务执行成功后开始执行Confirm。通常情况下,采用TCC则认为Confirm阶段是不会出错的。即 :只要Try成功,Confirm一定成功。若Confirm阶段真的出错了,需引入重试机制或人工处理。

Cancel阶段:在业务执行错误需要回滚的状态下执行分支事务的业务取消,预留资源释放。通常情况下,采用TCC则认为Cancel阶段也是一定成功的。若Cancel阶段真的出错了,需引入重试机制或人工处理。

TM事务管理器
TM事务管理器可以实现为独立的服务,也可以让全局事务发起方充当TM的角色,TM独立出来是为了成为公用组件,是为了考虑结构和软件复用。
TM在发起全局事务时生成全局事务记录,全局事务ID贯穿整个分布式事务调用链条,用来记录事务上下文,追踪和记录状态,由于Confirm和Cancel失败需进行重试,因此需要实现为幂等性是指同一个操作无论请求多少次,其结果都相同。

TCC事务的处理流程与2PC两阶段提交类似,不过2PC通常都是在跨库的DB层面,而TCC本质上就是一个应用层面的2PC,需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于,可以让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。

而不足之处则在于对应用的侵入性非常强,业务逻辑的每个分支都需要实现try、confirm、cancel三个操作。此外,其实现难度也比较大,需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。为了满足一致性的要求,confirm和cancel接口还必须实现幂等。

在这里插入图片描述
TCC需要注意三种异常处理分别是空回滚、幂等、悬挂 :
空回滚 :
在没有调用TCC资源Try方法的情况下,调用来二阶段的Cancel方法,Cancel方法需要识别出这是一个空回滚,然后直接返回成功。
出现原因是当一个分支事务所在服务宕机或网络异常,分支事务调用记录为失败,这个时候其实是没有执行Try阶段,当故障恢复后,分布式事务进行回滚则会调用二阶段的Cancel方法,从而形成空回滚。
解决思路是关键就是要识别出这个空回滚。思路很简单就是需要知道一阶段是否执行,如果执行来,那就是正常回滚;如果没执行,那就是空回滚。前面已经说过TM在发起全局事务时生成全局事务记录,全局事务ID贯穿整个分布式事务调用链条。再额外增加一张分支事务记录表,其中有全局事务ID和分支事务ID,第一阶段Try方法里会插入一条记录,表示一阶段执行来。Cancel接口里读取该记录,如果该记录存在,则正常回滚;如果该记录不存在,则是空回滚。
幂等 :
通过前面介绍已经了解到,为了保证TCC二阶段提交重试机制不会引发数据不一致,要求TCC的二阶段Try、Confirm和Cancel接口保证幂等,这样不会重复使用或者释放资源。如果幂等控制没有做好,很有可能导致数据不一致等严重问题。
解决思路在上述 “分支事务记录”中增加执行状态,每次执行前都查询该状态。
悬挂 :
悬挂就是对于一个分布式事务,其二阶段Cancel接口比Try接口先执行。
出现原因是在RPC调用分支事务try时,先注册分支事务,再执行RPC调用,如果此时RPC调用的网络发生拥堵,通常RPC调用是有超时时间的,RPC超时以后,TM就会通知RM回滚该分布式事务,可能回滚完成后,RPC请求才到达参与者真正执行,而一个Try方法预留的业务资源,只有该分布式事务才能使用,该分布式事务第一阶段预留的业务资源就再也没有人能够处理了,对于这种情况,我们就称为悬挂,即业务资源预留后无法继续处理。
解决思路是如果二阶段执行完成,那一阶段就不能再继续执行。在执行一阶段事务时判断在该全局事务下,“分支事务记录”表中是否已经有二阶段事务记录,如果有则不执行Try。

9.saga

Saga 和 TCC 一样,也是一种补偿事务,但是它没有 try 阶段,而是把分布式事务看作一组本地事务构成的事务链。

事务链中的每一个正向事务操作,都对应一个可逆的事务操作。Saga 事务协调器负责按照顺序执行事务链中的分支事务,分支事务执行完毕,即释放资源。如果某个分支事务失败了,则按照反方向执行事务补偿操作.
假如一个 Saga 的分布式事务链有 n 个分支事务构成,[T1,T2,…,Tn],那么该分布式事务的执行情况有三种:
(1) T1,T2,…,Tn:n 个事务全部执行成功了。
(2) T1,T2,…,Ti,Ci,…,C2,C1:执行到第 i (i<=n) 个事务的时候失败了,则按照 i->1 的顺序依次调用补偿操作。如果补偿失败了,就一直重试。补偿操作可以优化为并行执行。
(3) T1,T2,…,Ti (失败),Ti (重试),Ti (重试),…,Tn:适用于事务必须成功的场景,如果发生失败了就一直重试,不会执行补偿操作

在这里插入图片描述
Saga 事务是可以保障事务的三个特性:

原子性:Saga 协调器可以协调事务链中的本地事务要么全部提交,要么全部回滚。
一致性:Saga 事务可以实现最终一致性。
持久性:基于本地事务,所以这个特性可以很好实现。

但是 Saga 不保证事务隔离性的,本地事务提交后变更就对其他事务可见了。其他事务如果更改了已经提交成功的数据,可能会导致补偿操作失败。比如扣款失败,但是钱已经花掉了,业务设计上需要考虑这种场景并从业务设计上规避这种问题

Saga 事务和 TCC 事务一样,对业务实现要求高,要求业务设计实现上遵循三个策略:

允许空补偿:网络异常导致事务的参与方只收到了补偿操作指令,因为没有执行过正常操作,因此要进行空补偿。
保持幂等性:事务的正向操作和补偿操作都可能被重复触发,因此要保证操作的幂等性。
防止资源悬挂:网络异常导致事务的正向操作指令晚于补偿操作指令到达,则要丢弃本次正常操作,否则会出现资源悬挂问题。

Saga 模式非常适合于业务流程长的长事务的场景,实现上对业务侵入低,所以非常适合微服务架构的场景。同时 Saga 采用的是一阶段提交模式,不会对资源长时间加锁,不存在“木桶效应”,所以采用这种模式架构的系统性能高、吞吐高。

10.华为serviceComb

1.ServiceComb Pack架构如下图所示,主要包含两个组件,即Alpha和Omega,其中:

Alpha充当协调者的角色,主要负责对事务的事件进行持久化存储以及协调子事务的状态,使其最终得以与全局事务的状态保持一致,即保证事务中的子事务要么全执行,要么全不执行。

Omega是微服务中内嵌的一个agent,负责对监控本地事务执行情况并向Alpha上报事务执行事件,并在异常情况下根据alpha下发的指令执行相应的补偿或重试操作。
在这里插入图片描述
2.服务之间的消息传递以及关联性

服务调用过程中插入唯一的全局事务ID,并在后续的调用其它服务过程中传递这个全局事务ID。通过全局事务ID可以从汇总到Alpha事件中找到事件与之相关联的所有事件,通过对这些事件信息进行分析,我们可以完整地追踪到与分布式事务执行情况。
在这里插入图片描述

3.相关实现细节

Omega会以切面编程的方式向应用程序注入相关的处理模块,帮助我们构建分布式事务调用的上下文。

Omega会将本地事务执行的情况以事件的方式通知给Alpha。 由于单个Omega不可能知晓一个分布式事务下其他参与服务的执行情况, 这样就需要Alpha扮演一个十分重要的协调者的角色。Alpha将收集到的分布式事务事件信息整理汇总,通过分析这些事件之间的关系可以了解到分布式事务的执行情况, Alpha通过向Omega下发相关的执行指令由Omega执行相关提交或恢复操作,实现分布式事务的最终一致性。
在这里插入图片描述
4.华为serviceComb 实现saga
1.正常情况下的场景:

在分布式事务初始阶段由初始服务的Omega将SagaStarted事件到Alpha 进行分布式事务备案。当有新的服务参与到各个分布式事务中 参与服务的Omega会在本地事务执行前发 TxStarted到Alpha端  并在本地事务执行成功之后将TxEnded事件发 到Alpha。如果分布式事务正常结束 初始服务Omega会直接发 SagaEnded事件到Alpha结束整个分布式事务。
在这里插入图片描述
2.参与分布式事务的服务在执行本地事务出现异常

Transaction B执行出现 ,这 个时候参与服务B会向Alpha发 一个TxAborted的事件,Alpha收到这个事件后会将整Saga事务挂起,终止Saga事务的继续执行。如果这个时候 有其他的Omega向Alpha发 挂载在个Saga事务下的TxStarted事件的话,Alpha会直接发拒绝应答消息通知Omega 这个Saga事务已经出现异常,Omega收到应答之后会抛出异常拒绝执行新的本地事务。由于初始服务在调用参与服务B的程中,通过服务B的应答消息也知道了服务 用失败的消息,初始服务也会发生SagaAborted事件到Alpha来关闭整个Saga事件
在这里插入图片描述
Alpha可以通过查询TxEnded事件可以获取到需要进行补偿恢复的服务信息,Alpha会向相关的服务实例Omega发 TxCompensated事件,由Omega调用服务实例补偿方法进行相关的恢复操作。为了恢复本地事务执行上下文ServiceComb Pack会将TxStarted传递过来来的方法参数列表信息放入TxCompensated消息中传 给Omega,除此之外ServiceComb Pack 还会会将OmegaContext的全局事务ID和本地事务ID 置成本地事务执行时的状态。
在这里插入图片描述

3.超时问题

Alpha上的事件扫描器会定时查找Started事件在设定的超时时间内是否有对应的Aborted或 Ended事件 如果没有 Alpha事件扫描器则会生成对应的Aborted事件发相关的补偿操作。当整个saga事务执行超时时,Alpha事件扫描器会在后台数据库中添加SagaAborted事件终止整个Saga事务 并且调用Omega注册的恢复函数进行相关的恢复操作。
在这里插入图片描述
本地事务执行超时的情况下 Alpha事件扫描器会识别出Transaction B 执行超时 同时会发生TxAborted事件终止整个Saga 事务  用相关的恢复方法 行恢复。由于Alpha无法确 对应的本地事务的执行情况 Alpha会 用向Omega发 TxCompensated的方式强制恢复事务 即使此时参与的服务B的本地事务已经执行成功了 Alpha还是会调用参与
服务B的Omega来执行相关的恢复操作。
在这里插入图片描述

5.华为serviceComb Tcc实现

1.正常的Tcc调用流程:

初始服务在分布式事务开始时向Alpha协调器发 TccStarted事件,Alpha协调器在接收到TccStarted事件之后 会创建相关事务 追踪资源跟踪整个TCC事务整个生命周期。当在参与服务 用try方法前发 ParticipationStarted事件来声明与TCC相关本地事务。Alpha协调器会根据TCC事务当前的状态决定是否允许后续的参与服务参加到TCC事务中。 如果参与的TCC事务没有终止 Alpha协调器会回复确认消息,参与服务会继续执行相关的try方法调用,如果TCC事务已经出错终止了,Alpha协调器会回复终止消息,参与服务所在的Omega将抛出异常 直接终止try方法用。如果参与服务调用try方法成功 则会向Alpha发松ParticipationEnded事件。因为这个事件发送之后Omega端不需做任何操作,为了提高系统效率 Omega 用异步方式通知Alpha协调器。当初始服务执行完TCCStart所标注的方法之后  初始服务所在的Omega会向Alpha协调器发送TccEnded事件 Alpha协调器在接收到这个个事件之后会查询与本次TCC调用相关的ParticipationStarted事件,识别相关的参与服务实例,然后通过向这些服务实例所对应的Omega发 Coordinated事件,由Omega用相关的确认方法,完成本地事务提交工作。

在这里插入图片描述
2.参与分布式事务的服务在执行本地事务出现异常

当TCC调用执行过程中出现异常,初始服务所在的Omega会向Alpha协调器发 TccEnded事件来终止当前的TCC事务。Alpha协调器则会根据其记录的TCC分布式事务的参与情况,向相关服务的Omega发 Coordinated事件,由Omega 调用相关的取消方法
在这里插入图片描述
如果参与服务在执行try方法出错了,Alpha协调器会收到一条标注try方法执行状态的ParticipationEnded事件,Alpha协调器会给自己发送一个包含Aborted信息的TccEnded事件来关闭正在执行的TCC事务,同时触发Omega相关恢复操作的调用
在这里插入图片描述
3.超时问题

对于参与服务的try方法来说,Alpha协调器可以通过是否接收到ParticipationEnded事件判断参与服务try方法是否执行超时。 如果在超时时间内没有收到ParticipationEnded事件,Alpha事件扫描器会向数据库添加TccEnded信息 ,触发和之前一样的事务错误处理流程, 关闭分布式事务以及调用Omega进行相关恢复的操作。
在这里插入图片描述
当TCC分布式事务执行超时(Alpha在一定时 内没有收到TccEnded事件 ),  Alpha事件扫描器会发送TccEnded终止整个TCC事务,触发与上面相同的恢复操作。

在这里插入图片描述
6.相关注解实现细节
@SagaStart
在这里插入图片描述
在这里插入图片描述
@Compensiable
在这里插入图片描述
@TccStart
在这里插入图片描述
@Participate (try过程,Tcc默认try成功,confirm也会成功)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值