一、Seata 的发展历程

阿里巴巴作为国内最早一批进行应用分布式(微服务化)改造的企业,很早就遇到微服务架构下的分布式事务问题。阿里巴巴对于分布式事务问题先后发布了以下解决方案:

  • 2014 年,阿里中间件团队发布 TXC(Taobao Transaction Constructor),为集团内应用提供分布式事务服务。
  • 2016 年,TXC 在经过产品化改造后,以 GTS(Global Transaction Service) 的身份登陆阿里云,成为当时业界唯一一款云上分布式事务产品。在阿云里的公有云、专有云解决方案中,开始服务于众多外部客户。
  • 2019 年起,基于 TXC 和 GTS 的技术积累,阿里中间件团队发起了开源项目 Fescar(Fast & EaSy Commit And Rollback, FESCAR),和社区一起建设这个分布式事务解决方案。
  • 2019 年 fescar 被重命名为了seata(simple extensiable autonomous transaction architecture)。
  • TXC、GTS、Fescar 以及 seata 一脉相承,为解决微服务架构下的分布式事务问题交出了一份与众不同的答卷。

二、分布式事务相关概念

分布式事务主要涉及以下概念:

  • 事务:由一组操作构成的可靠、独立的工作单元,事务具备 ACID 的特性,即原子性、一致性、隔离性和持久性。
  • 本地事务:本地事务由本地资源管理器(通常指数据库管理系统 DBMS,例如 MySQL、Oracle 等)管理,严格地支持 ACID 特性,高效可靠。本地事务不具备分布式事务的处理能力,隔离的最小单位受限于资源管理器,即本地事务只能对自己数据库的操作进行控制,对于其他数据库的操作则无能为力。
  • 全局事务:全局事务指的是一次性操作多个资源管理器完成的事务,由一组分支事务组成。
  • 分支事务:在分布式事务中,就是一个个受全局事务管辖和协调的本地事务。

我们可以将分布式事务理解成一个包含了若干个分支事务的全局事务。全局事务的职责是协调其管辖的各个分支事务达成一致,要么一起成功提交,要么一起失败回滚。此外,通常分支事务本身就是一个满足 ACID 特性的本地事务。

三、Seata 整体工作流程

Seata 对分布式事务的协调和控制,主要是通过 XID 和 3 个核心组件实现的:

  • XID:XID 是全局事务的唯一标识,它可以在服务的调用链路中传递,绑定到服务的事务上下文中。
  • Seata 定义了 3 个核心组件:
  • TC(Transaction Coordinator):事务协调器,它是事务的协调者(这里指的是 Seata 服务器),主要负责维护全局事务和分支事务的状态,驱动全局事务提交或回滚。
  • TM(Transaction Manager): 事务管理器,它是事务的发起者,负责定义全局事务的范围,并根据 TC 维护的全局事务和分支事务状态,做出开始事务、提交事务、回滚事务的决议。
  • RM(Resource Manager):资源管理器,它是资源的管理者(这里可以将其理解为各服务使用的数据库)。它负责管理分支事务上的资源,向 TC 注册分支事务,汇报分支事务状态,驱动分支事务的提交或回滚。

以上三个组件相互协作,TC 以 Seata 服务器(Server)形式独立部署,TM 和 RM 则是以 Seata Client 的形式集成在微服务中运行,其整体工作流程如下图:

Seata分布式事务组件_配置文件

Seata 的整体工作流程如下:

  • TM 向 TC 申请开启一个全局事务,全局事务创建成功后,TC 会针对这个全局事务生成一个全局唯一的 XID;
  • XID 通过服务的调用链传递到其他服务;
  • RM 向 TC 注册一个分支事务,并将其纳入 XID 对应全局事务的管辖;
  • TM 根据 TC 收集的各个分支事务的执行结果,向 TC 发起全局事务提交或回滚决议;
  • TC 调度 XID 下管辖的所有分支事务完成提交或回滚操作。

四、Seata 的下载和安装

4.1.下载seata

使用浏览器访问 https://github.com/seata/seata/releases,在 Seata Server 下载页面分别下载“seata-server-1.6.1.zip”,如下图。

Seata分布式事务组件_分布式事务_02

4.2.解压

解压 seata-server-1.6.1.zip,其目录结构如下图。

Seata分布式事务组件_全局事务_03

4.3.Seata 配置中心

配置中心就像是一个 大柜子一样,内部存放着各种各样的配置文件,我们可以根据自己的需要从其中获取指定的配置文件,加载到对应的客户端中。Seata 支持多种配置中心:

  • nacos(推荐)
  • consul
  • zookeeper
  • file (读本地文件,包含 conf、properties、yml 等配置文件)

4.4.Seata 整合 Nacos 配置中心

Seata和Nacos同属于阿里巴巴,作为配置中心更加的合适。Seata 整合 Nacos 配置中心的操作步骤如下。seata安装版本是1.6.1,版本不同,安装流程也可能不同,这里的版本需要保持一致

  1. 在代码中添加依赖
  2. 配置Seata事务日志存储模式,修改application.yml文件,分别修改store、config、registry相关配置。
  3. 在数据库中创建seata库,执行初始化SQL创建表
  4. seteaserver配置信息添加到nacos
  5. 启动服务,成功登陆seata控制台。
  6. 查看nacos控制台,服务列表新增seata服务。

4.4.1.配置事务日志存储模式

seata的配置在conf文件下,打开后及能找到其yml文件配置,在原配置文件中只有一些seata的基础配置,并未对其有更详细的配置,大多需要根据个人使用情况参照模板配置去配置一些自定义的配置文件。

Seata分布式事务组件_分布式事务_04

默认情况下seata的存储模式是file,但是我们希望能通过本地数据库来进行存储以方便我们进行查看,因此在需要在原配置文件application.yml中添加模板配置文件上的如下配置,这里以MySQL数据库为例演示,修改后如下:

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos 、 consul 、 apollo 、 zk  、 etcd3
    type: nacos
    nacos:
      server-addr: http://127.0.0.1:8848
      # namespace: 7392baed-d98b-48a4-8676-34e1b38eade6
      namespace:
      group: SEATA_GROUP
      username:
      password:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key: ""
      #secret-key: ""
      data-id: seataServer.properties
  registry:
    # support: nacos 、 eureka 、 redis 、 zk  、 consul 、 etcd3 、 sofa
    type: nacos
    preferred-networks: 30.240.*
    nacos:
      application: seata-server
      server-addr: http://127.0.0.1:8848
      group: SEATA_GROUP
      namespace:
      # namespace: 7392baed-d98b-48a4-8676-34e1b38eade6
      cluster: default
      username:
      password:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key: ""
      #secret-key: ""
  store:
    # support: file 、 db 、 redis
    mode: db
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

如下图所示:

Seata分布式事务组件_分布式事务_05

另外需要注意的一点是:seata-1.6.1默认的mysql配置的数据库驱动是8.0以下的,因此如果我们使用8.0的配置的话,除了更改配置信息还需要检查运行jar包是否存在。在lib文件下的jdbc目录下可以看到已经包含了8.0+的jar包了,不需要我们额外导入,如果其他版本需要但是没有的话还是要自己手动导入jar包的,如下图所示:

Seata分布式事务组件_分布式事务_06

4.4.2.创建seata库执行初始化SQL建表(仅db方式)

全局事务会话信息由3块内容构成,全局事务–>分支事务–>全局锁,对应表global_table、branch_table、lock_table,当前版本支持 3大数据库:mysql、postgresql 、oracle。在MySQL 中创建数据库seata,执行的mysql脚本为: /seata/script/server/db/mysql.sql,创建后如下图所示:

Seata分布式事务组件_分布式事务_07

4.4.3.在nacos中添加Seata Server 配置信息

Seata从v1.4.2版本开始,支持从nacos中一个Nacos dataId配置项中获取所有配置信息。所以,在nacos配置中心中新建配置,dataId为 seataServer.properties配置项

  • 在nacos中 添加dataID:seataServer.properties文件,组位是:SEATA_GROUP,具体内容还是config.txt中(在 Seata Server 安装目录进入目录:/seata/script/config-center/config.txt)的配置,可以自己添加修改内容,如下:

修改内容说明:

Seata分布式事务组件_配置文件_08

事务路由规则配置,只针对客户端(项目代码和这里要保持一致),配置修改内容说明:

Seata分布式事务组件_全局事务_09

修改store mode 为 db`则需要这些配置

Seata分布式事务组件_配置文件_10

 整个修改过的配置文件如下:

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption
store.publicKey=""

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
  • 添加配置之后,如下图所示:

Seata分布式事务组件_全局事务_11

4.4.4.启动seata

此首先需要启动Nacos后然后手动启动seate服务,双击seata-server.bat即可启动成功:

Seata分布式事务组件_分布式事务_12

查看nacos控台台

Seata分布式事务组件_配置文件_13

访问seata控制台在浏览器输入如下图所示:http://127.0.0.1:7091/ 账户密码均为:seata

Seata分布式事务组件_全局事务_14