分布式事务解决方案
2022-05-13 14:42:14 35 举报
AI智能生成
分布式事务解决方案是一种处理跨多个数据库或服务器的事务的技术。它确保了在分布式环境中,所有的操作要么全部成功,要么全部失败,从而保证了数据的一致性和完整性。这种解决方案通常包括两阶段提交协议(2PC)、三阶段提交协议(3PC)和补偿事务等技术。其中,2PC通过协调者和参与者之间的交互来保证事务的原子性,但可能会导致阻塞问题;3PC则通过引入超时机制来解决2PC的阻塞问题,但实现更复杂;补偿事务则是通过在事务失败后进行反向操作来恢复数据一致性,但可能会增加系统的复杂性和延迟。
作者其他创作
大纲/内容
跨库事务
分库分表
微服务化
出现的场景?
分区容错性(Partition tolerance):分布式系统在遇到任何网络分区故障时,仍然需要能够保证对外提供满足一致性和可用性的服务
有限时间内
返回正常结果
可用性(Availability):系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果
强一致性
弱一致性
最终一致性
一致性(Consistency):数据更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致,不能存在中间状态
名词解释
如果保证了一致性(C):对于节点N1和N2,当往N1里写数据时,N2上的操作必须被暂停,只有当N1同步数据到N2时才能对N2进行读写请求,在N2被暂停操作期间客户端提交的请求会收到失败或超时。显然,这与可用性是相悖的
如果保证了可用性(A):那就不能暂停N2的读写操作,但同时N1在写数据的话,这就违背了一致性的要求。
为什么一致性(C)和可用性(A)之间进行取舍?
CAP定理:分布式系统设计理论
响应时间上的损失
功能上的损失(服务降级)
Basically Available(基本可用):分布式系统在出现不可预知的故障的时候,允许损失部分可用性,但不等于系统不可用
Soft state(软状态):指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性
Eventually consistent(最终一致性):强调系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态
ACID 是传统数据库常用的设计理念,追求强一致性模型
BASE 支持的是大型分布式系统,提出通过牺牲强一致性获得高可用性
一致性
ACID 和 BASE 代表了两种截然相反的设计哲学,在分布式系统设计的场景中,系统组件对一致性要求是不同的,因此 ACID 和 BASE 又会结合使用
ACID 和 BASE 的区别与联系
BASE定理:CAP理论中AP方案的延伸,对于C我们采用的方式和策略就是保证最终一致性
ACID实现
本地事务
不要求强一致性,而是要求最终一致性,允许有中间状态,也就是Base理论,换句话说,就是AP状态
应用场景
概念:补偿模式使用一个额外的协调服务来协调各个需要保证一致性的业务服务,协调服务按顺序调用各个业务微服务,如果某个业务服务调用异常(包括业务异常和技术异常)就取消之前所有已经调用成功的业务服务
主业务服务:主业务服务为整个业务活动的发起方,服务的编排者,负责发起并完成整个业务活动
从业务服务:从业务服务是整个业务活动的参与方,负责提供 TCC 业务操作,实现初步操作(Try)、确认操作(Confirm)、取消操作(Cancel)三个接口,供主业务服务调用
业务活动管理器:业务活动管理器管理控制整个业务活动,包括记录维护 TCC 全局事务的事务状态和每个从业务服务的子事务状态,并在业务活动提交时调用所有从业务服务的 Confirm 操作,在业务活动取消时调用所有从业务服务的 Cancel 操作
核心组成部分
Try 阶段: 调用 Try 接口,尝试执行业务,完成所有业务检查,预留业务资源。Confirm 或 Cancel 阶段: 两者是互斥的,只能进入其中一个,并且都满足幂等性,允许失败重试。Confirm 操作: 对业务系统做确认提交,确认执行业务操作,不做其他业务检查,只使用 Try 阶段预留的业务资源。Cancel 操作: 在业务执行错误,需要回滚的状态下执行业务取消,释放预留资源
流程
TCC 中会添加事务日志,如果 Confirm 或者 Cancel 阶段出错,则会进行重试,所以这两个阶段需要支持幂等;如果重试失败,则需要人工介入进行恢复和处理等
Try 阶段失败可以 Cancel,如果 Confirm 和 Cancel 阶段失败了怎么办?
阶段1:1、在XA中,各个RM准备提交各自的事务分支,事实上就是准备提交资源的更新操作(insert、delete、update等);2、在TCC中,是主业务活动请求(try)各个从业务服务预留资源。在阶段2:1、XA根据第一阶段每个RM是否都prepare成功,判断是要提交还是回滚。如果都prepare成功,那么就commit每个事务分支,反之则rollback每个事务分支。2、TCC中,如果在第一阶段所有业务资源都预留成功,那么confirm各个从业务服务,否则取消(cancel)所有从业务服务的资源预留请求。
相似之处
1、XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。基于数据库锁实现,需要数据库支持XA协议,由于在执行事务的全程都需要对相关数据加锁,一般高并发性能会比较差
2、TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁,性能较好。但是对微服务的侵入性强,微服务的每个事务都必须实现try、confirm、cancel等3个方法,开发成本高,今后维护改造的成本也高为了达到事务的一致性要求,try、confirm、cancel接口必须实现幂等性操作由于事务管理器要记录事务日志,必定会损耗一定的性能,并使得整个TCC事务时间拉长
不同之处
TCC与2PC对比
概念:TCC(Try-Confirm-Cancel)分布式事务模型相对于 XA 等传统模型,其特征在于它不依赖资源管理器(RM)对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务
TCC
概念:Saga模型是把一个分布式事务拆分为多个本地事务,每个本地事务都有相应的执行模块和补偿模块(对应TCC中的Confirm和Cancel),当Saga事务中任意一个本地事务出错时,可以通过调用相关的补偿方法恢复之前的事务,达到事务最终一致性。SAGA可以看做一个异步的、利用队列实现的补偿事务
LLT(Long Live Transaction):由一个个本地事务组成的事务链
本地事务:事务链由一个个子事务(本地事务)组成,LLT = T1+T2+T3+...+Ti
补偿:每个本地事务 Ti 有对应的补偿 Ci
向后恢复(Backward Recovery):撤销掉之前所有成功子事务。如果任意本地子事务失败,则补偿已完成的事务
向前恢复(Forward Recovery):即重试失败的事务,适用于必须要成功的场景,该情况下不需要Ci
Saga 两种恢复策略
Saga
实现
补偿型(同步)
依靠MQ的半消息机制来实现投递消息和参与者自身本地事务的一致性保障
原理
1.producer(本例中指A系统)发送半消息到broker,这个半消息不是说消息内容不完整, 它包含完整的消息内容, 在producer端和普通消息的发送逻辑一致2.broker存储半消息,半消息存储逻辑与普通消息一致,只是属性有所不同,topic是固定的RMQ_SYS_TRANS_HALF_TOPIC,queueId也是固定为0,这个tiopic中的消息对消费者是不可见的,所以里面的消息永远不会被消费。这就保证了在半消息提交成功之前,消费者是消费不到这个半消息的3.broker端半消息存储成功并返回后,A系统执行本地事务,并根据本地事务的执行结果来决定半消息的提交状态为提交或者回滚4.A系统发送结束半消息的请求,并带上提交状态(提交 or 回滚)5.broker端收到请求后,首先从RMQ_SYS_TRANS_HALF_TOPIC的queue中查出该消息,设置为完成状态。如果消息状态为提交,则把半消息从RMQ_SYS_TRANS_HALF_TOPIC队列中复制到这个消息原始topic的queue中去(之后这条消息就能被正常消费了);如果消息状态为回滚,则什么也不做。6.producer发送的半消息结束请求是 oneway 的,也就是发送后就不管了,只靠这个是无法保证半消息一定被提交的,rocketMq提供了一个兜底方案,这个方案叫消息反查机制,Broker启动时,会启动一个TransactionalMessageCheckService 任务,该任务会定时从半消息队列中读出所有超时未完成的半消息,针对每条未完成的消息,Broker会给对应的Producer发送一个消息反查请求,根据反查结果来决定这个半消息是需要提交还是回滚,或者后面继续来反查7.consumer(本例中指B系统)消费消息,执行本地数据变更(至于B是否能消费成功,消费失败是否重试,这属于正常消息消费需要考虑的问题)注意:在rocketMq中,不论是producer收到broker存储半消息成功返回后执行本地事务,还是broker向producer反查消息状态,都是通过回调机制完成
设计思想
MQ事务消息方案(RocketMQ,ActiveMQ支持半消息)
将分布式事务拆分成本地事务进行处理
发送消息方:1、需要有一个消息表,记录着消息状态相关信息。2、业务数据和消息表在同一个数据库,要保证它俩在同一个本地事务。直接利用本地事务,将业务数据和事务消息直接写入数据库。3、在本地事务中处理完业务数据和写消息表操作后,通过写消息到 MQ 消息队列。使用专门的投递工作线程进行事务消息投递到MQ,根据投递ACK去删除事务消息表记录4、消息会发到消息消费方,如果发送失败,即进行重试。消息消费方:1、处理消息队列中的消息,完成自己的业务逻辑。2、如果本地事务处理成功,则表明已经处理成功了。3、如果本地事务处理失败,那么就会重试执行。4、如果是业务层面的失败,给消息生产方发送一个业务补偿消息,通知进行回滚等操作。注意:生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。如果有靠谱的自动对账补账逻辑,这种方案还是非常实用的
本地消息表方案
异步确保型
要实现最大努力通知,可以采用 MQ 的 ACK 机制
1、业务活动的主动方,在完成业务处理之后,向业务活动的被动方发送消息,允许消息丢失。2、主动方可以设置时间阶梯型通知规则,在通知失败后按规则重复通知,直到通知N次后不再通知。3、主动方提供校对查询接口给被动方按需校对查询,用于恢复丢失的业务消息。4、业务活动的被动方如果正常接收了数据,就正常返回响应,并结束事务。5、如果被动方没有正常接收,根据定时策略,向业务活动主动方查询,恢复丢失的业务消息
基于MQ自身的事务消息方案
要实现最大努力通知,可以采用 定期检查本地消息表的机制
发送消息方:1、需要有一个消息表,记录着消息状态相关信息。2、业务数据和消息表在同一个数据库,要保证它俩在同一个本地事务。直接利用本地事务,将业务数据和事务消息直接写入数据库。3、在本地事务中处理完业务数据和写消息表操作后,通过写消息到 MQ 消息队列。使用专门的投递工作线程进行事务消息投递到MQ,根据投递ACK去删除事务消息表记录4、消息会发到消息消费方,如果发送失败,即进行重试。5、生产方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。如果有靠谱的自动对账补账逻辑,这种方案还是非常实用的。最大努力通知事务在于第三方系统的对接,所以最大努力通知事务有几个特性:1、业务主动方在完成业务处理后,向业务被动方(第三方系统)发送通知消息,允许存在消息丢失。2、业务主动方提供递增多挡位时间间隔(5min、10min、30min、1h、24h),用于失败重试调用业务被动方的接口;在通知N次之后就不再通知,报警+记日志+人工介入。3、业务被动方提供幂等的服务接口,防止通知重复消费。4、业务主动方需要有定期校验机制,对业务数据进行兜底;防止业务被动方无法履行责任时进行业务回滚,确保数据最终一致性。
基于DB的本地事务消息表方案
最大努力通知型
解决方案
整体解决方案对比
柔性事务:满足BASE理论
AP架构
无业务改造,强一致性,原生支持回滚/隔离性,低并发,适合短事务
参与者角色(资源管理器Participant):接收协调者的指令执行事务操作,向协调者反馈操作结果,并继续执行协调者发送的最终指令
没有一直锁表
优点
一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源
二阶段:提交异步化,非常快速地完成。或回滚通过一阶段的回滚日志进行反向补偿
执行步骤
1、TM 请求 TC,开始一个新的全局事务,TC 会为这个全局事务生成一个 XID
2、XID 通过微服务的调用链传递到其他微服务
3、RM 把本地事务作为这个XID的分支事务注册到TC
4、TM 请求 TC 对这个 XID 进行提交或回滚
5、TC 指挥这个 XID 下面的所有分支事务进行提交、回滚
springboot集成:https://cloud.tencent.com/developer/article/1923686
踩坑解决:https://blog.csdn.net/RookiexiaoMu_a/article/details/119426595
不生效排查?https://blog.csdn.net/godkzz/article/details/122398887
springboot整合参考资料
Seata AT 模式(增强型2pc模式)
集成springboot:https://dandelioncloud.cn/article/details/1469353539419086849/
TC(Tx-Client):由业务系统集成,事务发起方、参与方都由TxClient端来控制
TM (Tx-Manager):是独立的服务,是分布式事务的控制方,协调分布式事务的提交,回滚
主要组成
1、事务发起方也是一个事务模块,它去调用TM创建一个事务组,这个事务组的数据就会在TM下存储(目前TM数据是存在Redis下),目前框架中TM数据是存在Redis下。2、为了简化流程,参与方A是先执行业务再加入事务组,这样当参与方A在执行业务过程中出现异常就没有必要再加入事务组了,此时事务发起方会捕获该异常然后直接通知事务回滚。如果参与方A先加入事务组再执行业务,则A出现异常时再通过事务组去通知它,会多一个来回。执行完“加入事务组”之后,TM就把参与方A的状态记录下来。参与方A会给事务发起方返回数据(response)3、参与方B与参与方A类似,也是由事务发起方调用,执行完业务再加入事务组,最后给事务发起方返回数据。4、只要没有抛异常,事务发起方就视为要提交本次事务,此时通知事务管理器,让其知道是要提交还是回滚。TM会遍历这个事务组下关联的事务参与方信息,去通知各参与方要执行的状态(提交还是回滚)。5、当TM拿到各参与方返回的信息时,才会响应给事务发起方,告知事务已处理完毕。事务发起方拿到TM的这个响应之后,就可以响应给调用者了。
LCN(采用2PC)
协调者角色(事务管理器Coordinator):负责向参与者发送指令,收集参与者反馈,做出提交或者回滚决策
组成成员
单点故障导致高可用(HA)问题
同步阻塞导致性能问题
丢失消息导致的数据不一致问题
2PC带来的问题
相对于2PC,3PC主要解决的单点故障问题,并减少阻塞(引入 超时机制)
3PC作为2PC的改进版,3PC将原有的两阶段过程,重新划分为CanCommit、PreCommit和do Commit三个阶段
2PC/3PC
原理:JTA是基于XA架构上建模的,在JTA 中,事务管理器抽象为javax.transaction.TransactionManager接口,并通过底层事务服务(即JTS)实现,JTA更多的是从框架的角度来约定程序角色的接口,而JTS则是从具体实现的角度来约定程序角色之间的接口
J2EE容器所提供的JTA实现(JBoss)
DataSourceTransactionManager:用于实现本地事务
学习地址:https://github.com/cicadasmile/middle-ware-parent
源码地址:https://gitee.com/cicadasmile/middle-ware-parent
JTATransactionManager:用于实现分布式事务
spring事务整合
独立的JTA(Java-Transaction-API)实现:如JOTM,Atomikos
实现方式
JTA/JTS规范
数据锁定:数据在事务未结束前,为了保障一致性,根据数据隔离级别进行锁定
协议阻塞:本地事务在全局事务 没 commit 或 callback前都是阻塞等待的
性能损耗高:主要体现在事务协调增加的RT成本,并发事务数据使用锁进行竞争阻塞
XA缺点
解决方案(XA 协议:XA协议是数据库层面的一套分布式事务管理的规范)
刚性事务:满足CAP的CP理论
CP架构
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案
Seata 是什么?
分布式事务(CAP)
分布式事务分类?
分布式事务学习图
0 条评论
回复 删除
下一页