Seata-based distributed transaction solution

Seata-based distributed transaction solution

Foreword

The last article has brought you a preliminary understanding of the basic solution of distributed transactions. Today I will introduce you to distributed transaction middleware Seata and a demo of distributed transactions based on seata

text

background

In January 2019, the Alibaba middleware team launched the open source project Fescar (Fast & EaSy Commit And Rollback) to work with the community to build open source distributed transaction solutions. Fescar's vision is to make the use of distributed transactions as simple and efficient as the use of local transactions, and to gradually solve all the problems of distributed transactions encountered by developers. After Fescar was open sourced, Ant Financial joined the Fescar community to participate in the co-construction and contributed the TCC model in the 0.4.0 version of Fescar. In order to build a more neutral, open, and ecologically rich distributed transaction open source community, after voting by core members of the community, everyone decided to upgrade the brand of Fescar and renamed it Seata, which means: Simple Extensible Autonomous Transaction Architecture, is a set One-stop distributed transaction solution.

What is Seata?

Seata is an open source distributed solution dedicated to providing high-performance and simple-to-use distributed transaction services. The original intention of its design is:

  • No intrusion to business: Intrusion here refers to the design and transformation of applications at the business level due to the constraints of the technical issue of distributed transactions. This design and modification often bring high R & D and maintenance costs to the application. Solving the distributed transaction problem at the middleware level does not require the application to do extra work at the business level.
  • High performance: Introducing the guarantee of distributed transactions, there will inevitably be additional overhead, causing a decrease in performance. Reduce the performance loss introduced by distributed transactions to a very low level, so that applications are not affected by the availability of services due to the introduction of distributed transactions

Seata provides users with AT mode, TCC mode, Soga mode and XA transaction mode to create a one-stop distributed transaction solution for users.

我们先来了解一下Seata的重要的组件:

  • Transcation Coordinator(TC):事务协调器, 维护全局事务的事务状态,负责协调并驱动全局事务的提交或回滚 即Seata-server
  • Transaction Manager(TM): 维护全局事务的边界,负责开启一个全局事务,并负责发起全局事务的提交或者回滚的决议 即Seata-Client,事务的发起者,整个微服务调用链的起点
  • Resource Manger(RM): 控制分支事务,负责注册分支事务,分支事务状态的汇报,并接受事务协调器的指令,驱动本地事务的提交或者回滚 即Seata-Client, 事务的参与者,负责本地事务的处理以及与Seata-server的交互

一个典型的分布式事务过程:

  1. TM 向TC发起创建一个全局事务,TC创建全局事务成功并生成一个全局唯一的XID
  2. XID在整个服务调用上下文中传递
  3. RM向TC注册分支事务,并入对应XID的全局事务的管辖下
  4. TM 向TC 发起对应XID全局事务的提交或回滚决议
  5. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
2pc
seata事务处理过程

接下来介绍下Seata各个事务模式

AT模式

AT模式的使用的提前是:一是基于支持ACID的关系数据库,而是Java应用,通过JDBC访问数据库。AT模式其实是对基于XA解决方案的改进,将资源管理器从数据库层面抽离出来,而已二方包的形式作为中间件层部署在应用的一侧。不依赖与数据库本身对协议的支持,当然也不需要数据库支持 XA 协议。

它的基本步骤:

  • 一阶段:
  1. 解析业务sql
  2. 获取sql执行前的镜像,前镜像
  3. 执行业务sql
  4. 获取sql执行后的镜像,后镜像
  5. 添加undo_log日志,把前后镜像数据和业务sql相关的信息组成回滚日志,添加到undo_log表中
  6. 向TC注册分支事务,并申请全局锁
  7. 事务提交,将业务操作和undo_log一起提交
  8. 释放本地锁与数据库连接资源
  • 二阶段-提交:
  1. 收到TC发出的提交分支事务的请求,将请求放进一个异步任务队列中,马上返回成功给TC
  2. 异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录
  • 二阶段-回滚
  1. 收到TC发出的回滚请求,开启一个事务
  2. 根据XID和Branch ID 查找对应的UNDO_LOG记录
  3. 数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理
  4. 根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句
  5. 提交本地事务

这时有的同学可能会问为啥它能在第一阶段就能释放锁呢

Seata的JDBC 数据源代理通过对业务 SQL 的解析,把业务数据在更新前后的数据镜像组织成回滚日志,利用本地事务的 ACID 特性,将业务数据的更新和回滚日志的写入在同一个本地事务中提交。这样就可以保证:任何提交的业务数据的更新一定有相应的回滚日志存在。基于这样的设计,就可以在第一阶段释放本地锁

那么AT模式如何保证写隔离的呢

  1. 本地事务在commit之前都会去申请全局锁,需要确保拿到全局锁才能commit
  2. 拿不到全局锁便不会commit
  3. 申请全局锁有限制范围,超出了这个范围,就会回滚本地事务并释放本地锁

如何保证读隔离

Seata的AT模式默认的全局隔离级别是读未提交。如果应用在特定场景下,必需要求全局的读已提交 ,目前Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。SELECT FOR UPDATE 语句的执行会申请全局锁,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到全局锁拿到,即读取的相关数据是已提交 的,才返回。出于总体性能上的考虑,Seata目前的方案并没有对所有SELECT语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。

AT模式优缺点

优点:

  • 不需要数据库对XA协议的支持
  • 并发和吞吐量提升,本地锁在第一阶段就可以释放

缺点

  • 只能用在支持ACID的关系型数据库
  • 事务隔离级别最高支持到读已提交的水平,SQL 的解析还不能涵盖全部的语法等。

TCC模式

TCC模式 可以把自定义的分支事务纳入到全局事务之中,不依赖于底层数据资源对事务的依赖

它的处理过程是:

  • 一阶段 prepare 行为:调用自定义的 prepare 逻辑。
  • 二阶段 commit 行为:调用自定义的 commit 逻辑。
  • 二阶段 rollback 行为:调用自定义的 rollback 逻辑。
2pc
seata TCC模式
@LocalTCC
public interface TccAcountAction {

    @TwoPhaseBusinessAction(name = "DubboTccActionTwo" , commitMethod = "commit", rollbackMethod = "rollback")
    public boolean prepare(BusinessActionContext actionContext,
                           @BusinessActionContextParameter(paramName = "b")
 String b,
                           @BusinessActionContextParameter(paramName = "c", index = 0) List list)
;

    public boolean commit(BusinessActionContext actionContext);


    public boolean rollback(BusinessActionContext actionContext);
}
复制代码

整个事务的过程:

  • TM 向TC发起创建一个全局事务,TC创建全局事务成功并生成一个全局唯一的XID
  • 依次执行分支事务
  • - 向TC注册分支事务
  • 执行事务的prepare阶段 即调用prepare方法
  • 提交或者回滚全局事务,TC向每个RM发起commit或者rollbac,即调用写好的commit或者rollback方法

TCC模式的优缺点

优点:

  • 可以把众多非事务的资源纳入纳入全局事务的管理,如缓存

缺点

  • 要自己实现补偿逻辑

Soga模式

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

2pc
seata Soga模式

Saga的实现:

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

  1. 通过状态图来定义服务调用的流程并生成 json 状态语言定义文件
  2. 状态图中一个节点可以是调用一个服务,节点可以配置它的补偿节点
  3. 状态图 json 由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚

​ 注意: 异常发生时是否进行补偿也可由用户自定义决定

  1. 可以实现服务编排需求,支持单项选择、并发、子流程、参数转换、参数映射、服务执行状态判断、异常捕获等功能

适用场景:

  • 业务流程长、业务流程多
  • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

优势:

  • 一阶段提交本地事务,无锁,高性能
  • 事件驱动架构,参与者可异步执行,高吞吐
  • 补偿服务易于实现

缺点:

  • 不保证隔离性

小编自己也写了一个基于Seata的AT模式/TCC模式的demo,github地址:https://github.com/GBBP1813/seata-use

基于分布式事务中间件seata的分布式解决方案

本Demo工程基于seata/seata-sample实现AT/MT模式

涉及技术栈:

springboot dubbo zookeeper

使用本案例demo步骤

1.准备项目

克隆此项目到本地,导入idea,JDK为1.8 创建业务数据库 sql在项目中 包括undo表

模块:

Seata-order 订单服务模块

Seata-storage 库存服务模块

Seata-account 账户服务模块

Seata-common 公共模块

Seata-transcation-manage TM模块

2.环境准备

1)先下载seata-server 地址:https://github.com/seata/seata/releases 下载完后修其 数据库配置

由于demo使用的是db模式存储事务日志,要创建三张表:global_table,branch_table,lock_table,建表sql在上面下载的seata-server的/conf/db_store.sql中; 配置文件事务组也可以自己修改,修改的话项目中也要对应变更

2)启动本地zookeeper

3)启动seata-server

3.启动项目

分别启动项目四个子模块

4.模拟请求

AT模式

Commit:

curl -H "Content-Type:application/json" -X POST -d '{"userId":"1","commodityCode":"C201901140001","name":"电脑","count":1,"amount":"10"}' 'localhost:8004/tmManager/buy'
复制代码

Rollback:

curl -H "Content-Type:application/json" -X POST -d '{"userId":"1","commodityCode":"C201901140001","name":"电脑","count":1,"amount":"10"}' 'localhost:8004/tmManager/buy?throwExp=true'
复制代码

TCC模式:

Commit:

curl -H "Content-Type:application/json" -X POST -d ''  'localhost:8004/tcc/bug'
复制代码

Rollback:

curl -H "Content-Type:application/json" -X POST -d ''  'localhost:8004/tcc/bug?throwExp=true'
复制代码

Guess you like

Origin juejin.im/post/5e9ebfcd51882573c508ea1b