基于seata官网示例改造的最新版本 Spring Cloud Alibaba + OpenFeign + Druid + Seata 分布式事务演练

本项目案例基于seata官网快速开始示例改造。官方展示的是Dubbo + SEATA提供支持的示例,本人基于此示例整合Spring Cloud Alibaba + OpenFeign + Druid + Seata 。

环境准备

本案例版本是 Spring Cloud Alibaba 2.2.1.RELEASE + Spring Boot 2.2.2 RELEASE

  1. 下载nacos,用于微服务的注册和配置中心。seata是一个分布式事务服务,可以把seata服务注册到nacos,seata的配置参数,可以保持在nacos上。
  2. 下载seata-server-1.4.0。seata-server其实就是TC(分布式事务协调器)
  3. 初始化sql语句,并下载项目。源码地址 https://gitee.com/brozer/alibaba-seata-samples

seata

seata 是什么

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

seata 特色功能

  • 微服务框架支持
    目前已支持 Dubbo、Spring Cloud、Sofa-RPC、Motan 和 grpc 等RPC框架,其他框架持续集成中
  • AT模式
    提供无侵入自动补偿的事务模式,目前已支持 MySQL、 Oracle 、PostgreSQL和 TiDB的AT模式,H2 开发中
  • TCC模式
    支持 TCC 模式并可与 AT 混用,灵活度更高
  • SAGA 模式
    为长事务提供有效的解决方案
  • XA 模式
    支持已实现 XA 接口的数据库的 XA 模式
  • 高可用
    支持基于数据库存储的集群模式,水平扩展能力强

快速开始

用例

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:

  1. 仓储服务:对给定的商品扣除仓储数量。
  2. 订单服务:根据采购需求创建订单。
  3. 帐户服务:从用户帐户中扣除余额。

架构图

在这里插入图片描述

项目模块

本案例是个maven聚合工程,总共有5个模块。

  1. samples-common-service 公共依赖服务。定义了一些公共基础类和OpenFeign接口定义。
  2. samples-account-service 账户服务。账号服务提供者
  3. samples-business-service 业务服务。用于接受用户请求,处理业务逻辑。微服务消费者。
  4. samples-order-service 订单服务。根据采购需求创建订单。订单服务提供者,账号服务消费者。
  5. samples-storage-service 存储服务。给指定商品扣除仓储数量。存储服务提供者。

在这里插入图片描述

安装seata

解压seata-server-1.4.rar

修改注册中心配置文件 /seata/conf/reigstry.conf

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"
  loadBalance = "RandomLoadBalance"
  loadBalanceVirtualNodes = 10

  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
 
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

修改seata-server 事务日志配置 seata/conf/file.conf。sql脚本在项目的doc文件seata.sql

## transaction log store, only used in seata-server
store {
  ## store mode: file、db、redis
  mode = "db"

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true"
    user = "root"
    password = "123456"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

}

配置好后,启动seata-server服务。查看seata服务是否注册到Nacos了
在这里插入图片描述

添加seata配置参数到nacos

上一步骤启动只是验证seata-server是否注册到nacos中。由于我们的配置也保持在了nacos中,所以需要在nacos中添加seata的配置参数。为了避免一个个添加,官方为我们提供了config.txt(我拷贝到了seata/conf/config.txt) 配置文件和启动脚本nacos-config.sh(拷贝到了seata/conf/nacos/nacos-config.sh)。
我们需要修改config.txt

transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
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
#修改my_test_tx_group为自定义服务seata-group
service.vgroupMapping.seata-group=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
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=false
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=db
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
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?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=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.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
store.redis.host=127.0.0.1
store.redis.port=6379
store.redis.maxConn=10
store.redis.minConn=1
store.redis.database=0
store.redis.password=null
store.redis.queryLimit=100
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
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.log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

配置参数service.vgroupMapping.seata-group=default的seata-group需要和项目的 seata.tx-service-group一致。seata-server事务存储我们保持到mysql。

执行启动脚本nacos-config.sh。

./nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -u nacos -w nacos 

至此,您可以在nacos配置列表中看到seata的配置参数了。如下图所示
在这里插入图片描述

启动

  1. 启动nacos服务。
  2. 启动seata-server
  3. 下载源码后,依次启动 samples-account-service、samples-order-service、samples-storage-service、samples-business-service服务。

启动看到如下图所示,则表示微服务的数据源已被seata代理,微服务已经连上seata服务了。
在这里插入图片描述

测试案例

在这里插入图片描述请求链接因为项目是基于官网示例,没有改。哈哈~
第一个接口是正常请求的,发现数据库生成了相关记录。
第二个接口时测试异常的流程,事务回滚了,参与的事务分支在第二阶段执行回滚操作。

遇到一些坑

版本依赖过低

因为使用版本过低,报:no available service ‘default’ found, please make sure registry config correct 错误。
这个错误信息困扰我一个晚上了,最后看了源码,发现源码的配置参数少了很多,于是怀疑是否版本太旧不支持。果真换了版本就可以了。
seata-spring-boot-starter 默认采用的是1.1.0,需要替换成1.4.0。项目maven pom.xml文件如下:

 <!--alibaba seata start-->
        <dependency>
            <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-seata -->
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>
        <!--alibaba seata end-->

        <dependency>
            <groupId>com.example.cloud.alibaba</groupId>
            <artifactId>common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.4.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>asm</artifactId>
                    <groupId>org.ow2.asm</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>8.0.1</version>
        </dependency>

项目中使用druid 自动配置依赖

使用druid-spring-boot-starter配置,会导致报错 xxx …com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper$$Enhancer

 <dependency>
	 <groupId>com.alibaba</groupId>
     <artifactId>druid-spring-boot-starter</artifactId>
 </dependency>

解决方法:去掉依赖,然后自己在项目配置druid参数配置。配置成功如下图所示
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Lixuanshengchao/article/details/113092873