目录

一、简介

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

在 Seata 开源之前,Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一致性中间件的角色,帮助经济体平稳地度过历年的双 11,对各 BU 业务进行了有力的支撑。经过多年沉淀与积累,商业化产品先后在阿里云、金融云进行售卖。2019 年 1 月为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,未来 Seata 将以社区共建的形式帮助其技术更加可靠与完备。

官网:

术语

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

事务模式

Seata 提供了 XA、AT、TCC 与 SAGA 四种分布式事务模式

XA 模式

前提:

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

整体机制:

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

image

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

问题:

  • 回滚日志无法自动清理,需要手工清理。
  • 多线程下对同一个 RM 中的数据进行修改,存在 ABA 问题。

AT 模式

前提:

  • 基于支持本地 ACID 事务的关系型数据库。
  • Java 应用,通过 JDBC 访问数据库。

整体机制:

两阶段提交协议的演变:

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

问题:

  • 不支持 NoSQL。
  • 全局 commit/rollback 阶段及回滚日志的清除过程,完全“自动化”无法实现定制化过程。

TCC 模式

AT 模式基于支持本地 ACID 事务关系型数据库

  • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
  • 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
  • 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。

相应的,TCC 模式,不依赖于底层数据资源的事务支持:

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

所谓 TCC 模式,是指支持把自定义 的分支事务纳入到全局事务的管理中。

TCC,Try Confirm/Cancel,同样也是 2PC 的,其与 AT 的重要区别是,支持将自定义的分支事务纳入到全局事务管理中,即可以实现定制化的日志清理与回滚过程。当然,该模式对业务逻辑的侵入性是较大的。

image

Sage 模式

对于架构复杂,且业务流程较多较长的系统,一般不适合使用 2PC 的分布式事务模式。因为这种系统一般无法提供 TM、TC、RM 三种接口。此时,我们可以尝试着选择 Saga 模式

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

image

其应用场景是:在无法提供 TC、TM、RM 接口的情况下,对于一个流程很长的复杂业务,其会包含很多的子流程(事务)。每个子流程都让它们真实提交它们真正的执行结果。

只有当前子流程执行成功后才能执行下一个子流程。若整个流程中所有子流程全部执行成功,则整个业务流程成功;只要有一个子流程执行失败,则可采用两种补偿方式:

  • 向后恢复:对于其前面所有成功的子流程,其执行结果全部撤销
  • 向前恢复:重试失败的子流程直到其成功。当然这个前提是要确保每个分支事务都能够成功。

2PC模式的区别

Saga 模式的所有分支事务是串行执行的,而 2PC 的则是并行执行的。

Saga 模式没有 TC,其是通过子流程间的消息传递来完成全局事务管理的,而 2PC 则具有 TC,其是通过 TC 完成全局事务管理的。

说明

无论是 AT 模式,还是 TCC 模式或 XA 模式,都需要有事务协调器 TC,即 Seata Server

下载地址:

Seata 的源码包与二进制包均需要下载。因为 Seata Client 需要使用 Seata 的源码包中的一个 sql 脚本文件。

image

二、Seata Server 存储模式

Seata Server 需要对全局事务与分支事务进行存储,以便对它们进行管理。其存储模式目前支持三种:file、db 与 redis。

  • file 模式:会将相关数据存储在本地文件中,一般用于 Seata Server 的单机测试。
  • db 模式:会将相关数据存储在数据库中,一般用于生产环境下的 Seata Server 集群部署。生产环境下使用最多的模式。
  • redis 模式:会将相关数据存储在 redis 中,一般用于生产环境下的 Seata Server 集群部署。性能略高于 db 模式,如果对性能要求较高,可选择 redis 模式。

1、file 模式

①修改application.xml

将 seata-server-1.7.1.zip 解压后,修改 seata 解压目录下的 conf 目录中的 application.yml文件。默认file模式,在该文件中需要配置三类信息:Seata 的配置中心、Seata 的注册中心,及回滚日志信息。不过,对于 file 模式,只需要修改以下位置即可。

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: file
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: file
  store:
    # support: file 、 db 、 redis
    mode: file

②启动Seata-Server

seata/bin目录下直接双击seata-server.sh批处理文件即可启动。启动后在该 bin 目录中就可以直接看到生成的 sessionStore 目录及其中的 root.data 文件。

2、db 模式

file 模式一般用于简单测试,生产环境下使用的是 db 模式

①运行mysql.sql脚本

在 seata 包解压目录的 script/server/db 下找到mysql.sql 文件。该脚本文件中创建了 4张表。这 4 张表都是用于保存整个系统中分布式事务相关日志数据的。

image

该脚本文件中仅有建表语句,没有创建数据库的语句,说明使用什么数据库名称都可以。为了方便,我们在脚本文件中直接添加了建库语句,并指定数据库名称为 seata。

create database if not exists seata;

image

②修改application.xml

修改 seata 解压目录下的conf目录中的application.yml 文件。在该文件中需要配置三类信息:Seata 的配置中心、Seata 的注册中心,及回滚日志信息。

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${log.home:${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: 127.0.0.1:8848
      namespace:
      group: SEATA_GROUP
      username: nacos
      password: nacos
      context-path:
      ##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
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace:
      cluster: default
      username: nacos
      password: nacos
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:    
  store:
    # support: file 、 db 、 redis
    mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
      user: root
      password: 123456
      min-conn: 10
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 1000
      max-wait: 5000
#  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,/**/*.jpeg,/**/*.ico,/api/v1/auth/login

mysql5.7 使用 com.mysql.jdbc.Driver

Mysql8.0 使用 com.mysql.cj.jdbc.Driver

image

③修改 config.txt

修改 seata 解压目录的script/config-center下的 config.txt 文件。这里的内容都是 key-value,将来都是作为 nacos 配置中心中的数据出现的,将来打开 nacos 可以根据其 key 逐条查看到

image

修改存储模式

指定这里要使用的存储模式为 db

store.modestore.lock.modestore.session.mode 中原来的 file 值修改为 db。再将公钥行注释掉。

image

修改db的连接四要素
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.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

image

删除其它存储模式配置

由于这里指定的存储模式是db,所以需要将file模式与redis模式相关的配置全部删除。

image

定义seataServer.properties

在 Nacos 配置中心定义 seataServer.properties 文件。该文件是在上述 application.yml 中指定的 data-id 文件。将前面修改后的 config.txt 文件内容全部复制到 seataServer.properties文件中。

#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.cj.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

image

④启动 Seata-server

运行命令

在 seata 解压目录下的 bin 目录中有个文件seata-server.sh,在命令行运行这个批处理文件

./seata-server.sh -m db

image

⑤查看 nacos

在 nacos 中可以看到 seata-server 的服务时,表示 seata 启动成功了。

image

⑥seata web界面

端口默认7091、账号密码:seata

image