From 53bc5f0150936b24a4978f86c8bf69f30f175ed0 Mon Sep 17 00:00:00 2001 From: "595208882@qq.com" Date: Tue, 5 Apr 2022 21:34:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E4=BA=8B=E5=8A=A1?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Solution.md | 109 +++++++++++++++------------------- images/Solution/Seate-TCC.png | Bin 0 -> 11579 bytes 2 files changed, 47 insertions(+), 62 deletions(-) create mode 100644 images/Solution/Seate-TCC.png diff --git a/Solution.md b/Solution.md index fe26f44..960274a 100644 --- a/Solution.md +++ b/Solution.md @@ -5921,119 +5921,104 @@ Saga事务模型又叫做长时间运行的事务。其核心思想是**「将 ## Seate -**XA和Seata区别** - -![XA和Seata的区别](images/Solution/xa-seata.png) - -![XA过程](images/Solution/XA过程.png) - -![seata过程](images/Solution/seata过程.png) - -Seata 中有三大模块,分别是 TM、RM 和 TC。 其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。 +Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。目前已支持Dubbo、Spring Cloud、Sofa-RPC、Motan和grpc等RPC框架。 ![seata流程](images/Solution/seata流程.png) -在 Seata 中,分布式事务的执行流程: - -- TM 开启分布式事务(TM 向 TC 注册全局事务记录) -- 按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态 ) -- TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务) -- TC 汇总事务信息,决定分布式事务是提交还是回滚 -- TC 通知所有 RM 提交/回滚 资源,事务二阶段结束 +Seata主要分为以下三大模块: -![seata](images/Solution/seata.png) +- **TC (Transaction Coordinator) - 事务协调者** -- Transaction Coordinator(TC) + 维护全局和分支事务的状态,驱动全局事务提交或回滚。 -事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。 +- **TM (Transaction Manager) - 事务管理器** -- Transaction Manager(TM) + 定义全局事务的范围:开始全局事务、提交或回滚全局事务。 -控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。 +- **RM (Resource Manager) - 资源管理器** -- Resource Manager(RM) + 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。 -控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。 - - - -Seata 会有 4 种分布式事务解决方案,分别是:AT 模式、TCC 模式、Saga 模式和 XA 模式。 - -![seata发展历程](images/Solution/seata发展历程.png) +> 注意:其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。 ### AT模式 -2019年1月,Seata 开源了 AT 模式。AT 模式是一种无侵入的分布式事务解决方案。在 AT 模式下,用户只需关注自己的“业务 SQL”,用户的 “业务 SQL” 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。 +AT模式提供了无侵入自动补偿的事务模式,目前已支持MySQL、Oracle、PostgreSQL、TiDB和MariaDB的AT模式,H2、DB2、SQLServer等。 ![AT 模式](images/Solution/AT模式.png) -**AT模式如何做到对业务的无侵入 :** +**AT模式的前提:** -- **一阶段** +- **基于支持本地 ACID事务的关系型数据库** +- **Java应用,通过JDBC访问数据库** -在一阶段,Seata 会拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。 -![AT模式一阶段](images/Solution/AT模式一阶段.png) -- **二阶段提交** - -二阶段如果是提交的话,因为“业务 SQL”在一阶段已经提交至数据库, 所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。 +**整体机制** -![AT模式二阶段提交](images/Solution/AT模式二阶段提交.png) +- 第一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源 +- 第二阶段 + - 提交异步化,非常快速地完成 + - 回滚通过一阶段的回滚日志进行反向补偿 -- **二阶段回滚** -二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据。回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。 -![AT模式二阶段回滚](images/Solution/AT模式二阶段回滚.png) +### TCC模式 -AT 模式的一阶段、二阶段提交和回滚均由 Seata 框架自动生成,用户只需编写“业务 SQL”,便能轻松接入分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案。 +一个分布式的全局事务,整体是 **两阶段提交** 的模型。全局事务是由若干分支事务组成的,分支事务要满足 **两阶段提交** 的模型要求,即需要每个分支事务都具备自己的: +- 一阶段 prepare 行为 +- 二阶段 commit 或 rollback 行为 +![Seate-TCC](images/Solution/Seate-TCC.png) -### TCC模式 +根据两阶段行为模式的不同,我们将分支事务划分为: -2019 年 3 月份,Seata 开源了 TCC 模式,该模式由蚂蚁金服贡献。TCC 模式需要用户根据自己的业务场景实现 Try、Confirm 和 Cancel 三个操作;事务发起方在一阶段 执行 Try 方式,在二阶段提交执行 Confirm 方法,二阶段回滚执行 Cancel 方法。 +- **Automatic (Branch) Transaction Mode** +- **Manual (Branch) Transaction Mode** -![TCC模式](images/Solution/TCC模式.png) +AT 模式基于 **支持本地 ACID 事务** 的 **关系型数据库**: -TCC 三个方法描述: +- 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录 +- 二阶段 commit 行为:马上成功结束,**自动** 异步批量清理回滚日志 +- 二阶段 rollback 行为:通过回滚日志,**自动** 生成补偿操作,完成数据回滚 -- Try:资源的检测和预留 -- Confirm:执行的业务操作提交;要求 Try 成功 Confirm 一定要能成功 -- Cancel:预留资源释放 +TCC 模式,不依赖于底层数据资源的事务支持: +- 一阶段 prepare 行为:调用 **自定义** 的 prepare 逻辑 +- 二阶段 commit 行为:调用 **自定义** 的 commit 逻辑 +- 二阶段 rollback 行为:调用 **自定义** 的 rollback 逻辑 +所谓 TCC 模式,是指支持把 **自定义** 的分支事务纳入到全局事务的管理中。 -**业务模型分 2 阶段设计:** -用户接入 TCC ,最重要的是考虑如何将自己的业务模型拆成两阶段来实现。 -以“扣钱”场景为例,在接入 TCC 前,对 A 账户的扣钱,只需一条更新账户余额的 SQL 便能完成;但是在接入 TCC 之后,用户就需要考虑如何将原来一步就能完成的扣钱操作,拆成两阶段,实现成三个方法,并且保证一阶段 Try 成功的话 二阶段 Confirm 一定能成功。 +### Saga模式 -![kqcq](images/Solution/kqcq.png) +Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。 -如上图所示,Try 方法作为一阶段准备方法,需要做资源的检查和预留。在扣钱场景下,Try 要做的事情是就是检查账户余额是否充足,预留转账资金,预留的方式就是冻结 A 账户的 转账资金。Try 方法执行之后,账号 A 余额虽然还是 100,但是其中 30 元已经被冻结了,不能被其他事务使用。 +![Saga模式](images/Solution/Saga模式.png) -二阶段 Confirm 方法执行真正的扣钱操作。Confirm 会使用 Try 阶段冻结的资金,执行账号扣款。Confirm 方法执行之后,账号 A 在一阶段中冻结的 30 元已经被扣除,账号 A 余额变成 70 元 。 +**适用场景:** -如果二阶段是回滚的话,就需要在 Cancel 方法内释放一阶段 Try 冻结的 30 元,使账号 A 的回到初始状态,100 元全部可用。 +- **业务流程长、业务流程多** +- **参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口** -用户接入 TCC 模式,最重要的事情就是考虑如何将业务模型拆成 2 阶段,实现成 TCC 的 3 个方法,并且保证 Try 成功 Confirm 一定能成功。相对于 AT 模式,TCC 模式对业务代码有一定的侵入性,但是 TCC 模式无 AT 模式的全局行锁,TCC 性能会比 AT 模式高很多。 +**优势:** -### Saga模式 +- **一阶段提交本地事务,无锁,高性能** +- **事件驱动架构,参与者可异步执行,高吞吐** +- **补偿服务易于实现** -Saga 模式是 Seata 即将开源的长事务解决方案,将由蚂蚁金服主要贡献。在 Saga 模式下,分布式事务内有多个参与者,每一个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向操作和逆向回滚操作。 -分布式事务执行过程中,依次执行各参与者的正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会去退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。 -![Saga模式](images/Solution/Saga模式.png) +**缺点:** -Saga 模式下分布式事务通常是由事件驱动的,各个参与者之间是异步执行的,Saga 模式是一种长事务解决方案。 +- **不保证隔离性** diff --git a/images/Solution/Seate-TCC.png b/images/Solution/Seate-TCC.png new file mode 100644 index 0000000000000000000000000000000000000000..df7a8af7722e6ab497cc7bae91110f75d0c0e568 GIT binary patch literal 11579 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 G1pgPK6fvIw literal 0 HcmV?d00001