Seata分布式事务模式(TA、TCC、XA、SAGA)工作机制

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 分布式应用有一个比较明显的问题就是,一个业务流程通常需要几个服务来完成,业务的一致性很难保证。为了保障业务一致性,每一步都要在 catch 里去处理前面所有的“回滚”操作,可读性及维护性差,开发效率低下。

前言

分布式应用痛点

分布式应用有一个比较明显的问题就是,一个业务流程通常需要几个服务来完成,业务的一致性很难保证。为了保障业务一致性,每一步都要在 catch 里去处理前面所有的“回滚”操作,可读性及维护性差,开发效率低下。

分布式事务解决方案

分布式事务解决方案中的2PC、3PC、TCC等,大多是提供了事务协调器这一角色,协调业务中的各个事务要么全部成功,要么全部失败,不用在业务中嵌套处理“回滚事务”,更好的解决分布式事务中一致性问题。

Seata

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。为用户提供了 AT、TCC、SAGA 和 XA 事务模式,打造一站式的分布式解决方案。其定义了3个角色完成分布式事务的工作。

  • TC (Transaction Coordinator) - 事务协调者
    维护全局和分支事务的状态,驱动全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器
    定义全局事务的范围:开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - 资源管理器
    管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

其协调流程如下
在这里插入图片描述

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

Seata AT模式

AT模式是Seata默认的分布式解决方案

前提

  • 基于支持本地 ACID 事务的关系型数据库。
  • 依赖回滚日志表UNDO_LOG,以业务表形式存在,需要单独创建。
  • Java 应用,通过 JDBC 访问数据库。

工作机制

AT模式属于两阶段提交协议的演变:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
  • 二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿。

以一个示例来说明整个 AT 分支的工作过程。

业务表stock
| Field | Type | Key |
|--|--|--|
| id | bigint(20) | PRI |
| goods_id | bigint(20) | |
| count | bigint(20) | |

业务逻辑

update stock set count = 20 where goods_id = 100001;

一阶段

执行过程:

  1. 解析 SQL:得到 SQL 的类型(UPDATE),表(stock),条件(where goods_id = 100001)等相关的信息。
  2. 查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。

     select id,goods_id,count from stock where goods_id = 100001;
    

    得到前镜像

    | id | goods_id | count |
    |--|--|--|
    | 1 | 100001 | 0 |

  3. 执行业务sql,count 更新为20
  4. 查询后镜像:根据前镜像的结果,通过主键定位数据。
     select id, goods_id,count from stock where id = 1;
    
    得到后镜像
    | id | goods_id | count |
    |--|--|--|
    | 1 | 100001 | 20 |
  5. 插入日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到 UNDO_LOG 表中。

     {
         
         
         "branchId": xxxxxxxx,
         "undoItems": [{
         
         
             "afterImage": {
         
         
                 "rows": [{
         
         
                     "fields": [{
         
         
                         "name": "id",
                         "type": 4,
                         "value": 1
                     }, {
         
         
                         "name": "goods_id",
                         "type": 4,
                         "value": 100001
                     }, {
         
         
                         "name": "count",
                         "type": 4,
                         "value": 0
                     }]
                 }],
                 "tableName": "stock"
             },
             "beforeImage": {
         
         
                 "rows": [{
         
         
                     "fields": [{
         
         
                         "name": "id",
                         "type": 4,
                         "value": 1
                     }, {
         
         
                         "name": "goods_id",
                         "type": 4,
                         "value": 100001
                     }, {
         
         
                         "name": "count",
                         "type": 4,
                         "value": 20
                     }]
                 }],
                 "tableName": "stock"
             },
             "sqlType": "UPDATE"
         }],
         "xid": "xid:xxx"
     }
    
  6. 提交事务前,向 TC 注册分支:申请 stock 表中,主键值等于 1 的记录的 全局锁
  7. 本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
  8. 将本地事务提交的结果上报给 TC。

二阶段-提交

  1. 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
  2. 异步任务阶段批量地删除相应 UNDO LOG 记录。

二阶段-回滚

收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。

  1. 通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
  2. 数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。
  3. 根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:

     update stock set count = 0 where id = 1;
    
  4. 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。

Seata TCC模式

前提

回顾TCC解决方案,其 Try、Confirm、Cancel 3 个方法均由业务编码实现。

以传统的订单、库存、账户服务为例

在 try 阶段尝试预留资源,插入订单、扣减库存、扣减金额,这三个服务都是要提交本地事务的,这里可以把资源转入中间表。
在 commit 阶段,再把 try 阶段预留的资源转入最终表。
而在 cancel 阶段,把 try 阶段预留的资源进行释放,比如把账户金额返回给客户的账户。

TCC 模式在 try 阶段的锁定资源并不是真正意义上的锁定,而是真实提交了本地事务,将资源预留到中间态,并不需要阻塞等待,因此效率比其他模式要高。

工作机制

Seata中所谓 TCC 模式,是指支持把自定义的分支事务纳入到全局事务的管理中,不依赖于底层数据资源的事务支持,其工作流程如下:

  • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
  • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
  • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

在自定义的逻辑中,可以操作redis完成数据的一致性以提升业务性能。

Seata Saga模式

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

实现机制

目前SEATA提供的Saga模式是基于状态机引擎来实现的,机制是:

  1. 通过状态图来定义服务调用的流程并生成 json 状态语言定义文件。
  2. 状态图中一个节点可以是调用一个服务,节点可以配置它的补偿节点。
  3. 状态图 json 由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚。
  4. 可以实现服务编排需求,支持单项选择、并发、子流程、参数转换、参数映射、服务执行状态判断、异常捕获等功能

示例状态图:
在这里插入图片描述

Seata XA模式

前提

  • 支持XA 事务的数据库。
  • Java 应用,通过 JDBC 访问数据库。

工作机制

在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种事务模式。
在这里插入图片描述

  • 执行阶段:

    • 可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证可回滚。
    • 持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证持久化(即,之后任何意外都不会造成无法回滚的情况)
  • 完成阶段:
    • 分支提交:执行 XA 分支的 commit
    • 分支回滚:执行 XA 分支的 rollback

总结

在当前的技术发展阶段,不存一个分布式事务处理机制可以完美满足所有场景的需求。

一致性、可靠性、易用性、性能等诸多方面的系统设计约束,需要用不同的事务处理机制去满足。

Seata 项目最核心的价值在于:构建一个全面解决分布式事务问题的 标准化 平台。

基于 Seata,上层应用架构可以根据实际场景的需求,灵活选择合适的分布式事务解决方案。

AT是无侵入的分布式事务解决方案,满足大部分分布式事务场景。

TCC 模式是高性能分布式事务解决方案,适用于核心系统等对性能有很高要求的场景。

Saga 模式是长事务解决方案,适用于业务流程长且需要保证事务最终一致性的业务系统。

XA模式也是无侵入的分布式事务解决方案,适用于对一致性要求高的场景。

在这里插入图片描述

AT、TCC、Saga 都是补偿型的,补偿型分布式事务机制因为不要求事务资源本身(如数据库)的机制参与,所以无法保证从事务框架之外的全局视角的数据一致性。

比如,一条库存记录,处在补偿型事务处理过程中,由 100 扣减为 50。此时,仓库管理员连接数据库,查询统计库存,就看到当前的 50。之后,事务因为异常回滚,库存会被补偿回滚为100。显然,仓库管理员查询统计到的50就是脏数据。

XA 模式的加入,补齐了 Seata 在全局一致性场景下的缺口,形成 AT、TCC、Saga、XA 四大事务模式的版图,基本可以满足所有场景的分布式事务处理诉求。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3月前
|
存储 消息中间件 Apache
比较微服务中的分布式事务模式
比较微服务中的分布式事务模式
72 2
|
24天前
|
监控
Saga模式在分布式系统中保证事务的隔离性
Saga模式在分布式系统中保证事务的隔离性
|
1月前
|
存储 缓存 NoSQL
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
64 4
|
2月前
|
SQL NoSQL 数据库
SpringCloud基础6——分布式事务,Seata
分布式事务、ACID原则、CAP定理、Seata、Seata的四种分布式方案:XA、AT、TCC、SAGA模式
SpringCloud基础6——分布式事务,Seata
|
2月前
Saga模式在分布式系统中如何保证事务的隔离性
Saga模式在分布式系统中如何保证事务的隔离性
|
3月前
|
存储 分布式计算 算法
探索Hadoop的三种运行模式:单机模式、伪分布式模式和完全分布式模式
在配置Hadoop集群之前,了解这三种模式的特点、适用场景和配置差异是非常重要的。这有助于用户根据个人需求和资源情况,选择最适合自己的Hadoop运行模式。在最初的学习和开发阶段,单机模式和伪分布式模式能为用户提供便利和成本效益。进而,当用户要处理大规模数据集时,完全分布式模式将是理想的选择。
197 2
|
3月前
|
关系型数据库 MySQL 数据库
SpringCloud2023中使用Seata解决分布式事务
对于分布式系统而言,需要保证分布式系统中的数据一致性,保证数据在子系统中始终保持一致,避免业务出现问题。分布式系统中对数据的操作要么一起成功,要么一起失败,必须是一个整体性的事务。Seata简化了这个使用过程。
90 2
|
3月前
|
开发者 云计算 数据库
从桌面跃升至云端的华丽转身:深入解析如何运用WinForms与Azure的强大组合,解锁传统应用向现代化分布式系统演变的秘密,实现性能与安全性的双重飞跃——你不可不知的开发新模式
【8月更文挑战第31天】在数字化转型浪潮中,传统桌面应用面临新挑战。本文探讨如何融合Windows Forms(WinForms)与Microsoft Azure,助力应用向云端转型。通过Azure的虚拟机、容器及无服务器计算,可轻松解决性能瓶颈,满足全球用户需求。文中还提供了连接Azure数据库的示例代码,并介绍了集成Azure Storage和Functions的方法。尽管存在安全性、网络延迟及成本等问题,但合理设计架构可有效应对,帮助开发者构建高效可靠的现代应用。
32 0
|
3月前
|
Java 关系型数据库 MySQL
(二十七)舞动手指速写一个Seata-XA框架解决棘手的分布式事务问题
相信大家对于事务问题都不陌生,在之前《MySQL事务篇》中曾详解过MySQL的事务机制,在传统的单库环境下开发,咱们可依赖于MySQL所提供的事务机制,来确保单个事务内的一组操作,要么全部执行成功,要么全部执行失败。
|
3月前
|
Java Nacos Docker
"揭秘!Docker部署Seata遇上Nacos,注册成功却报错?这些坑你不得不防!一网打尽解决秘籍,让你的分布式事务稳如老狗!"
【8月更文挑战第15天】在微服务架构中,Nacos搭配Seata确保数据一致性时,Docker部署Seata后可能出现客户端连接错误,如“can not connect to services-server”。此问题多由网络配置不当、配置文件错误或版本不兼容引起。解决策略包括:调整Docker网络设置确保可达性;检查并修正`file.conf`和`registry.conf`中的Nacos地址和端口;验证Seata与Nacos版本兼容性;修改配置后重启服务;参考官方文档和最佳实践进行配置。通过这些步骤,能有效排除故障,保障服务稳定运行。
281 0

热门文章

最新文章

下一篇
无影云桌面