天天看點

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

背景:現有項目為springcloud+nacos 的。但是沒有分布式事務處理機制,偶發資料問題,現需要引入seata進行全局事務管理。簡單記錄一下改造和學習過程,過一段時間自己100%會忘的一幹二淨,并沒有對其進行很深的研究。

前期準備工作:

seata的模式介紹之類的,可以參考大佬的文章或者官網

https://wu55555.blog.csdn.net/article/details/124535548

seata官網:Seata 快速開始

官網現成samples,拿來直接能用的: GitHub - seata/seata-samples: seata-samples

服務下載下傳位址:Releases · seata/seata · GitHub

我一開始就就是拿着官網案例裡面的 springcloud-nacos-seata,直接本地運作起來,觀察了一下具體的資料庫變化之類的。

改造過程:

        官網案例畢竟比較簡單也不适用生産環境,需要改造一下。畢竟現有項目已經運作一年多了,直接使用AT模式,簡單快速。

        以1.4.2為例,目前最新為(1.6.0),大緻參數都差不多,隻是配置檔案的形式有所差別。具體有什麼優缺點并沒有去仔細了解過。

一:seata服務端 修改conf下的registry.conf檔案

        因為使用的nacos為配置中心,file.conf檔案可以直接無視,最開始接觸seata的時候看了很多很多的文章,明明用的nacos為配置中心,确非要引導讀者去改fiel.conf裡面的mode = "db",這壓根沒用好吧,一堆的坑。還有類似tx-service-group的問題也是一樣。隻有當配置裡面用用fle的時候,改file.conf才會有效!!!

        如果需要使用file為配置中心,那個config下面的type請改成 type="file",此時seataserver啟動的時候才會去讀conf檔案下面的file.conf。

registry.conf如下,基本修改nacos就行

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
	application = "seata-server"
	group = "SEATA_GROUP"
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    cluster = "default"
	username = "nacos"
    password = "nacos"
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = 0
    password = ""
    cluster = "default"
    timeout = 0
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
    aclToken = ""
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}

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

  nacos {
	application = "seata-server"
	group = "SEATA_GROUP"
    serverAddr = "127.0.0.1:8848"
    namespace = "24b8ffe7-7061-47b6-a2ef-4b860fd23b7f"
    cluster = "default"
	username = "nacos"
    password = "nacos"
  }
  consul {
    serverAddr = "127.0.0.1:8500"
    aclToken = ""
  }
  apollo {
    appId = "seata-server"
    ## apolloConfigService will cover apolloMeta
    apolloMeta = "http://192.168.1.204:8801"
    apolloConfigService = "http://192.168.1.204:8080"
    namespace = "application"
    apolloAccesskeySecret = ""
    cluster = "seata"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
    nodePath = "/seata/seata.properties"
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}
           

二、把seata的參數配置上傳到nacos

        因為使用nacos為配置中心,那麼你得告訴nacos,你需要怎麼配置。

1、啟動nacos,建立一個命名空間,存放seata的各項配置,我這邊名稱就是seata。命名空間id後續第3步要用到。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

 2、在下載下傳下來的服務端裡面,找到script\config-center\config.txt文檔。如果沒有,可以直接去官網找:seata/config.txt at 1.4.2 · seata/seata · GitHub

然後修改裡面的配置,主要改動為mysql的相關配置和vgroupMapping的相關配置。當然,你也可以不改,後續去nacos上改。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 
現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

具體配置如下

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
#修改service.vgroupMapping.後面的字元串為自定義服務seata-group
service.vgroupMapping.seata_demo_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=root
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
           

3、在script\config-center\nacos檔案夾下面,找到上傳腳本 nacos-config.sh,執行命名,上傳配置,注意需要把下面 命名空間ID替換成你自己的,就是之前咱們第一步新增的時候生成的。

sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 命名空間ID -u nacos -w nacos
           

Windows下可以直接使用git 的 git Bash Here功能,也可以使用别的工具。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

如果出現以下情況,則是沒有按第2步的時候放好,config.txt檔案,按提示的目錄,挪過去就行。其實上傳腳本和config.txt的位置随意調整都行,也可以自己去nacos-config.sh修改具體指向config.txt的路徑,隻要能上傳就好。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 
現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

上傳成功如下

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

同時nacos中也能看到所有的配置項。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

後續要改配置都可以直接去nacos裡面調整,友善快捷。例如,我本地資料庫密碼我從root改成了mysql,直接去nacos裡配置清單seata下面,找到store.db.password這一項,編輯在釋出就可以了。

4、調整各個client服務子產品

        首先引入依賴,seata-spring-boot-starter不能在spring-cloud-starter-alibaba-seata之前。否則會出現feign調用的時候,事務不會滾的情況。大緻使用因為feign調用是需要傳遞一個xid,傳遞xid的功能是隻在spring-cloud-starter-alibaba-seata才有,seata-spring-boot-starter是沒有傳遞xid的功能,會導緻被調用的服務擷取不到xid,進而無法觸發事務復原。

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
	<version>${spring-cloud-alibaba.version}</version>
	<exclusions>
		<exclusion>
			<groupId>io.seata</groupId>
			<artifactId>seata-spring-boot-starter</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>io.seata</groupId>
	<artifactId>seata-spring-boot-starter</artifactId>
	<version>1.4.2</version>
</dependency>        
           

然後配置檔案裡面添加,如下配置。

nacos相關位址資訊改成自己的就可以了,需要注意的是tx-service-group和vgroup-mapping這兩項,需要和你nacos裡面配置的保持一緻。否則RM和TM都沒法注冊到seata裡面去。

application.yml添加seata相關配置

seata:
  tx-service-group: seata_demo_group
  registry:
    type: nacos
    nacos:
      server-addr: ${spring.cloud.nacos.discovery.server-addr}
      username: ${spring.cloud.nacos.discovery.username}
      password: ${spring.cloud.nacos.discovery.password}
      group: ${spring.cloud.nacos.discovery.group}
  config:
    type: nacos
    nacos:
      server-addr: ${spring.cloud.nacos.config.server-addr}
      username: ${spring.cloud.nacos.config.username}
      password: ${spring.cloud.nacos.config.password}
      group: ${spring.cloud.nacos.config.group}
      namespace: 24b8ffe7-7061-47b6-a2ef-4b860fd23b7f
      dataId: seata-server.properties
  service:
    vgroup-mapping:
      seata_demo_group: default
           

可以去nacos查詢vgroupMapping關鍵字。如果不配置這個的話,低版本的seata預設是my_test_tx_group,高版本的是default_tx_group,對應的值都是default。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

這個地方如果配置不對或者對應不上,那麼各個client伺服器啟動都會彈出的

can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

例如這樣的 

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

 5、建立seata 事務相關表

        因為我這邊nacos中store.mode使用的是db模式,且用的是mysql資料庫,那麼就得建立 具體的表。建表語句可以在script\server\db下面找到。也可以去官網的github上找。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

這裡copy一下mysql的。

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
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;

-- the table to store BranchSession data
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;

-- the table to store lock data
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;
           

 因為需要使用AT模式,那麼得在每個子產品服務下的資料庫裡面添加undo_log表,具體sql如下

CREATE TABLE `undo_log`
(
  `id`            BIGINT(20)   NOT NULL AUTO_INCREMENT,
  `branch_id`     BIGINT(20)   NOT NULL,
  `xid`           VARCHAR(100) NOT NULL,
  `context`       VARCHAR(128) NOT NULL,
  `rollback_info` LONGBLOB     NOT NULL,
  `log_status`    INT(11)      NOT NULL,
  `log_created`   DATETIME     NOT NULL,
  `log_modified`  DATETIME     NOT NULL,
  `ext`           VARCHAR(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8;
           

6、啟動seata服務,其他其他子產品服務、測試

        seata啟動的時候,預設會先去找registry.conf裡面的配置,然後再去找具體的file、nacos、eureka、redis之類的,具體看每個人咋配置的。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

各個子產品啟動成功後,在seataserver日志中可以看到TM和RM的注冊資訊,各個子產品服務也有日志。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

在需要添加分布式事務的地方加上注解 @GlobalTransactional

測試前stock_tbl表資料如下

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

然後調用接口,自己斷點調試就能發現,此時stock服務的deduct已經執行完成了

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

資料庫已經發生修改。

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

undo_log會有記錄

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

global_table等也會有記錄

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

如果用的不是db而是file模式的話,可以直接去seata服務bin目錄下去找相關全局事務記錄資訊(預設配置的前提下)

當抛出異常後,會發生復原,在seataserver日志中可以看到如下資訊

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

同時原來被修改的資料會發生復原

現有項目內建seata的記錄can not get cluster name in registry config ‘service.vgroupMapping.XXX‘ 

        以上全部為官網demo改造而成,基于1.4.2,目前實際環境用的是seata 1.6.0。大緻差異為1.6.0的配置檔案是個application.yml檔案,基本配置都差不多。具體細節和差異性也沒有去了解過,感興趣的可以取官網檢視。

可能遇到的問題

        子產品服務啟動報錯can not get cluster name in registry config ‘service.vgroupMapping.XXX‘時,請檢查子產品服務的配置是否和注冊中心的配置一樣。參考上面第4點。

        配置成功,能啟動,子產品服務能注冊seata,但是不生效。遇到異常不會復原,可以參考第4點。是否依賴的問題或者xid為空的以及調用方和被調用方的xid是否一緻等。

        能復原,但是global_table、branch_table、lock_table沒有任何資料變化,首先檢查registry.conf裡面config下的typ用的是啥,再到對應的配置下面去檢查store.mode是不是db模式,以及資料庫的配置資訊了,隻要有一項不對,就這幾個表就不會有任何變化。例如registry.conf下的config使用nacos的話就要去nacos的配置中心去檢查,使用file的話就得去file.conf檔案去檢查配置資訊、其他的也是類似的。

        其他的問題可以參考官網Seata常見問題

繼續閱讀