Seata 配置错误排查
생성일: 2024년 12월 31일
생성일: 2024년 12월 31일
我在使用seata配置时报错
2024-12-31 12:46:25.285 INFO 17064 --- [nio-8088-exec-1] io.seata.tm.TransactionManagerHolder : TransactionManager Singleton io.seata.tm.DefaultTransactionManager@50937c39
io.seata.common.exception.FrameworkException: No available service
seata服务端的配置:
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${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:
type: nacos #使用nacos作为配置中心
nacos:
server-addr: http://192.168.28.32:8848
namespace: public #命名空间配置
group: DEFAULT_GROUP #分组信息配置
username: nacos #如果开启了nacos的验证功能则需要配置
password: nacos
data-id: seataServer.properties #nacos中的配置文件名称
registry:
type: nacos #使用nacos作为注册中心
nacos:
application: seata-server
server-addr: http://192.168.28.32:8848
group: DEFAULT_GROUP
namespace: public
cluster: seatatest #此处注意,这的值要和nacos中的配置文件service.vgroupMapping.my_test_tx_group的值一样
username: nacos
password: nacos
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,//*.css,//.js,/**/.html,//*.map,//.svg,/**/.png,//*.ico,/console-fe/public/,/api/v1/auth/login
使用了nacos作为配置注册中心,其中配置中心的配置:
#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=seatatest
#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=
#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
#此处注意驱动版本mysql8后是需要加cj
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://192.168.28.28:3305/seata?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
store.db.user=admin
store.db.password=NWT@temp123
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
springboot客户端的配置:
seata:
enabled: true
application-id: seata-server
enable-auto-data-source-proxy: false
tx-service-group: seatatest
service:
vgroup-mapping:
seatatest: default
group-list:
default: 192.168.28.28:8091 # 你的 Seata TC 服务器地址
disable-global-transaction: false
config:
type: nacos
nacos:
namespace: test-prod
server-addr: 192.168.28.32:8848
username: nacos
password: nacos
group: SEATA_GROUP
data-id: seataServer.properties
registry:
type: nacos
nacos:
application: seata-server # tc服务在nacos中的服务名称
cluster: seatatest
server-addr: 192.168.28.32:8848
group: SEATA_GROUP
namespace: test-prod
username: nacos
password: nacos
帮我优化修改这些配置
下面这类 No available service
的报错,通常代表 Seata 客户端找不到可用的 Seata Server 服务。
这往往是由于 Seata Server 与 Seata Client 的配置不一致(比如:注册中心、命名空间、分组、vgroupMapping、端口等等)导致的。
Seata Server 启动端口与 Client 引用的端口是否一致?
server.port: 7091
,但 Client 却写了 192.168.28.28:8091
。Seata Server 与 Client 的 registry
(注册中心)配置是否一致?
nacos
;server-addr
是否相同;namespace
是否相同;group
是否相同;cluster
是否对应;username/password
是否相同。Seata Server 与 Client 的 config
(配置中心)配置是否一致?
nacos
;namespace
、group
、data-id
等必须一致。service.vgroupMapping.xxx
与 seata.tx-service-group=xxx
是否匹配?
seata.tx-service-group
设置成 seatatest
,那在 Seata Server 的配置中就需要有 service.vgroupMapping.seatatest=xxxx
(或类似映射)。nacos
的地址、命名空间、分组(group
)等参数保持一致。service.vgroupMapping.xxx
的键(xxx
)要和 Client 侧 seata.tx-service-group=xxx
保持相同。registry
),那么 Client 里就不一定要再写死 IP:PORT 到 service.group-list
;只要保证 cluster
和 Nacos 上面的服务实例一致即可。service.vgroupMapping.xxx=…
中的 grouplist
改成实际能访问到 Seata Server 的 IP:Port。下文给出一套示例可行配置,可根据自己网络环境、数据源等微调。
以下示例:
- 端口统一改为
8091
(因为很多示例里习惯用 8091),如果你坚持用 7091,那 Client 那边也要写7091
。- 使用
nacos
做注册中心和配置中心;namespace
改为test-prod
,group
改为SEATA_GROUP
;- Data ID 依旧是
seataServer.properties
;- vgroupMapping 的键改为
seatatest
,与 Client 侧保持一致;- 底层存储使用 DB,指向了 MySQL(示例中的 IP、端口、用户名请根据真实环境修改)。
application.yml
(Server 侧)yamlserver: port: 8091 spring: application: name: seata-server logging: config: classpath:logback-spring.xml file: path: ${user.home}/logs/seata console: user: username: seata password: seata seata: # -- 安全相关,可根据实际需要保留或修改 -- security: secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017 tokenValidityInMilliseconds: 1800000 ignore: urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login # -- 配置中心 -- config: type: nacos nacos: server-addr: 192.168.28.32:8848 # 与客户端保持一致 namespace: test-prod group: SEATA_GROUP username: nacos password: nacos data-id: seataServer.properties # -- 注册中心 -- registry: type: nacos nacos: application: seata-server server-addr: 192.168.28.32:8848 group: SEATA_GROUP namespace: test-prod cluster: seatatest # 一定要和 data-id 里的 seatatest 一致 username: nacos password: nacos
seataServer.properties
(Nacos 中的配置内容示例)在 Nacos 上新建(或编辑) Data ID = seataServer.properties
, Group = SEATA_GROUP
, Namespace = test-prod
,内容大致如下(可按需改动):
properties########## transport ########## 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 ########## service ########## # 注意:这里与 Client 侧的 tx-service-group 要对应 service.vgroupMapping.seatatest=seatatest service.default.grouplist=127.0.0.1:8091 service.enableDegrade=false service.disableGlobalTransaction=false ########## 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 client.undo.logTable=undo_log client.undo.compress.enable=true client.undo.compress.type=zip client.undo.compress.threshold=64k 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 ########## log ########## log.exceptionRate=100 ########## store ########## store.mode=db store.lock.mode=db store.session.mode=db # 数据源相关(示例为 MySQL) store.db.datasource=druid store.db.dbType=mysql store.db.driverClassName=com.mysql.cj.jdbc.Driver store.db.url=jdbc:mysql://192.168.28.28:3305/seata?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false store.db.user=admin store.db.password=NWT@temp123 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.lockTable=lock_table store.db.queryLimit=100 store.db.maxWait=5000 ########## 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 ########## metrics.enabled=false metrics.registryType=compact metrics.exporterList=prometheus metrics.exporterPrometheusPort=9898
这里最关键的是:
service.vgroupMapping.seatatest=seatatest
,用于和客户端的tx-service-group=seatatest
对应;service.default.grouplist=127.0.0.1:8091
仅在直连时才生效;如果走 Nacos 注册中心,可不用太关注这个值;store.db.url
、store.db.user
、store.db.password
等需换成真实数据库信息。
假设在 application.yml
中这么写(或 application.properties
做同样含义配置):
yamlseata: enabled: true application-id: seata-server # 注意这里要和 service.vgroupMapping.seatatest=xxx 对应 tx-service-group: seatatest enable-auto-data-source-proxy: false # 是否自动代理数据源,可按需调整 service: # 如果已经用 Nacos 注册中心,这里的 vgroup-mapping 可以简单对齐一下 vgroup-mapping: seatatest: seatatest disable-global-transaction: false # 如果你想强行直连,也可以这样写 # group-list: # seatatest: 192.168.28.28:8091 config: type: nacos nacos: # 与 Seata Server 一致 server-addr: 192.168.28.32:8848 namespace: test-prod group: SEATA_GROUP username: nacos password: nacos data-id: seataServer.properties registry: type: nacos nacos: application: seata-server cluster: seatatest server-addr: 192.168.28.32:8848 group: SEATA_GROUP namespace: test-prod username: nacos password: nacos
这样即可通过 Nacos 发现 Seata Server。
如果你确认不想通过 Nacos 服务发现,而是直连 Seata Server(假设 IP 是192.168.28.28
,端口是8091
),那么可以把yamlservice: vgroup-mapping: seatatest: default group-list: default: 192.168.28.28:8091
之类的注释打开,但要确保与服务端
service.vgroupMapping.seatatest=seatatest
的键值匹配。
service.vgroupMapping.xxx
中的 xxx
必须和 Client seata.tx-service-group=xxx
相同,否则客户端进来时不知道应该映射到哪个集群。group-list
;但要保证 cluster
、application
这些信息也一致,且 Seata Server 能够正常注册到 Nacos。service.vgroupMapping.xxx=default
+ service.default.grouplist=SeataServerIP:SeataServerPort
这种直连配法,且客户端对应 tx-service-group=xxx
+ service.vgroup-mapping.xxx=default
+ group-list.default=SeataServerIP:SeataServerPort
匹配上。经过以上调整后,一般就能避免 No available service
的问题了。若仍然出现类似错误,请重点检查:
这样基本就能让 Seata 正常跑起来。祝一切顺利!
seata不是有两个端口吗 一个是7091一个是8091 前者是控制台的访问端口 后者是服务的访问端口 我想两个端口都保留 怎么修改
在 Seata Server 中,通常会有 两个端口:
server.port
,例如 7091
。用于访问 Seata 的控制台(即前端界面)以及健康检查等常规 HTTP 请求。8091
。负责 Client <-> Server 之间的分布式事务通信。很多人一开始会误以为只有一个端口,但其实 Seata 默认就会开启 8091 作为 RPC 服务端口;而如果你用的是官方提供的 seata-server
(基于 Spring Boot 的),那它还会同时使用 server.port
(默认为 7091,或者其他端口)来提供控制台/管理接口。
如果你想 同时保留:
那么通常只需要:
在 Spring Boot 的 application.yml
(或 application.properties
)里指定:
yamlserver: port: 7091
这样,访问控制台就用 http://{ip}:7091。
在 Seata 的配置中心(或本地 file.conf
)里,配置 service.default.grouplist
、service.vgroupMapping.xxx
等时,指向的是 8091。
8091
端口 作为 Netty 服务器的监听端口(RPC 通信端口),无需额外手动配置也行。file.conf
/ nacos
的 seataServer.properties
)增加显式配置。但 大多数版本默认就是 8091。application.yml
示例yamlserver: port: 7091 # 用于控制台/管理的HTTP端口 spring: application: name: seata-server # 其他省略...
seataServer.properties
(或本地 file.conf)properties# 指定给客户端使用的RPC地址列表(直连模式才需要),或者只用来做默认值 service.vgroupMapping.default_tx_group=default service.default.grouplist=192.168.28.28:8091 # 其他参数,如 store.db.*、transport.* 等等...
注意:如果你启用了 Nacos 注册中心,那么客户端可能并不会真正使用
service.default.grouplist
中的8091
直连,而是通过 Nacos 服务发现到 8091。此时更要确保 Seata Server 已正确在 Nacos 中注册,且暴露的是 8091 端口。
某些场景下你想改掉默认的 8091,或者希望在配置文件中写明。Seata(从 1.x 到 1.6+)通常有两种方式:
registry.conf
或者 file.conf
里,通过 serverAddress
来显式指定。service.default.grouplist
或者 service.vgroupMapping.xxx
后面写上 IP:PORT
即可。如果是通过 Nacos/Eureka 等注册中心,则以它们注册的端口信息为准。目前在 官方最新版本中,大多数情况下只要你不修改 Netty 监听端口,就会默认启用 8091
。如果确实要改,你可以在 transport
相关配置块里手动加入(注意版本差异),例如:
propertiestransport.server-port=9999
然后再把 service.default.grouplist=127.0.0.1:9999
这种对应上。
在 Client 侧(Spring Boot 工程)只要有下面类似配置,就能连到 8091:
yamlseata: # 对应 Seata Server 中 service.vgroupMapping.xxx 的 xxx tx-service-group: default_tx_group # 如果不走注册中心,而是直接写死IP:PORT service: vgroup-mapping: default_tx_group: default group-list: default: 192.168.28.28:8091
或是通过 Nacos 注册中心发现 8091,则只需要保证:
seata.registry.type=nacos
并配置了同一个 namespace
, group
, cluster
等service.vgroupMapping.xxx
一致server.port=7091
:启动 Seata Server 的控制台端口,HTTP 服务跑在 7091。8091
:用于分布式事务通信。application.yml
里设置 server.port=7091
,并且在 Seata 配置中心或本地 service.vgroupMapping.*
配置中指向 8091
,即可实现前者访问控制台、后者处理事务。这样便能同时保留 7091(供浏览器访问控制台)和 8091(供应用进行分布式事务交互)两条通道。
详细帮我输出 分三个配置来
下面给出 三份配置示例,以便 同时保留:
7091
8091
其中示例中使用了 Nacos 作为注册中心与配置中心。请根据你自己的 IP、端口、数据库、Nacos namespace 等进行适当修改。
application.yml
)在 Seata 官方的 seata-server
工程里,或者你自己打包的 Seata Server Spring Boot 应用中,修改 application.yml
:
yamlserver: # 这个端口用于 Seata Server 的控制台(HTTP 管理端口) port: 7091 spring: application: name: seata-server logging: file: path: ${user.home}/logs/seata # 如果有自己的 logback 配置,可以在这儿指定 config: classpath:logback-spring.xml # Seata 核心配置: 让它去读 Nacos 上的 data-id = "seataServer.properties" seata: # 配置中心 config: type: nacos nacos: server-addr: 192.168.28.32:8848 namespace: test-prod group: SEATA_GROUP username: nacos password: nacos data-id: seataServer.properties # 注册中心 registry: type: nacos nacos: application: seata-server server-addr: 192.168.28.32:8848 namespace: test-prod group: SEATA_GROUP cluster: seatatest username: nacos password: nacos # 控制台登录(可选) security: secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017 tokenValidityInMilliseconds: 1800000 ignore: urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login console: user: username: seata password: seata
说明:
server.port=7091
:此端口仅用于 HTTP 控制台访问。- Netty RPC 端口默认是
8091
(Seata 内部会自动使用 8091 进行事务协调)。如果想改成别的,比如9991
,可以在后面所示的seataServer.properties
中进行显式设置。- 如果你只是想保留默认的 8091,就不需要额外写。Seata 启动后会在日志中提示它的监听端口是哪一个。
seataServer.properties
)在 Nacos 的 Namespace = test-prod
,Group = SEATA_GROUP
下,新建或编辑 Data ID = seataServer.properties
,写入内容示例:
properties########## transport ########## 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 # 如果想把 Netty RPC 改成别的端口,而不是 8091,可以加: # transport.server-port=8091 ########## service ########## # tx-service-group 映射。Client 设置 tx-service-group=seatatest 时,对应 seatatest service.vgroupMapping.seatatest=seatatest # 如果是直连模式,这里会生效,告诉客户端要连 8091 service.default.grouplist=192.168.28.28:8091 service.enableDegrade=false service.disableGlobalTransaction=false ########## 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 client.undo.logTable=undo_log client.undo.compress.enable=true client.undo.compress.type=zip client.undo.compress.threshold=64k # Undo 日志保留天数/清理周期 server.undo.logSaveDays=7 server.undo.logDeletePeriod=86400000 ########## log ########## log.exceptionRate=100 ########## store(主要是 TC 端使用) ########## store.mode=db store.lock.mode=db store.session.mode=db # 数据源信息(示例:MySQL) store.db.datasource=druid store.db.dbType=mysql store.db.driverClassName=com.mysql.cj.jdbc.Driver store.db.url=jdbc:mysql://192.168.28.28:3305/seata?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false store.db.user=admin store.db.password=NWT@temp123 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.lockTable=lock_table store.db.queryLimit=100 store.db.maxWait=5000 ########## 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 ########## metrics.enabled=false metrics.registryType=compact metrics.exporterList=prometheus metrics.exporterPrometheusPort=9898
说明:
- 默认情况下,Seata 在 Netty RPC 端会监听 8091。若你想改端口,可以在这里加上
transport.server-port=xxxx
。- 如果 Client 用的是 Nacos 注册中心,则它会通过 Nacos 的服务发现到 Seata Server 注册的真实
host:port
,所以这里的service.default.grouplist
在注册中心模式下只是一个备用配置。service.vgroupMapping.seatatest=seatatest
对应客户端的seata.tx-service-group=seatatest
。
application.yml
)在你的业务微服务中,如果使用 Spring Boot + Seata:
yamlspring: application: name: your-biz-service seata: enabled: true # 这里对应 service.vgroupMapping.seatatest=seatatest tx-service-group: seatatest # 是否自动代理数据源,可根据实际情况选择 enable-auto-data-source-proxy: false # 如果启用 Nacos 做注册中心,就和 Server 保持一致 registry: type: nacos nacos: application: seata-server server-addr: 192.168.28.32:8848 namespace: test-prod group: SEATA_GROUP cluster: seatatest username: nacos password: nacos # 配置中心:和 Seata Server 保持一致 config: type: nacos nacos: server-addr: 192.168.28.32:8848 namespace: test-prod group: SEATA_GROUP username: nacos password: nacos data-id: seataServer.properties service: # 如果要强制直连模式,可写 group-list # vgroup-mapping: # seatatest: default # group-list: # default: 192.168.28.28:8091 disable-global-transaction: false
说明:
tx-service-group: seatatest
一定要与 服务端配置中的service.vgroupMapping.seatatest=...
保持一致,否则会报 “No available service” 等错误。- 如果确实要直连,你可以在上面
service
块里把group-list
的 IP:PORT 设成SeataServerIP:8091
;但前提是 Server 端默认监听 8091,且能通。- 如果使用 Nacos 注册中心,那么只要 Server 成功注册到 Nacos(application = seata-server,cluster = seatatest,端口 8091),Client 就能正常发现并连上。
seata-server
、集群 seatatest
,下方有实例暴露 8091 端口。这样就能 同时保留 7091
(Seata 控制台) 和 8091
(RPC 端口) 这两个端口,互不冲突,各司其职。祝使用顺利!
2024-12-31 14:50:11.236 INFO 32368 --- [_RMROLE_1_38_40] i.s.c.r.p.c.RmBranchRollbackProcessor : rm handle branch rollback process:xid=10.23.24.6:8091:3576461000735551497,branchId=3576461000735551502,branchType=AT,resourceId=jdbc:mysql://192.168.28.33:3306/owm,applicationData=null
2024-12-31 14:50:11.236 INFO 32368 --- [_RMROLE_1_38_40] io.seata.rm.AbstractRMHandler : Branch Rollbacking: 10.23.24.6:8091:3576461000735551497 3576461000735551502 jdbc:mysql://192.168.28.33:3306/owm
2024-12-31 14:50:11.236 INFO 32368 --- [_RMROLE_1_38_40] i.seata.rm.datasource.DataSourceManager : branchRollback failed. branchType:[AT], xid:[10.23.24.6:8091:3576461000735551497], branchId:[3576461000735551502], resourceId:[jdbc:mysql://192.168.28.33:3306/owm], applicationData:[null]. reason:[Branch session rollback failed and try again later xid = 10.23.24.6:8091:3576461000735551497 branchId = 3576461000735551502 dynamic-datasource can not find primary datasource]
2024-12-31 14:50:11.237 INFO 32368 --- [_RMROLE_1_38_40] io.seata.rm.AbstractRMHandler : Branch Rollbacked result: PhaseTwo_RollbackFailed_Retryable
从日志上看,Seata 在做分支回滚时,出现了:
textbranchRollback failed... reason:[Branch session rollback failed and try again later xid = 10.23.24.6:8091:3576461000735551497 branchId = 3576461000735551502 dynamic-datasource can not find primary datasource]
这说明 Seata 要回滚该分支事务时,调用了 分布式事务资源管理器(RM),但 动态数据源(dynamic-datasource) 无法匹配到对应的数据源,导致回滚失败,并返回了 “PhaseTwo_RollbackFailed_Retryable
”。(Seata 会尝试再次进行回滚,一直重试。)
在使用 AT 模式 时,Seata 需要感知并代理你的实际数据源,以便在需要回滚时执行对应的 Undo SQL。然而现在它提示找不到对应的 datasource,通常是因为:
resourceId
不一致。jdbc:mysql://host:port/dbname
) 与实际 dataSource 名、URL 不匹配,导致 Seata 在回滚时无法定位正确数据库连接。baomidou
的 dynamic-datasource-spring-boot-starter
),但并未做与 Seata 的正确联动配置。下面给出一些常见的排查 / 解决思路。
在 application.yml 中,明确指定默认数据源:
yamlspring: datasource: dynamic: primary: owm # 这就是你想指定为默认的数据源名称 datasource: owm: url: jdbc:mysql://192.168.28.33:3306/owm?useSSL=false&useUnicode=true... username: xxx password: xxx driver-class-name: com.mysql.cj.jdbc.Driver
如果 Seata 在回滚时没有找到 “owm”,就会报「can not find primary datasource」。所以需要确保你已经设置了 primary
的名字,并且它对应的 URL 正好是 jdbc:mysql://192.168.28.33:3306/owm
。
如果你有多个动态数据源,需要确认在执行分支事务时,实际使用的是哪个数据源?Seata 回滚时就要找那个数据源,名字要和 Seata resourceId
对上。
方式一:通过 Seata 原生的 自动代理。
在 application.yml
里加上:
yamlseata: enable-auto-data-source-proxy: true # 其他Seata的配置...
这样 Seata 会扫描 Spring 容器里的数据源并自动代理。但是当使用了 Dynamic Datasource 时,有时候会和其原生的 Bean 初始化顺序冲突,需要仔细调试。
方式二:显式通过 Baomidou 侧提供的 Seata 拦截器 / 代理适配器。
Baomidou 在 3.x 之后支持简单的 Seata 适配,如果你用的是最新版(比如 3.5+),可以在官方文档中查一下「[Dynamic Datasource - Seata 集成]」。有些场景下需要额外加注解或配置。
jdbc:mysql://IP:Port/DBName
当作 resourceId
。如果你的实际数据源在 Baomidou 里配置的是类似 xxx?useUnicode=true&characterEncoding=utf8
,那么 Seata 识别时,也需要确保能匹配到同一个字符串(或者至少是同一个数据库地址)。seata.datasource.resourceName
)来显式指定 resourceId,但在大多数场景下只要 URL 一致就行。那就需要检查:
spring.datasource.url=jdbc:mysql://192.168.28.33:3306/owm
配置,但在 Seata 回滚时,却拿到 jdbc:mysql://192.168.28.33:3306/owm
而无法匹配到 DataSource。seata.enable-auto-data-source-proxy
或 spring.cloud.alibaba.seata.tx-service-group
之类的配置。owm
里建一个 undo_log
表,Seata 执行回滚时会去这个表里找对应的记录。如果这个表不存在,也会导致回滚失败(不过错误提示会不一样)。DataSource
是不是只有一个?名字叫啥?是否带有 “primary = true”?DEBUG
,看看在启动时是如何加载数据源、如何被 Seata 代理的。假设你用 Baomidou dynamic-datasource 并且只有一个数据源,名叫 owm
,可以尝试这么写:
application.yml
里的数据源配置yamlspring: datasource: dynamic: primary: owm # 指定默认数据源名称 datasource: owm: url: jdbc:mysql://192.168.28.33:3306/owm?useSSL=false&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver
yamlseata: enabled: true enable-auto-data-source-proxy: true application-id: your-app tx-service-group: seatatest # 需要与 server 那边service.vgroupMapping.seatatest对应 registry: type: nacos nacos: server-addr: 192.168.28.32:8848 namespace: test-prod group: SEATA_GROUP username: nacos password: nacos cluster: seatatest application: seata-server config: type: nacos nacos: server-addr: 192.168.28.32:8848 namespace: test-prod group: SEATA_GROUP username: nacos password: nacos data-id: seataServer.properties service: disable-global-transaction: false
jdbc:mysql://192.168.28.33:3306/owm
,Seata 默认就能识别到同一个 resourceId。jdbc:mysql://192.168.28.33:3306/owm?useUnicode=true&characterEncoding=utf-8...
,一般 Seata 也可以识别,只要 IP、端口、库名一致就行。dynamic-datasource can not find primary datasource
,说明 动态数据源没能匹配到当前要回滚的数据库连接。primary
;只要让 Seata 知道「哪一个数据源对应 jdbc:mysql://192.168.28.33:3306/owm
」并成功执行 Undo/Redo,就能正常完成回滚操作。祝调试顺利!