分布式事务

这篇博客详细探讨了分布式事务的ACID特性和BASE理论,并介绍了多种分布式事务处理方式,包括TCC、2PC、3PC、Seata等。文章强调了各种方法的优缺点,如TCC的业务耦合,2PC的阻塞问题,3PC的改进以及Seata的无侵入性和高性能特性。此外,还讨论了基于最大努力交付和消息最终一致性的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果只是有诚意就能搞定事情,那这个世界就没有遗憾了


数据库事务 一般指数据库执行过程中的逻辑单位

事务拥有以下四个特性,称为 ACID 特性
原子性(Atomicity)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)


BASE理论(基本可用:在故障出现时保证核心功能可用,软状态:允许中间状态出现,最终一致性:不要求分布式事务打成中时间点数据都是一致性的,但是保证达到某个时间点后,数据就处于了一致性了)的事务我们称为柔性事务


分布式事务常用的有下面几种方式
1、TCC
2、2PC
3、3PC
4、Seata
5、LCN
6、XA
7、基于最大努力交付 && 消息队列以及消息存储来解决最终一致性


TCC

TCC是一种比较成熟的分布式事务解决方案,可用于解决跨库操作的数据一致性问题,也可以用于非数据库的事务一致性情况

TCC是服务化的两阶段编程模型,其Try、Confirm、Cancel 3个方法均由业务编码实现;

try 数据就生效了,提交了事务

confirm 确定下数据,查询try的数据是否正确

cancle 回滚数据,把try的数据回滚掉

其中Try操作作为一阶段,负责资源的检查和预留,Confirm操作作为二阶段提交操作,Cancel是回滚

TCC实际上把数据库层的二阶段提交上提到了应用层来实现

TCC事务的缺点:
TCC的Try、Confirm和Cancel操作功能需业务提供,开发成本高,与业务有些耦合,对业务有侵入性

在这里插入图片描述
TCC与XA

TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。(第一阶段的事务就已经提交了,第二阶段执行确认操作或取消第一阶段的操作)

XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。基于数据库锁实现。

在这里插入图片描述


XA

主要限制

必须要拿到所有数据源,而且数据源还要支持XA协议。

性能比较差,要把所有涉及到的数据都要锁定,是强一致性的,会产生长事务。

使用范围(资源管理方面的控制)


2PC

二阶段提交,是指将事务提交分成两个部分:准备阶段和提交阶段。事务的发起者称之为协调者,事务的执行者称为参与者
阶段一:准备阶段

         由协调者发起并传递带有事务信息的请求给各个参与者,询问是否可以提交事务,并等待返回结果。

         参与者执行事务操作,将Undo和Redo放入事务日志中(但是不提交)

         如果参与者执行成功就返回YES(可以提交事务),失败NO(不能提交事务)

阶段二:提交阶段

          此阶段分两种情况:所有参与者均返回YES,有任何一个参与者返回NO

           所有参与者均反馈YES时,即提交事务。

           任何一个参与者反馈NO时,即中断事务。

3PC

2PC存在的问题
1.阻塞问题
二阶段提交的第一阶段中,协调者需要等待参与者的响应,如果没有接收到任意参与者的响应,这时进入等待状态,其他正常发送响应的参与者,进入阻塞状态,无法进行其他任何操作,只有等待超时中断事务,限制了系统的性能。
2.单点问题
协调者处于一个中心的位置,一旦出现问题,那么整个二阶段提交将无法运转,更为严重的是,如果协调者在阶段二中出现问题,其他参与者将会一直处于锁定事务资源的状态中,无法继续完成操作

以上提到的2个问题在3PC得到了解决
1.解决阻塞问题:将2PC中的第一阶段一分为二,提供了一个CanCommit阶段,此阶段并不锁定资源,这样可以降低阻塞概率
2.解决单点问题:在参与者这边也引入了超时机制

与两阶段提交不同,三阶段提交有两个改动点。

1、引入超时机制。同时在协调者和参与者中都引入超时机制。
2、在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

两者区别:三阶段提交较二阶段提交,各个处理者完成预提交后,无论能不能正常收到协调者的提交决定,都会在一定时间内完成提交。从而一定程度上缓解了单点问题,但也可能存在数据不一致


三者的联系 2PC/3PC由来:XA规范
2PC/3PC提交其实就是实现XA分布式事务的关键,而分布式事务从广义上来讲也是一致性的一种表现,所以2PC/3PC也可以叫一致性协议;其实在表示数据一致性的环境下,2PC/3PC代表的含义:要么所有备份数据同时更改某个值,要么都不更改,以此来达到数据的强一致性。在真实的应用中,尽管有系统使用2PC/3PC协议来作为数据一致性协议,但是比较少见,更多的是作为实现数据更新原子性手段出现。

为什么2PC/3PC没有被广泛用在保证数据的一致性上,主要原因应该还是它本身的缺陷,所有经常看到这句话:there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos. 意即世上只有一种一致性算法,那就是Paxos。

无论2PC或3PC,均无法彻底解决分布式一致性问题

2PC/3PC用来处理分布式事务: 能够很好的提供强一致性和强事务性,但相对来说延迟比较高,比较适合传统的单体应用,在同一个方法中存在跨库操作的情况,不适合高并发和高性能要求的场景。

2PC/3PC用来处理数据一致性:很少使用,更多的是Paxos或者基于Paxos的变体,如Zookeeper 的 zab


基于最大努力交付 & 消息最终一致性

最大努力交付,就是最大努力做,能不能成功,不做完全保证
会涉及到三个模块
上游应用,发消息到 MQ 队列。
下游应用(例如短信服务、邮件服务),接受请求,并返回通知结果。
最大努力通知服务,监听消息队列,将消息存储到数据库中,并按照通知规则调用下游应用的发送通知接口。
总结
最大努力通知服务表示在不影响主业务的情况下,尽可能地确保数据的一致性。它需要开发人员根据业务来指定通知规则,在满足通知规则的前提下,尽可能的确保数据的一致,以达到最大努力的目的

流程
1、上游应用发送 MQ 消息到 MQ 组件内,消息内包含通知规则和通知地址
2、最大努力通知服务监听到 MQ 内的消息,解析通知规则并放入延时队列等待触发通知
3、最大努力通知服务调用下游的通知地址,如果调用成功,则该消息标记为通知成功,如果失败则在满足通知规则(例如 5 分钟发一次,共发送 10 次)的情况下重新放入延时队列等待下次触发。

优点:实现简单
缺点:无补偿机制,不保证能够送达

可靠消息最终一致性方案
此方案涉及 3 个模块:
1、上游应用,执行业务并发送 MQ 消息。
2、可靠消息服务和 MQ 消息组件,协调上下游消息的传递,并确保上下游数据的一致性。
3、下游应用,监听 MQ 的消息并执行自身业务。

第一阶段:上游应用执行业务并发送 MQ 消息
第二阶段:下游应用监听 MQ 消息并执行业务
第三阶段:消息状态确认或消息重发(如果业务执行成功则更改消息状态为已发送,否则删除此消息确保数据一致)


Seata

Seata是个阿里分布式事务中间件
起初起名为 Fescar,后改名为 Seata

因为目前分布式事务解决的方案主要有对业务无入侵和有入侵的方案,无入侵方案主要有基于数据库 XA 协议的两段式提交(2PC)方案,一方面要求数据库对 XA 协议的支持,并且性能不好

解决分布式事务问题,有两个设计初衷

对业务无侵入:即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入
高性能:减少分布式事务解决方案所带来的性能消耗


seata中有两种分布式事务实现方案,AT及TCC

AT模式主要关注多 DB 访问的数据一致性,当然也包括多服务下的多 DB 数据访问一致性问题

TCC 模式主要关注业务拆分,在按照业务横向扩展资源时,解决微服务间调用的一致性问题

Seata 的设计思路是将一个分布式事务可以理解成一个全局事务,下面挂了若干个分支事务,而一个分支事务是一个满足 ACID 的本地事务,因此我们可以操作分布式事务像操作本地事务一样。


Seata 内部定义了 3个模块来处理全局事务和分支事务的关系和处理过程,这三个组件分别是:

Transaction Coordinator (TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。

Transaction Manager ™:控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。

Resource Manager (RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

简说全局事务的执行步骤
1.TM 向 TC 申请开启一个全局事务,TC 创建全局事务后返回全局唯一的 XID,XID 会在全局事务的上下文中传播;
2.RM 向 TC 注册分支事务,该分支事务归属于拥有相同 XID 的全局事务;
3.TM 向 TC 发起全局提交或回滚;
4.TC 调度 XID 下的分支事务完成提交或者回滚。

Seata 在数据源做了一层代理层,所以我们使用 Seata 时,我们使用的数据源实际上用的是 Seata 自带的数据源代理 DataSourceProxy,Seata 在这层代理中加入了很多逻辑,主要是解析 SQL,把业务数据在更新前后的数据镜像组织成回滚日志,并将 undo log 日志插入 undo_log 表中,保证每条更新数据的业务 sql 都有对应的回滚日志存在。

上面说的是 Seata 默认模式, AT 模式,它是类似于 XA 方案的两段式提交方案,并且是对业务无侵入,但是这种机制依然是需要依赖数据库本地事务的 ACID 特性,

必须是支持 ACID 特性的关系型数据库,那么问题就来了,非关系型或者不支持 ACID 的数据库就无法使用 Seata 了,不过,Seata 现阶段准备了另外一种模式,叫 MT 模式

它是一种对业务有入侵的方案,提交回滚等操作需要我们自行定义,业务逻辑需要被分解为 Prepare/Commit/Rollback 3 部分,形成一个 MT 分支,加入全局事务,它存在的意义是为 Seata 触达更多的场景。

基于这样的机制,分支的本地事务便可以在全局事务的第一阶段提交,并马上释放本地事务锁定的资源

这也是Seata和XA事务的不同之处,两阶段提交往往对资源的锁定需要持续到第二阶段实际的提交或者回滚操作,而有了回滚日志之后,可以在第一阶段释放对资源的锁定,降低了锁范围,提高效率,即使第二阶段发生异常需要回滚,只需找对undolog中对应数据并反解析成sql来达到回滚目的

同时Seata通过代理数据源将业务sql的执行解析成undolog来与业务数据的更新同时入库,达到了对业务无侵入的效果


亮点
相比与其它分布式事务框架,Seata架构的亮点主要有几个:

应用层基于SQL解析实现了自动补偿,从而最大程度的降低业务侵入性;
将分布式事务中TC(事务协调者)独立部署,负责事务的注册、回滚;
通过全局锁实现了写隔离与读隔离。


Seate 如何使用
1、Seata AT模式需要UNDO_LOG表
2、Seate 需要单独部署
3、分布式事务的接口加注解 @GlobalTransactional(timeoutMills = 300000, name = “spring-cloud-demo-tx”)

性能损耗:
一条Update的SQL,则需要全局事务xid获取(与TC通讯)、before image(解析SQL,查询一次数据库)、after image(查询一次数据库)、insert undo log(写一次数据库)、before commit(与TC通讯,判断锁冲突),这些操作都需要一次远程通讯RPC,而且是同步的。另外undo log写入时blob字段的插入性能也是不高的。每条写SQL都会增加这么多开销,粗略估计会增加5倍响应时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值