seata集群部署与踩坑集合之秃头篇-持续优化

  1. 开启seata事务的工程中引入相关依赖
    在父工程pom.xml中引入seata的jar包,如果使用1.4.2的版本,需要排除默认引入的1.3的包。

    com.alibaba.cloud
    spring-cloud-starter-alibaba-seata
    
        
        
            io.seata
            seata-spring-boot-starter
        
    



    io.seata
    seata-spring-boot-starter
    ${seata.version}

关于spring cloud alibaba生态的版本参考地址
如果使用1.3.0的版本则可以在子项目引入

        
            io.seata
            seata-spring-boot-starter
        

⚠️⚠️⚠️如果使用此依赖,将会出现 服务A->B,B报错,A事务回滚,但是B事务不会回滚,因为此依赖在请求传递中header不会携带xid。
建议直接使用

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-seata
            2021.1
        
  1. seata server服务器搭建
    github下载地址
    下载1.3.0版本,本文以1.3.0版本为例。seata-server-1.3.0.tar.zip上传至服务器进行解压、配置。
    1. 修改seata/conf/file.conf文件
      此配置项为seata 服务器的存储配置,存储方式选择db,再配置数据库的连接信息,以及处理事务的全局性表(表名使用默认的就可以)。
store {
  mode = "db"
  db {
    datasource = "druid"
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://172.31.215.70:3306/seata"
    user = "root"
    password = "123456"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

⚠️注意
driverClassName驱动的配置需要根据mysql的版本决定:
mysql5.+使用 driverClassName = "com.mysql.jdbc.Driver"
mysql8使用 driverClassName = "com.mysql.cj.jdbc.Driver"

    1. 修改seata/conf/registry.conf文件
      需要配置选用的注册中心类型(nacos),注册中心的连接信息;配置中心的类型,配置中心的连接信息。
registry {
  type = "nacos"
  nacos {
    application = "seata-server"
    serverAddr = "172.31.215.72:8848"
    group = "SEATA_GROUP"
    namespace = "787964a5-e21d-4eb8-9999-9bcc9244bd48"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}

config {
  type = "nacos"
  nacos {
    serverAddr = "172.31.215.72:8848"
    namespace = "787964a5-e21d-4eb8-9999-9bcc9244bd48"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

⚠️注意
namespace :生产环境和项目中保持一致
group: 和项目中保持一致
serverAddr: nacos连接地址,如果是内网,请保证服务器之前内网互通并打开端口防火墙
项目中的group如果不是用的最新nacos最好不要配置,默认就行

    1. script/config-center/config.txt配置文件
      此配置信息是seata事务的相关属性
      下载seata源码 选择对应版本,将script/config-center/ 下的文件 config.txt 上传服务器中 seata/下,上传script/config-center/nacos/下的nacos-config.sh文件到服务器seata/conf/下。
      放哪都一样,但是config.txt文件要在nacos-config.sh文件的上一级目录。

为nacos-config.sh文件赋予执行权限

chmod +x 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
# 自己命名一个vgroupMapping,my_test_tx_group为自定义,怕出错可默认不修改
service.vgroupMapping.my_test_tx_group=default
service.default.grouplist=172.31.215.71: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.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
#model改为db
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.jdbc.Driver
# 改为上面创建的seata服务数据库
store.db.url=jdbc:mysql://172.31.215.70:3306/seata?useUnicode=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.my_test_tx_group=default
    中的my_test_tx_group需要与bootstrap.yml或者application.yml中配置的seata.tx-service-group的值一致。
  • service.vgroupMapping.my_test_tx_group=default
    配置的default必须要等于registry.conf中配置的cluster="default"。
  • store.mode=db配置为db的方式,则需要配置db数据库方式的连接信息
    store.db.url、store.db.user、store.db.password,此数据库存储下存放的表
    global_table、branch_table、lock_table,用于记录全局性的事务信息
  • store.db.driverClassName的配置
    mysql5.+使用 driverClassName = "com.mysql.jdbc.Driver"
    mysql8使用 driverClassName = "com.mysql.cj.jdbc.Driver"
  • service.default.grouplist=ip:port为访问seata服务器的地址和端口(仅注册中心为file时使用),8091是默认端口,
    也可以修改启动端口,在启动项目时加上端口:
    seata-server.bat -p 8091
    ./seata-server.sh -p 8091
  • seata server需要配置集群时,只需要在启动seata server服务时指定不同的端口和节点序号即可,配置file.conf和registry.conf的内容一致。一般在生产环境中每一个seata服务放不同的服务器中,其余保持一致。
    每个服务的seata启动一致
    ./seata-server.sh -p 8091 -n 1
    1. 执行上传命令
      将config.txt配置上传至nacos,执行nacos-config.sh文件
./nacos-config.sh -h localhost -p 8848 -t 787964a5-e21d-4eb8-9999-9bcc9244bd48 -u nacos -w nacos

-h localhost :访问nacos的ip地址
-p 8848 :nacos的端口号
-t 787964a5-e21d-4eb8-9999-9bcc9244bd48 :namespace命令空间

查看nacos配置列表是否成功。

⚠️注意
如果nacos-config.sh文件下载的是1.4.2版本的,那么执行将会报语法错误,建议使用1.3.2版本的nacos-config.sh

    1. 启动nacos
./seata-server.sh -p 8091 -n 1
  1. 创建需要的事务表
    global_table:全局事务表
    branch_table:分支信息表
    lock_table:加锁的表
    以上三个表需要创建在seata服务器操作的db上,即file.conf中配置的数据库。
--全局事务表--
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
-- 分支表
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
-- 锁定表
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
--seata新版本加的锁表
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    PRIMARY KEY (`lock_key`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8mb4;
 
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

也可在源码 script/server/db/下找到mysql.sql直接在seata数据库执行。

undo_log:回滚日志表
在每个需要开启seata事务操作的数据库下都需要建立此表。

--日志文件表--
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
    ) ENGINE = INNODB
    AUTO_INCREMENT = 1
    DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

⚠️注意
seata1.4.2之后,需要回滚的表日期类型不能使用datetime,可以使用timestamp

  1. 客服端配置
    需要开启seata事务的客户端,需要配置seata的注册和配置中心,使用相关注解进行事务开启。
  • application.yml
seata:
  enabled: true
  enable-auto-data-source-proxy: true #是否开启数据源自动代理,默认为true
  tx-service-group: my_test_tx_group #要与配置文件中的vgroupMapping一致
  service:
    vgroup-mapping:
      my_test_tx_group: default
  registry:  #registry根据seata服务端的registry配置
    type: nacos #默认为file
    nacos:
      application: seata-server #配置自己的seata服务
      cluster: default # 配置自己的seata服务cluster, 默认为 default
      group: SEATA_GROUP #根据自己的seata服务配置
      server-addr: 127.0.0.1:8848 #根据自己的seata服务配置
      namespace: 787964a5-e21d-4eb8-9999-9bcc9244bd48 #根据自己的seata服务配置
      username: nacos #根据自己的seata服务配置
      password: nacos #根据自己的seata服务配置
  config:
    type: nacos #默认file,如果使用file不配置下面的nacos,直接配置seata.service
    nacos:
      group: SEATA_GROUP #配置自己的dev
      server-addr: 127.0.0.1:8848 #配置自己的nacos地址
      namespace: 787964a5-e21d-4eb8-9999-9bcc9244bd48  #配置自己的namespace
      username: nacos #配置自己的username
      password: nacos #配置自己的password
  • spring boot 启动程序添加数据自动代理
    使用注解:@EnableAutoDataSourceProxy
@EnableAutoDataSourceProxy
@EnableDiscoveryClient
@SpringBootApplication
public class UmappCloudServiceAppcenterApplication {
    public static void main(String[] args) {
        SpringApplication.run(UmappCloudServiceAppcenterApplication.class, args);
    }
}

-使用注解开启事务

    @GlobalLock
    @GlobalTransactional
    public void deleteMusicScore(String musicScoreId) {
    }

⚠️⚠️⚠️注意⚠️⚠️⚠️
启动项目报错

seata :no available service ‘null‘ found, please make sure registry config correct

请检查

seata:
 tx-service-group: my_test_tx_group #要与配置文件中的vgroupMapping一致
 service:
   vgroup-mapping:
     my_test_tx_group: default

配置是否同seata服务配置一致。
seata.registry.nacos.group
seata.config.nacos.group
是否通seata服务配置一致。

can not register RM,err:can not connect to services-server.

如果在本地启动项目,seata又部署在服务器,那么请检查,在服务启动nacos的是否是否以内网启动
改成外网启动即可,但是会造成线上项目无法连接seata,所以有条件的话在测试服重新搭建seata

./seata-server.sh -p 8091 -h 127.0.0.1

NacosException: failed to req API

这个原因是Nacos重启后微服务项目启动时出现
有时候重启Nacos(大多数情况下是因为重启了机器),再启动微服务项目的服务时,后端控制台会出现NacosException: failed to req API异常。
解决办法: 现有两种解决可供参考:
一、如果未做过特殊配置,直接删除(或重命名)protocol文件夹即可
protocol文件夹在安装目录的下列位置:

...\nacos-server-1.3.0\data\

二、如果有特殊配置,修改文件raft_meta、__raft_snapshot_meta中的IP
raft_meta和__raft_snapshot_meta位置如下:

...\nacos-server-1.4.0\data\protocol\raft\naming_persistent_service\meta-data
...\nacos-server-1.4.0\data\protocol\raft\naming_persistent_service\snapshot\snapshot_7(此处可能不是_7,视具体情况而定)

注意: IP要修改为Nacos所在机器的当前IP。

项目中可能会出现的问题

⚠️⚠️⚠️

  1. seata事务不回滚?
  • 检查依赖包是否引入正确?
  • 分支事务库有没有undo_log表?
  • 分支事务服务有没有引入Seata?
  • 分支事务通过Feign接口调用,Feign接口处理了异常,导致主事务没有捕获到异常,导致事务无法回滚?
  • 通过 RootContext.getXID() 打印每个服务的xid是否一致?
  • enable-auto-data-source-proxy: true #是否开启数据源自动代理,默认为true ?
  • 每个服务日志是否会显示 register RM success ?
  1. B服务多次执行?
    feign使用get请求,请求超时会重新请求,默认五次,post只会用一次。

参考文档
seata整合nacos完成分布式的部署
分布式事务seata1.4.2使用配置
Nacos重启后微服务项目启动时后端出现NacosException: failed to req API异常解决办法

愿广大水友珍重,不掉发。

你可能感兴趣的:(seata集群部署与踩坑集合之秃头篇-持续优化)