分布式事务之Seata
它把一个分布式事务理解成一个包含了若干分支事务的全局事务。 而全局事务的职责是协调它管理的分支事务达成一致性,要么一起成功提交,要么一起失败回滚。
该图片来自互联网
Seata 中存在几种重要角色
TC(Transaction Coordinator)
事务协调者。管理全局的分支事务的状态,用于全局性事务的提交和回滚。
TM(Transaction Manager)
事务管理者。用于开启、提交或回滚事务。
RM(Resource Manager)
资源管理器。用于分支事务上的资源管理,向 TC 注册分支事务,上报分支事务的状态,接收 TC 的命令来提交或者回滚分支事务。
其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。
Seata工作流程
在 Seata 中,分布式事务的执行流程:
- TM 开启分布式事务(TM 向 TC 注册全局事务记录);
- 按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态 );
- TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务);
- TC 汇总事务信息,决定分布式事务是提交还是回滚;
- TC 通知所有 RM 提交/回滚 资源,事务二阶段结束;
Seata事务模式
Seata AT模式
在生产环境上,我实际使用过的模式
该图片来自互联网
在 AT 模式下,用户只需关注自己的“业务 SQL”,用户的 “业务 SQL” 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。
Seata AT模式是如何做到对业务无侵入的?
该图片来自互联网
在一阶段,Seata 会拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性
二阶段提交或回滚
-
二阶段提交:二阶段如果是提交的话,因为“业务 SQL”在一阶段已经提交至数据库, 所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。
该图片来自互联网 -
二阶段回滚:二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据。回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。
该图片来自互联网
Seata TCC模式
该图片来自互联网
TCC 模式需要用户根据自己的业务场景实现 Try、Confirm 和 Cancel 三个操作;事务发起方在一阶段执行 Try 方式,在二阶段提交执行 Confirm 方法,二阶段回滚执行 Cancel 方法
- Try:资源的检测和预留;
- Confirm:执行的业务操作提交;要求 Try 成功 Confirm 一定要能成功;
- Cancel:预留资源释放;
TCC 设计
- TCC 设计 - 允许空回滚。Cancel 接口设计时需要允许空回滚。在 Try 接口因为丢包时没有收到,事务管理器会触发回滚,这时会触发 Cancel 接口,这时 Cancel 执行时发现没有对应的事务 xid 或主键时,需要返回回滚成功。让事务服务管理器认为已回滚,否则会不断重试,而 Cancel 又没有对应的业务数据可以进行回滚。
- TCC 设计 - 防悬挂控制。悬挂的意思是:Cancel 比 Try 接口先执行,出现的原因是 Try 由于网络拥堵而超时,事务管理器生成回滚,触发 Cancel 接口,而最终又收到了 Try 接口调用,但是 Cancel 比 Try 先到。按照前面允许空回滚的逻辑,回滚会返回成功,事务管理器认为事务已回滚成功,则此时的 Try 接口不应该执行,否则会产生数据不一致,所以我们在 Cancel 空回滚返回成功之前先记录该条事务 xid 或业务主键,标识这条记录已经回滚过,Try 接口先检查这条事务xid或业务主键如果已经标记为回滚成功过,则不执行 Try 的业务操作。(其实就是幂等)
- TCC 设计 - 幂等控制。幂等性的意思是:对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的。因为网络抖动或拥堵可能会超时,事务管理器会对资源进行重试操作,所以很可能一个业务操作会被重复调用,为了不因为重复调用而多次占用资源,需要对服务设计时进行幂等控制,通常我们可以用事务 xid 或业务主键判重来控制。在写代码时,TCC三个方法均需保证幂等性
与Seata AT模式比较
相对于 AT 模式,TCC 模式对业务代码有一定的侵入性,但是 TCC 模式无 AT 模式的全局行锁,TCC 性能会比 AT 模式高很多。但就是需要业务端写很多代码,这个是缺点,强侵入性
Seata Saga模式
长事务解决方案。在 Saga 模式下,分布式事务内有多个参与者,每一个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向操作和逆向回滚操作。
- Saga模式适用于业务流程长且需要保证事务最终一致性的业务系统,Saga 模式一阶段就会提交本地事务,无锁、长流程情况下可以保证性能。
- 不能保证隔离。原因: Saga 模式由于一阶段已经提交本地数据库事务,且没有进行“预留”动作,所以不能保证隔离性
Saga 模式不保证事务的隔离性,在极端情况下可能出现脏写。比如在分布式事务未提交的情况下,前一个服务的数据被修改了,而后面的服务发生了异常需要进行回滚,可能由于前面服务的数据被修改后无法进行补偿操作。这时的一种处理办法可以是“重试”继续往前完成这个分布式事务。由于整个业务流程是由状态机编排的,即使是事后恢复也可以继续往前重试。所以用户可以根据业务特点配置该流程的事务处理策略是优先“回滚”还是“重试”,当事务超时的时候,Server 端会根据这个策略不断进行重试。
由于 Saga 不保证隔离性,所以我们在业务设计的时候需要做到“宁可长款,不可短款”的原则,长款是指在出现差错的时候站在我方的角度钱多了的情况,钱少了则是短款,因为如果长款可以给客户退款,而短款则可能钱追不回来了,也就是说在业务设计的时候,一定是先扣客户帐再入帐,如果因为隔离性问题造成覆盖更新,也不会出现钱少了的情况。
Seata Saga模式原理
基于状态机引擎的 Saga 实现: 它基于事件驱动架构,每个步骤都是异步执行的,步骤与步骤之间通过事件队列流转, 极大的提高系统吞吐量。每个步骤执行时会记录事务日志,用于出现异常时回滚时使用,事务日志会记录在与业务表所在的数据库内,提高性能。
“向前”
Saga 服务设计经验和TCC类似,内容也是一致的,Saga多了一个 【自定义事务恢复策略】 由于Saga 事务不保证隔离性,在极端情况下可能由于脏写无法完成回滚操作,所以状态机引擎除了提供”回滚”能力还需要提供”向前“执行的恢复操作,让业务最终执行成功。 用户可以根据业务特点配置该流程的事务处理策略是优先“回滚”还是“重试”,当事务超时的时候,服务器端会根据这个策略不断进行重试。
Seata XA模式
前提:
- 支持XA 事务的数据库。
- Java 应用,通过 JDBC 访问数据库。
XA 协议是由X/Open 公司于1991 年发布的一套标准协议。 XA 是eXtended Architecture 的缩写,因此该协议旨在解决如何在异构系统中保证全局事务的原子性。
在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。 从编程模型上,XA 模式与 AT 模式保持完全一致。
除了Seata还有哪些分布式事务框架?
- ByteTCC:美团点评开源的分布式事务框架,基于TCC补偿机制实现,支持高性能和高可用,提供了丰富的API接口和工具支持
- Nacos-AT:阿里巴巴开源的分布式事务框架,基于TCC补偿机制实现,可与Nacos和Spring Cloud等分布式框架无缝集成
- SkyWalking-Tx: Apache SkyWalking社区开源的分布式事务框架,支持TCC和Saga等事务模式,提供了完善的监控和追踪功能。
- TCC-Transaction:华为开源的分布式事务框架,基于TCC补偿机制实现,支持高性能和高可用,提供了简单易用的API接口和工具支持。
- Atomikos:开源的Java事务管理器,支持XA协议,可用于实现分布式事务的控制和管理,提供了简单易用的API接口和工具支持。
使用Seata会遇到哪些问题
-
在高并发下出现的问题:AT模式获取全局锁失败
Seata的AT、XA模式都是基于全局事务实现的,在高并发的场景下会出现获取全局锁异常,因此这两种模式都不适用高并发场景; Seata TCC模式性能比AT模式的好一点,但是并发量大于100的话还是不适合; 如果基本没有什么并发量的话,可以选择AT模式;并发量在一百内的话可以使用TCC模式 高并发场景,不适合使用Seata,适合用中间件,例如用rocketmq替代Seata,可以弥补Seata的不足
-
高并发超时
容易犯的错误: 服务调用->发现注解->创建事务->
等待锁->获取锁
->业务处理调整代码顺序就可以解决: 用户请求
->等待锁->获取锁
->服务调用->发现注解->创建事务->业务处理 -
还遇到一些字段长度的问题,调整表的字段长度。但是在最新版的Seata上想这些问题都已经解决了
网站当前构建日期: 2024.11.18