我是靠谱客的博主 默默咖啡,最近开发中收集的这篇文章主要介绍Spring项目整合 Seata分布式事务解决方案,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

    • 版本说明
    • Seata术语
    • 配置Seata服务端(TC)
      • 配置Seata服务端(TC)数据源
      • Docker安装Seata服务端(TC)
    • 配置Seata客户端(TM和RM)
    • 注意事项
    • 其它知识

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

版本说明

  • Seata 1.5.1 (1.4.2版本会有时间序列化问题,网上有一些解决方案,试了但是没能解决,建议直接用1.5.0+版本)
  • nacos 1.4.3
  • SpringBoot 2.6.3
  • java 1.8
  • mysql 8.0+

Seata术语

Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。

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

配置Seata服务端(TC)

配置Seata服务端(TC)数据源

  • 数据库脚本 (包含 lock_table、branch_table 与 global_tabledian 、distributed_lock) ,注意:distributed_lock表是1.5.0+版本新加的。
  • 数据库建表语句:https://github.com/seata/seata/tree/1.5.0/script/server/db
  • 使用sql建表脚本创建服务端数据源,下面的服务端的application.yml配置文件中需要配置数据源的数据库相关信息。

Docker安装Seata服务端(TC)

  • 拉取指定版本的seata-server镜像并运行
docker run --name seata-server -p 8091:8091 -p 7091:7091 seataio/seata-server:1.5.1
  • 将resources目录文件拷出的临时容器
# docker cp seata-serve:/seata-server/resources  /User/seata/config
docker cp seata-serve:/seata-server/resources  [服务器本地存放配置文件地址]
  • 拷出后,修改application.yml,然后有以下两种解决方案:

    • A:可以选择修改application.ymldocker cp [服务器本地存放配置文件地址] seata-serve:/seata-server/resources进容器,然后重器Seata容器 docker restart [容器名/容器ID]
    • B: 可以删除docker rm 容器名/容器ID 刚刚创建的容器,重新创建,并做好映射路径设置。
    docker run --name seata-server 
            -p 8091:8091 
            -p 7091:7091 
            -v [服务器本地存放配置文件地址]:/seata-server/resources  
            seataio/seata-server
    
  • Seata 注册中心和配置中心配置支持 file,nacos, consul, apollo, zk, etcd3 等,可以参考从容器拷贝下来的 application.example.yml 官方yaml配置文档,下面是配置nacos的application.yml参考:

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata

console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
       #  配置中心的地址
       server-addr: ip地址:8848
       namespace:
       group: SEATA_GROUP
       username: nacos
       password: nacos
       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: ip地址:8848
       namespace:
       group: SEATA_GROUP
       username: nacos
       password: nacos
       cluster: default
  store:
    # support: file 、 db 、 redis
    mode: db
    session:
      mode: db
    lock:
      mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver  # Mysql5.6+ 用 com.mysql.jdbc.Driver 驱动
      url: jdbc:mysql://ip地址:3306/seata?useUnicode=true&rewriteBatchedStatements=true
      username: 数据库用户名
      password: 数据库密码
      min-conn: 5
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 100
      max-wait: 5000
  server:
    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
    max-commit-retry-timeout: -1
    max-rollback-retry-timeout: -1
    rollback-retry-timeout-unlock-enable: false
    enableCheckAuth: true
    retryDeadThreshold: 130000
    xaerNotaRetryTimeout: 60000
    recovery:
      handle-all-session-period: 1000
    undo:
      log-save-days: 7
      log-delete-period: 86400000
    session:
      branch-async-queue-size: 5000 #branch async remove queue size
      enable-branch-async-remove: false #enable to asynchronous remove branchSession
#  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
  metrics:
    enabled: false
    registry-type: compact
    exporter-list: prometheus
    exporter-prometheus-port: 9898
    transport:
      rpc-tc-request-timeout: 30000
      enable-tc-server-batch-send-response: false
      shutdown:
        wait: 3
      thread-factory:
        boss-thread-prefix: NettyBoss
        worker-thread-prefix: NettyServerNIOWorker
        boss-thread-size: 1
  • 至此,Seata服务端(TC)已经配置并启动成功并注册到nacos了。
  • 查看Seata启动日志:docker logs -f seata-server
    在这里插入图片描述
    在这里插入图片描述

配置Seata客户端(TM和RM)

  • 引入依赖(参与分布式事务的每个服务模块中都需要引入下面的依赖
 <!-- 分布式事务 -->
 <dependency>
      <groupId>io.seata</groupId>
      <artifactId>seata-spring-boot-starter</artifactId>
 </dependency>
  • undo_log建表、配置参数(仅AT模式)
    • https://github.com/seata/seata/blob/1.5.0/script/client/at/db/mysql.sql
    • 参与分布式事务的每个服务模块中的数据库都需要新建undo_log表
  • 添加yaml配置文件(参与分布式事务的每个服务模块中都需要引入下面的配置
# 分布式事务配置
seata:
  tx-service-group: my_test_tx_group
  service:
    vgroup-mapping:
      my_test_tx_group: default
  enable-auto-data-source-proxy: true
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: ip:端口号
      namespace:
      group: SEATA_GROUP
      username: nacos
      password: nacos
  config:
    type: nacos
    nacos:
      server-addr: ip:端口号  
      namespace:
      group: SEATA_GROUP
      username: nacos
      password: nacos
      dataId: seataServer.properties  # 这个名字需要和下面nacos中添加的配置文件名一样
  • nacos添加seataServer.properties配置文件(group:SEATA_GROUP,需要和服务端的配置文件中配置的group组一样)
#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.my_test_tx_group=default  # service.vgroupMapping.后缀 需要和服务端配置 seata:tx-service-group  一致
#If you use a registry, you can ignore it
service.default.grouplist=ip地址:8091  # Seata 服务端地址
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  # 存储模式 db
store.lock.mode=file
store.session.mode=file
#Used for password encryption
store.publicKey=

#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100

#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  # Mysql5.6+ 用 com.mysql.jdbc.Driver 驱动
store.db.url=jdbc:mysql://ip地址:3306/seata?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
store.db.user=数据库用户名
store.db.password=数据库密码
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

#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
store.redis.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100

#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

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
  • 业务使用,全局事务

    • 在需要开启全局事务的方法上加上注解 @GlobalTransactional
  • 启动全局事务对应的业务服务模块,seata服务端可以看到TM和RM的注册日志

在这里插入图片描述

注意事项

  • AT模式支持的数据库有:MySQL、Oracle、PostgreSQL、 TiDB、MariaDB。当全局事务中有其他数据库(例如:redis等)时,可以将redis等相关删除操作影响事务回滚后的下次执行时,将对应子事务放到全局事务最后面执行。

其它知识

Seata AT 模式

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

工作机制

  • 以一个示例来说明整个 AT 分支的工作过程。
    在这里插入图片描述
  • AT 分支事务的业务逻辑:
 update product set name = 'GTS' where name = 'TXC';

一阶段

  • 过程:

    • 1.解析 SQL:得到 SQL 的类型(UPDATE),表(product),条件(where name = ‘TXC’)等相关的信息。
    • 2.查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。
      select id, name, since from product where name = 'TXC';
      
    • 3.执行业务 SQL:更新这条记录的 name 为 ‘GTS’。
    • 4.查询后镜像:根据前镜像的结果,通过 主键 定位数据。
      select id, name, since from product where id = 1;
      
    • 5.插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到 UNDO_LOG 表中。
    {
    	"branchId": 641789253,
    	"undoItems": [{
    		"afterImage": {
    			"rows": [{
    				"fields": [{
    					"name": "id",
    					"type": 4,
    					"value": 1
    				}, {
    					"name": "name",
    					"type": 12,
    					"value": "GTS"
    				}, {
    					"name": "since",
    					"type": 12,
    					"value": "2014"
    				}]
    			}],
    			"tableName": "product"
    		},
    		"beforeImage": {
    			"rows": [{
    				"fields": [{
    					"name": "id",
    					"type": 4,
    					"value": 1
    				}, {
    					"name": "name",
    					"type": 12,
    					"value": "TXC"
    				}, {
    					"name": "since",
    					"type": 12,
    					"value": "2014"
    				}]
    			}],
    			"tableName": "product"
    		},
    		"sqlType": "UPDATE"
    	}],
    	"xid": "xid:xxx"
    }
    
    • 6.提交前,向 TC 注册分支:申请 product 表中,主键值等于 1 的记录的 全局锁 。
    • 7.本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
    • 8.将本地事务提交的结果上报给 TC。

二阶段-回滚

  • 收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
  • 通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
  • 数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需
  • 根据配置策略来做处理,详细的说明在另外的文档中介绍。
  • 根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
    update product set name = 'TXC' where id = 1;
    
  • 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。

二阶段-提交

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

参考:https://seata.io/zh-cn/

你知道的越多,你不知道的越多。

最后

以上就是默默咖啡为你收集整理的Spring项目整合 Seata分布式事务解决方案的全部内容,希望文章能够帮你解决Spring项目整合 Seata分布式事务解决方案所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部