文章目录
前言
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案,他们每种事务模式的原理是什么,在实际使用中应该选择哪种事务模式。
一、事务模式 是什么?
事务模式(Transaction Mode)指的是处理分布式系统中的多个操作步骤时,如何确保这些操作的一致性和隔离性的方式。分布式系统中的事务模式可以分为以下几种:
-
ACID 事务模式:
- ACID 模式是传统的关系型数据库事务的标准模式。
- ACID 是指原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
- 在 ACID 模式下,事务要么被完整地执行,要么被完整地回滚,确保了数据的一致性和隔离性。
-
BASE 事务模式:
- BASE(Basically Available, Soft state, Eventually consistent)模式是一种放松 ACID 的事务模式,用于分布式系统中的大规模和高并发环境。
- BASE 强调可用性(Basically Available)和柔性状态(Soft state),而不是一致性。
- BASE 模式允许系统在一段时间内保持不一致状态,最终达到一致性。
-
分布式事务模式:
- 分布式事务模式用于解决分布式系统中的多个服务之间的事务一致性问题。
- 分布式事务模式通常涉及全局事务协调器、本地事务协调器、事务日志和补偿机制等组件。
- 常见的分布式事务模式包括两阶段提交(Two-Phase Commit,2PC)、TCC(Try-Confirm-Cancel)、SAGA(Saga)等。
不同的事务模式适用于不同的场景和需求。ACID 模式适合对数据一致性要求较高的传统关系型数据库,而 BASE 模式适合对数据一致性要求相对较低但要求高可用性的分布式系统。分布式事务模式则提供了一种解决分布式系统中事务一致性问题的方式。
在选择事务模式时,需要考虑系统的需求、性能要求、可扩展性以及数据一致性等因素。同时,每种事务模式都有其优缺点和适用场景,需要根据实际情况进行选择。
希望这个回答能够帮助您理解事务模式的概念。如果您有任何进一步的疑问,请随时提问。
二、Seata中的事务模式支持:
在应用中Seata整体事务逻辑基于两阶段提交的模型,核心概念包含三个角色:
- TC:事务协调者即独立运行的seata-server,用于接收事务注册,提交和回滚,运行在服务端。
- TM:事务发起者。用来告诉TC全局事务的开始,提交,回滚,运行在客户端。
- RM:事务资源,每一个RM都会作为一个分支事务注册在TC,运行在客户端。
2.1 AT 模式(自动补偿型事务):
最终一致性模型,Seata 默认使用的模式;2pc
2.1.1 AT 模型:
流程:
-
TM 向 TC 申请开启一个全局事务,全局事务创建并生成一个全局唯一的XID ;XID 在微服务调用链路的上下文中传播;
-
在第一个阶段,执行Rm 自己的本地事务,并记录undo_log日志,数据修改之前的状态及数据修改之后的状态;
-
- 假设运行:update product set name =‘GTS’ where name = ‘TXC’; // id=1
1).解析 SQL:得到 SQL的类型(UPDATE),表(product),条件(where name='TXC”)等相关的信息;
2).査询前镜像:根据解析得到的条件信息,生成査询语句,定位数据。selectfrom produc where name =‘TXC’;
3).执行业务 SQL:更新这条记录的 name 为’GTS’。
4).查询后镜像:根据前镜像的结果,通过 主键 定位数据。selectfrom produc where name=‘TXC’
5).插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到 undo_log表中。
6).提交前,RM 向 TC 注册分支:申请product表中,主键值等于1的记录的 全局锁。
7).本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
8).TM 向 TC 发起针对 XID 的全局提交或回滚决议。将本地事务提交的结果上报给 TC
- 假设运行:update product set name =‘GTS’ where name = ‘TXC’; // id=1
-
第二阶段:TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
-
- 提交:
1).收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
2).异步任务阶段的分支:提交请求,将异步和批量地删除相应 UNDO LOG 记录。
- 提交:
-
- 回滚:
1).收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
2). 通过 XID 和 Branch lD 查找到相应的 UNDO LOG 记录。
3).数据校验:拿 UNDOLOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改(出现脏写),转人工处理(Seata 因为无法感知这个脏写如何发生,此时只能打印日志和触发异常通知,告知用户需要人工介入)
4).人工没有脏写就简单了:根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
5).提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。
- 回滚:
2.1.2 AT 写隔离:
在分布式两个不同的事务对同一条数据修改:怎么进行写的相互隔离,以一个示例来说明:
两个全局事务 tx1 和 tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000。
- tx1 先获取本地改数据锁,执行更新操作,获取全局事务锁偶,本地事务提交,释放本地锁;
- tx2 获取该数据时先进行阻塞直到,tx1 释放了本地事务锁,此时 tx2 获取改数据本地事务锁,然后执行sql 修改, 然后等待获取全局事务锁后,提交tx2 的事务;
- tx1 确认事务提交成功,释放全局锁;
- tx2 获取到全局锁,确认本地事务成功,释放本地锁;
失败的情况:
- tx 1 执行事务的回滚操作操作时,需要获取本地事务锁,此时tx2 在阻塞到超时 时间之后,tx2 获取全局锁失败(回滚事务,数据回滚为900),然后释放到本地的数据锁;
- tx1 获取到该数据的本地锁,然后执行回滚操作,然后释放本地锁,数据回滚到1000;
2.1.3 AT 读隔离:
在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。
- tx1 事务获取本地数据锁,执行sql ,然后获取全局锁,并且提交本地事务,释放本地数据锁;
- tx2 阻塞式的获取到该条数据的本地锁;tx2 阻塞式的获去获取全局锁;
- tx1 事务此时确认事务(进行回滚或者提交),并且释放全局锁;
- tx2 获取到全局锁 然后释放本地数据锁,然后重新进行查询,查询完毕释放全局锁;
SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。
出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。
2.1.3 AT 优缺点:
优点:
- 简单易用:AT 模式对应用程序的侵入性较小,开发人员只需要按照 Seata 的要求编写本地事务即可,无需显式地编写补偿逻辑。
- 原子性保证:AT 模式通过在本地事务中插入逆向行为(Undo Log),保证了全局事务的原子性,即要么全部提交,要么全部回滚,从而确保了数据的一致性。
- 性能较高:AT 模式相较于其他事务模式,如 TCC 模式和 SAGA 模式,具有较低的事务处理开销和较高的性能表现。
缺点:
- 不支持柔性事务:AT 模式是一种强一致性的事务模式,不支持 BASE 模式的柔性事务,在面对高并发场景和复杂交互时可能会造成性能瓶颈。
- 潜在的性能开销:由于 AT 模式需要在本地事务中插入逆向行为,可能会导致事务处理逻辑复杂化,对性能有一定的影响。
- 依赖数据库的日志功能:AT 模式的实现依赖数据库的日志功能,需要数据库支持回滚操作和数据一致性的保证。
需要根据具体的业务需求来选择适合的事务模式。对于要求强一致和较高性能的场景,AT 模式是一个较好的选择。但对于需要柔性事务的场景,可能需要考虑其他的事务模式。
2.2 TCC 模式(补偿型两阶段提交):
2.2.1 TCC 模型:
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中:
- TCC(Try-Confirm-Cancel)模式允许应用程序通过明确的 Try-Confirm-Cancel 阶段来处理分布式事务。
- 在 TCC 模式中,业务应用程序需要实现两个阶段的逻辑:Try 阶段尝试占用资源,Confirm 阶段实际执行业务逻辑,Cancel 阶段撤销 Try 阶段的操作。
- 当全局事务提交时,Seata 会按照 Try 阶段、Confirm 阶段的顺序执行业务逻辑,如果有异常则执行 Cancel 阶段来进行回滚。
2.2.2 TCC 读写隔离:
因为TCC 中的 try ,confirm 和cancel 业务逻辑都是交由业务开发者自己实现,所有对于读写隔离依赖于 数据库的隔离级别; 数据库层面需要设置合适的隔离级别 (如 mysql innodb 设置级别为可重复读);然后在try 的业务实现中可以使用基于悲观锁的行级锁,或者基于乐观锁的版本号来进行数据更新,然后在confirm 和cancel 进行数据的最终提交或者回滚;
2.2.3 TCC 优缺点:
优点:
- 柔性事务支持:TCC 模式是一种柔性事务模式,适用于需要在不同服务之间执行复杂的交互逻辑的场景。它允许开发人员通过编写 Try、Confirm 和 Cancel 三个阶段的代码来实现事务的执行、确认和取消操作。
- 高并发性能:TCC 模式在执行事务时,通过预留资源、确认资源和释放资源等阶段来保证事务的一致性。这样可以减少锁的使用,提高并发性能。
- 精确的异常处理:TCC 模式允许开发人员在事务的不同阶段处理异常,并通过 Confirm 和 Cancel 阶段来恢复和补偿资源,实现精确的异常处理,保证事务的可靠性。
缺点:
- 适应性较差:TCC 模式相对于 AT 模式来说需要开发人员编写更多的代码,尤其是在 Confirm 和 Cancel 阶段的编码过程中,需要处理更多的业务逻辑。
- 实现复杂度高:TCC 模式的实现相对较为复杂,需要进行多个阶段的事务协调和补偿,开发和维护成本相对较高。
- 不支持强一致性:TCC 模式是一种柔性事务模式,对一致性的要求相对较低,无法保证强一致性。在异常复杂的场景下,可能需要开发人员手动处理事务致性。
2.3 SAGA 模式(无补偿型事务):
Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。
2.3.1 SAGA 模型:
- SAGA(Saga)模式通过一系列的局部事务和补偿操作来实现分布式事务的一致性。
- 在 SAGA 模式中,每一个局部事务都会有对应的补偿操作,用于撤销或修复操作。
- 当全局事务提交时,Seata 会根据事务的执行状态来确定下一步的操作,如果有异常则会执行相应的补偿操作来回滚或修复。
2.3.2 SAGA 读写隔离:
同TCC 模式一样,SAGA 的数据的提交和数据的回滚也是交由业务开发者自身进行实现,每个分支事务进行自身的提交,然后进入到下个分支事务,如果某个分支事务异常则需要通知之前的事务完成数据的补偿;
2.3.3 SAGA 优缺点:
优点:
- 异步执行:SAGA 模式通过将事务操作拆分为一系列的补偿操作,并使用消息来触发和协调这些操作,实现了异步执行。这有助于减少事务执行时间和提高性能。
- 柔性事务支持:SAGA 模式允许开发人员在分布式事务环境中执行具有补偿能力的事务。开发人员可以通过编写补偿操作来恢复事务的前一个状态,保证了事务的一致性。
- 分布式事务可控性:SAGA 模式使用了基于事件的机制来协调分布式事务,使得事务的执行过程更加可控。开发人员可以依靠消息和事件的传递来监控和恢复事务,增加了系统的可靠性和可维护性。
缺点:
- 实现复杂度高:SAGA 模式的实现相对复杂,需要进行事务的拆分和补偿操作的编写,以及事件的传递和监控等。这可能增加了开发和维护的工作量。
- 异步执行可能引发问题:由于 SAGA 模式的异步执行,存在一定的延迟和消息传递的不确定性。这可能导致在一些异常情况下,事务无法正确执行和补偿,从而影响事务的一致性。
- 不支持强一致性:SAGA 模式是一种柔性事务模式,对一致性的要求较低,无法保证强一致性。在一些对一致性要求非常高的业务场景中,可能需要其他更强一致性的事务模式。
对于需要在分布式环境下执行异步和具有补偿能力的业务操作的场景,SAGA 模式是一个比较好的选择。它允许开发人员根据具体的业务需求来实现补偿操作,通过消息的传递和事件的协调来实现分布式事务的可控性。但需要注意实现的复杂度和异步执行可能引发的问题。
2.4 XA 模式:
2.4.1 XA 模型:
在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。
-
注册全局事务id,xid
-
第一个rm 使用xid,绑定本地TM
-
执行业务sql,并不提交;
-
执行完毕返给TC 准备完成的状态(回滚/提交),数据的课件状态取决于当前的事务隔离级别;
-
TC 收集当前xid 准备完成的状态;
-
收集完毕,所有的都成功,则给到每个RM 提交指令,否则给与回滚指令;
-
每个RM 通信XA 协议提交/回滚事务;
2.4.2 XA 模式读写隔离:
在Seata XA模式下,读写隔离是通过数据库本身的事务隔离级别来实现的。Seata框架并不直接控制事务的隔离级别,而是借助数据库的事务隔离级别来保证读写的隔离性。开发人员在使用Seata XA模式时,需要依赖底层数据库支持的事务隔离级别来确保读写的隔离性。
2.4.3 XA 模式优缺点:
优点:
-
强一致性:Seata XA模式使用XA协议来保证分布式事务的强一致性,所有分支事务要么全部提交成功,要么全部回滚,确保了数据的一致性。
-
分布式事务管理:Seata提供了TC(Transaction Coordinator,事务协调器)和TM(Transaction Manager,事务管理器)这样的组件,能够对分布式事务进行管理和协调,大大简化了分布式事务的开发和管理。
-
支持多种数据源和框架:Seata XA模式可以支持多种数据库和数据源,如MySQL、Oracle、Redis等,并且与多种开发框架(如Spring、MyBatis等)兼容,方便接入不同的应用。
-
容错和可靠性:Seata XA模式具有良好的容错能力,能够处理各种异常情况,如网络故障、宕机等,并通过日志记录和重试机制来保证事务的可靠性。
缺点:
-
性能开销:由于XA协议的特性,Seata XA模式在性能方面可能会有一定的开销。XA协议需要进行两阶段提交的过程,涉及到多次网络通信和资源的锁定,这会导致额外的延迟和性能消耗。
-
依赖底层数据库支持:Seata XA模式依赖于底层数据库的XA支持,需要确保数据库驱动程序和配置的数据库都支持XA协议。某些数据库可能存在对XA协议的支持限制,或者需要特定的配置和调优才能达到最佳性能和可靠性。
-
部署和运维复杂性:Seata XA模式在分布式事务的管理和协调方面提供了丰富的功能,但也增加了部署和运维的复杂性。需要配置和管理TC和TM等组件,并且要确保它们的高可用性和可靠性。
综合考虑,Seata XA模式在需要强一致性、分布式事务管理和对底层数据库XA支持较好的场景下是一种较为合适的选择。但对于高性能和并发要求较高的场景,可能需要权衡使用其他事务模式或技术来满足需求。
三、 总结
Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,其中AT 和XA 提供了强一致性的模式,TCC 和SAGA 提供最终一致性的模式。在实际使用Seata进行分布式事务管理时,可以根据不同的业务需求和场景选择合适的事务模式:
- AT(Automatic Transaction)模式:
特点:在AT模式下,Seata框架会自动为参与分布式事务的业务操作生成全局事务ID,并通过拦截器将该ID注入到每个参与者的调用中,实现事务的协调和管理。
应用场景:适用于对业务影响较小、对性能要求较高的场景。例如,对于一些简单的数据更新操作或查询操作,不需要复杂的预处理、确认和取消逻辑,可以选择AT模式。 - TCC(Try-Confirm-Cancel)模式:
特点:TCC模式将业务操作分为Try阶段、Confirm阶段和Cancel阶段,通过事务协调器的支持,确保事务的一致性。在Try阶段,会进行预处理;在Confirm阶段,会进行确认;在Cancel阶段,会进行取消操作。
应用场景:适用于需要对业务预处理、确认和取消的场景,例如下单、支付和库存相关的复杂业务流程。TCC模式可以提供精确的控制和处理失败时的回滚操作。 - Saga模式:
特点:Saga模式基于异步补偿机制,通过一系列的局部事务来构建完整的分布式事务。每个局部事务都有对应的补偿操作,以便在失败的情况下进行回滚。
应用场景:适用于长时间运行、具有复杂业务流程和可能出现部分操作失败的场景。例如,订单状态变更的复杂流程可以使用Saga模式来管理。 - XA(eXtended Architecture)模式:
特点:XA模式使用XA协议实现了分布式事务的管理和协调,确保所有分支事务的一致性。XA模式要求数据库和驱动程序支持XA协议。
应用场景:适用于对事务强一致性要求较高的场景,例如资金转账、库存调整等需要保证原子性操作的场景。
在选择Seata事务模式时,需要综合考虑业务需求、性能要求、一致性要求和开发复杂性等因素。如果有不同的业务场景,也可以结合使用不同的事务模式来满足各种需求。