
在微服务体系里Nacos 和 Seata 常常是成对出现的。注册配置中心有了分布式事务也得跟上否则服务一拆数据一致性就成了大问题。把这两个组件用 Docker 跑起来是很多团队落地微服务的第一步但也是踩坑最多的第一步。我自己实操下来Docker 跑单个 Nacos 不难真正让人头大的是 Seata。它的坑不在容器本身而在“配置链路”Seata 要先用 Nacos 当配置中心拉到自己的配置再注册到 Nacos 上然后客户端才能通过事务分组找到它。这一环扣一环任何一个时序错了、版本不匹配、分组配置漏了结果就是日志里疯狂输出重试事务永远起不来。这篇文章我就把从零到跑通的这条链路掰开讲清楚。不绕弯子先讲整体思路和组件关系再逐步给 Nacos 和 Seata 的容器部署方案最后是微服务客户端的集成要点和排坑记录。目标是照着操作能在自己机器上把一套可用的 Nacos Seata 跑起来并搞清楚每一个关键配置背后的原因。1. 部署思路拆解先搞懂这两个组件是怎么配合的很多人一上来就急着敲 docker run结果环境起了一堆容器服务却连不上。我先花点时间把这俩组件之间的关系拆清楚这比任何命令都重要。1.1 Nacos 和 Seata 各自扮演什么角色Nacos 是注册中心和配置中心。在 Seata 的体系里它同时承担了三个职责注册中心Seata Server事务协调器简称 TC启动后要把自己的地址注册到 Nacos这样微服务事务发起方和参与方也就是 RM/TM才能找到 TC 在哪。配置中心Seata Server 自身的配置比如存储模式、事务分组、超时时间等可以放在 Nacos 配置中心统一管理而不是打包在容器里写死。这样改配置不用重新构建镜像。配置存储Seata 的配置还可以通过 Nacos 的配置管理界面直接修改实现动态生效。Seata 则负责分布式事务。它的核心结构是 TC事务协调器、TM事务管理器、RM资源管理器。TC 就是独立部署的 Seata ServerTM 和 RM 是嵌入在微服务里的客户端。事务发起时TM 向 TC 申请开启全局事务RM 把分支事务注册到 TC最终由 TC 统一决定提交还是回滚。1.2 为什么 Seata 必须先依赖 Nacos 才能启动Seata Server 启动时第一件事是去 Nacos 拉取配置。如果 Nacos 里没有对应的配置或者 Seata 拿不到注册中心的地址它就会一直处于尝试连接的状态。这里有个非常关键的时序问题如果你先启动 Seata再启动 Nacos或者 Seata 启动时 Nacos 还没就绪那么 Seata 会反复重试但很可能最终也没能正确注册。即便 Nacos 之后起来了有些老版本 Seata 也不会自动重连成功你必须重启 Seata 容器。所以在 Docker 编排里务必保证 Nacos 先启动并健康检查通过再启动 Seata。从容器编排角度推荐创建一个独立的 Docker 网络让 Nacos 和 Seata 通过容器名互通而不是依赖宿主机 IP。这样做的好处是IP 变了不用改配置容器间通信稳定后续扩容也方便。1.3 版本匹配问题为什么我的客户端连不上 Seata这是踩坑率最高的一块。Seata 的版本、Spring Cloud Alibaba 的版本、Nacos 的版本以及微服务里引入的 Seata 依赖版本必须谨慎匹配。组件推荐版本组合说明Nacos2.x比如 2.2.x2.x 性能更好gRPC 端口要记得开放Seata Server1.7.x 或 1.6.x1.7 之后配置方式有调整下文会讲Spring Cloud Alibaba2021.0.5.0 左右该版本内置的 Seata 依赖通常为 1.5.x/1.6.x需显式覆盖Seata Client微服务依赖与 Server 保持一致强烈建议 client 和 server 版本完全一致举个例子某项目里用了 Spring Cloud Alibaba 2021.0.5.0它默认引入的 Seata 可能是 1.5.2结果 Server 端部署的是 1.7.0于是客户端启动时提示版本不一致或注册失败。解决办法很简单在微服务里显式指定 Seata 版本和 Server 对齐。这一点后文集成部分还会再提。2. 环境准备与镜像基础版本、网络、存储一次到位动手之前先花十分钟把环境准备好。工欲善其事必先利其器镜像选型错了后面全是眼泪。2.1 镜像选择与下载镜像我建议直接使用官方或社区维护版Nacosnacos/nacos-server:v2.2.3生产建议选 2.2.3 以上稳定版。Seataseataio/seata-server:1.7.0这个版本配置项变化较大直接对应 1.7.x 客户端。拉取命令docker pull nacos/nacos-server:v2.2.3 docker pull seataio/seata-server:1.7.0这里有个细节Nacos 2.x 以后默认会使用 gRPC 端口1000 主端口偏移量比如主端口 8848gRPC 端口就是 9848。用 Docker 映射端口时别只映射 8848要同时映射 9848。否则服务注册没问题但配置中心长轮询和部分服务间通信会异常。2.2 创建 Docker 网络容器间通信我推荐手动建一个网络docker network create micro-net后续 Nacos 和 Seata 都挂到这个网络下互相用容器名访问。2.3 存储规划Nacos 有两种存储模式内嵌 Derby默认和 MySQL。单机测试用内嵌没问题但一旦你想保留配置、或者在一个 Nacos 集群里混用就必须用 MySQL。Seata 也有两种存储模式file 和 db。生产环境建议也用 db这样事务记录可查、可恢复。所以部署前要有一个 MySQL 实例并准备两个库Nacos 配置库例如nacos_configSeata 事务库例如seataNacos 的表结构脚本在 Nacos 官方包里有也可以从容器里取出来稍后说明。3. Nacos 部署实操单机模式跑通并持久化Nacos 可以单机跑可以集群跑。这里先讲单机适合开发和测试环境。3.1 先准备 MySQL创建数据库并导入 Nacos 脚本。如果你不方便连容器可以先下载 Nacos 包用压缩包里的conf/mysql-schema.sql或者从容器里拷贝出来# 先临时启动一个容器把脚本拷出来 docker run --name nacos-tmp -d nacos/nacos-server:v2.2.3 docker cp nacos-tmp:/home/nacos/conf/mysql-schema.sql ./mysql-schema.sql docker rm -f nacos-tmp然后到 MySQL 里执行CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4; USE nacos_config; SOURCE /path/to/mysql-schema.sql;3.2 正式启动 Nacos单机模式启动命令docker run -d \ --name nacos \ --net micro-net \ -p 8848:8848 \ -p 9848:9848 \ -e MODEstandalone \ -e SPRING_DATASOURCE_PLATFORMmysql \ -e MYSQL_SERVICE_HOST你的MySQL宿主机IP或容器名 \ -e MYSQL_SERVICE_DB_NAMEnacos_config \ -e MYSQL_SERVICE_PORT3306 \ -e MYSQL_SERVICE_USERroot \ -e MYSQL_SERVICE_PASSWORD你的密码 \ -e NACOS_AUTH_ENABLEfalse \ nacos/nacos-server:v2.2.3注意几个环境变量MODEstandalone单机模式不写的话默认也会尝集群模式会报错找不到配置。SPRING_DATASOURCE_PLATFORMmysql指定用 MySQL否则连内嵌 Derby。NACOS_AUTH_ENABLEfalse开发环境先关鉴权。生产环境必须开并配置密钥。启动完成后访问http://localhost:8848/nacos默认账号密码nacos/nacos。如果页面能打开说明 Nacos 起来了。也可以用docker logs -f nacos日志末尾看到 Nacos started successfully 之类字样就好了。3.3 为什么我建议单机也挂载数据目录有人会说数据都在 MySQL 里了容器删掉也没事。但 Nacos 有些运行态信息、应用的配置变更历史以及后续可能用到的 cluster.conf 等都存在容器文件系统里。建议至少挂载两个目录-v /data/nacos/logs:/home/nacos/logs -v /data/nacos/conf:/home/nacos/conf这样做的好处是升级版本或重建容器时日志和自定义配置不会丢。如果你改过 Nacos 的一些配置项比如鉴权密钥、超时时间都写在 conf 下挂载出来免得每次容器重建都要重新改。4. Seata Server 部署实操配置中心与注册中心双联调Seata Server 比 Nacos 复杂一个量级。它需要同时连接注册中心和配置中心而且在 1.7 版本里配置文件结构有变化很多人被旧教程坑得不轻。4.1 理解 Seata 1.7 的配置文件结构Seata 1.7 及之后版本配置文件分两块registry.conf指定注册中心和配置中心类型以及对应的连接参数。配置数据可以放在本地config.txt文件里也可以推到 Nacos 配置中心中由 Seata 动态读取。默认情况下Seata 容器里会自带registry.conf默认配置中心是 file。你要把它改成 Nacos。同时把 Seata 的那些核心配置事务分组、存储模式、数据库连接等通过脚本推送到 Nacos。如果你用的是 1.5.x 之类的老版本里面还有file.conf那里是事务分组和存储配置。1.7 版本弱化了 file.conf重点变成了“通过配置中心统一管理”。所以网上很多老教程就不适用了必须按照 1.7 的方式操作。4.2 制作 Seata 的 registry.conf 和 config.txt先用一个临时容器把 Seata 的默认配置取出来docker run --name seata-tmp -d seataio/seata-server:1.7.0 docker cp seata-tmp:/seata-server/resources/registry.conf ./ docker cp seata-tmp:/seata-server/resources/config.txt ./ docker rm -f seata-tmp然后编辑registry.conf重点改成 Nacosregistry { type nacos nacos { application seata-server serverAddr nacos:8848 group SEATA_GROUP namespace cluster default username nacos password nacos } } config { type nacos nacos { serverAddr nacos:8848 namespace group SEATA_GROUP username nacos password nacos } }这里注意serverAddr nacos:8848因为 Nacos 和 Seata 在同一个 Docker 网络里所以用容器名访问。如果你用宿主机 IP也行但一旦部署环境变化就得改。namespace保持空串表示 public 命名空间。如果你在 Nacos 里专门建了seata命名空间这里要填命名空间 ID注意不是名字是 ID。group SEATA_GROUP后续在 Nacos 配置里会统一放到这个分组里。客户端配置也要用同一个 group否则拉不到配置。再编辑config.txt这是 Seata Server 的核心配置。重点关注以下几项store.modedb store.db.datasourcedruid store.db.dbTypemysql store.db.driverClassNamecom.mysql.cj.jdbc.Driver store.db.urljdbc:mysql://你的MySQL地址:3306/seata?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai store.db.userroot store.db.password你的密码存储模式改成 db这样事务日志持久化到数据库。Seata 的数据库表结构脚本在 Seata 包里也有叫script/server/db/mysql.sql同样要先在 MySQL 里执行。如果你用的不是 MySQL 而是其他库对应改 dbType、驱动和脚本。4.3 用脚本把配置推送到 NacosSeata 官方提供了nacos-config.sh脚本位于 Seata 源码的script/config-center/nacos/目录下。在临时容器里可能没有这个脚本建议从源码仓库下载对应版本。脚本用法大致是sh nacos-config.sh -h nacos -p 8848 -g SEATA_GROUP -t 命名空间ID -u nacos -w nacos执行后它会读取config.txt里的配置项逐条推送到 Nacos。推送完成后你应该能在 Nacos 控制台的“配置管理”里看到SEATA_GROUP分组下有很多service.vgroupMapping.*、store.mode之类的配置项。注意如果你的 Nacos 开启了鉴权脚本里要带上用户名和密码。如果是旧版本脚本可能需要手动加参数。执行前可以先查看脚本帮助sh nacos-config.sh -h4.4 启动 Seata Server再把改好的registry.conf挂载进容器启动docker run -d \ --name seata-server \ --net micro-net \ -p 8091:8091 \ -e SEATA_IP宿主机IP \ -e SEATA_PORT8091 \ -v /data/seata/registry.conf:/seata-server/resources/registry.conf \ -v /data/seata/logs:/seata-server/logs \ seataio/seata-server:1.7.0这里解释几个关键点SEATA_IP这是 Seata Server 注册到 Nacos 时上报的 IP。如果不设置容器网络环境下它可能会把容器内网 IP 报上去导致微服务无法通过这个 IP 访问 Seata。如果微服务在宿主机上直接跑这里一定要填宿主机局域网 IP如果微服务也在同网络容器里填容器内网 IP 也行。8091Seata Server 默认端口不改的话保持默认。registry.conf挂载必须把刚才改好的配置挂进去否则容器用的是默认 file 配置不会连接 Nacos。启动后查看日志docker logs -f seata-server如果看到Server started successfully说明 Seata 已启动。再去 Nacos 控制台的服务列表里应该能看到一个名为serverAddr或seata-server的服务里面有一个default集群的实例。4.5 常见启动失败场景Seata 起不来九成是配置没对上。我见过最多的情况忘记推送配置到 NacosSeata 启动时拉不到store.mode报错提示 config not found 或类似信息。推送到 Nacos 的配置在SEATA_GROUP但 registry.conf 里 group 写的是别的分组。数据库连接失败比如密码不对、seata库不存在、MySQL 驱动版本不兼容。SEATA_IP填了 127.0.0.1导致微服务在别的机器上连不上 Seata。这些问题的排查套路都统一先看日志Seata 的日志会告诉你它连不上谁、拉不到什么。不要瞎改配置先docker logs -f seata-server盯五分钟再说。5. 微服务客户端集成拿到事务分组配置才真正能跑Seata Server 起来了不算结束。真正让分布式事务跑起来还要在微服务里配置好 Seata 客户端。很多人在这步翻车症状是服务都注册上了但事务不生效或者io.seata的日志一堆连接错误。5.1 引入依赖并锁定版本在微服务的pom.xml里以 Spring Boot 为例要引入dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-seata/artifactId /dependency这个依赖本身不带你指定 Seata 版本所以必须显式覆盖。比如你用的 Server 是 1.7.0那就dependency groupIdio.seata/groupId artifactIdseata-spring-boot-starter/artifactId version1.7.0/version /dependency版本不匹配会出现某些方法找不到、接口不兼容的问题而且很隐蔽运行到事务提交时才报错。所以我再次强调client 和 server 版本严格保持一致。5.2 配置 Seata 客户端在 application.yml 里客户端的配置原理是微服务启动时也去 Nacos 上拉取 Seata 配置。所以你要在application.yml里指定 Seata 相关参数。常见的配置段如下spring: cloud: nacos: discovery: server-addr: localhost:8848 namespace: public seata: enabled: true application-id: ${spring.application.name} tx-service-group: my_test_tx_group service: vgroup-mapping: my_test_tx_group: default grouplist: default: localhost:8091 registry: type: nacos nacos: server-addr: localhost:8848 namespace: public group: SEATA_GROUP config: type: nacos nacos: server-addr: localhost:8848 namespace: public group: SEATA_GROUP这里面最关键的两个东西tx-service-group事务分组名你可以自己起比如my_test_tx_group。service.vgroup-mapping这个映射把逻辑分组映射到 Seata 集群名。上面写的my_test_tx_group: default意思是这个事务分组对应 Seata Server 的default集群。这里有个容易混淆的点如果你在 Seata Server 的registry.conf里配了cluster default那客户端映射值必须是default。如果两边不一致客户端会报can not get cluster name或者老提示找不到 Seata Server。实际上事务分组的设计目的是不同服务可以归属于不同事务分组通过映射灵活指定它们要去哪个 Seata Server 集群。你可以有多个分组但每个分组最终都要落到一个实际集群名。5.3 关于服务端动态配置的补充之前把 Seata 配置推到了 Nacos 配置中心客户端其实也会拉取同样的配置。所以你在application.yml里写seata.service.vgroup-mapping.my_test_tx_groupdefault最终效果和在 Nacos 配置中心里的service.vgroupMapping.my_test_tx_groupdefault一致。建议统一以 Nacos 配置中心为准因为那样可以动态调整不需要重新打包。但在测试阶段先写在application.yml里也没问题。5.4 数据源代理与 undo_log 表Seata AT 模式的核心原理是代理数据源记录事务执行前后的镜像通过undo_log表实现回滚。所以有两个硬性要求数据源必须被 Seata 代理。在微服务里要么用SeataAutoDataSourceProxy或数据源配置要么确保 Seata 自动包装了数据源。如果用的是默认 Druid/MyBatis 环境通常 Seata 会自动代理。每个涉及分布式事务的数据库里都要有undo_log表。建表 SQLCREATE TABLE IF NOT EXISTS 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, PRIMARY KEY (id), UNIQUE KEY ux_undo_log (xid, branch_id) ) ENGINE InnoDB AUTO_INCREMENT 1 DEFAULT CHARSET utf8;如果某个分支服务没建这张表事务执行时不会立刻报错但回滚时会失败。排查时极难发现所以我建议初始化表时就把所有服务库都建上。5.5 增加全局事务注解最后在事务发起方的业务方法上加GlobalTransactional。注意这个注解只加在事务发起方TM分支参与方不需要加。比如订单服务在创建订单时同步扣库存、扣余额订单服务方法加注解GlobalTransactional(timeoutMills 300000, name create-order-tx) public void createOrder(OrderDTO order) { // 本地订单插入 // 调用库存服务扣减 // 调用账户服务扣余额 }分支服务里只需要保持本地事务注解TransactionalSeata 会自动接管分支事务的注册。6. 实操验证从启动到事务回滚的完整联调纸上谈兵没用最好亲自跑一遍。下面是我建议的验证路径你可以照着做一遍确保整套链路没有隐藏问题。6.1 验证 Seata Server 已注册到 Nacos打开 Nacos 控制台切换到服务列表。如果之前什么都没注册现在应该多了一个服务名字可能是seata-server。点进去看集群default下面有没有实例IP 端口是否为SEATA_IP:8091。如果没有实例说明 Seata Server 没注册成功。先看 Seata 日志里有没有报 Nacos 连接失败再看 registry.conf 填的 Nacos 地址是否正确。6.2 启动微服务观察客户端日志启动你的订单服务、库存服务、账户服务。观察日志中 Seata 相关输出。正常启动时会看到类似这样的日志xx.x.x.x:8091 - 连接成功或者至少没有can not get cluster name、no available service这类错误。也可以看 Nacos 控制台服务列表此时应该有多个微服务和 Seata Server 并列。6.3 触发事务故意让分支失败这是最有效的验证方法。在账户服务扣余额的方法里故意抛一个异常比如余额不足。然后调用订单服务创建订单观察结果账户服务本地事务回滚。库存服务也回滚即使它自己的 SQL 正常执行了。订单记录不落库。如果库存服务没有回滚问题出在分支服务没注册到同一个事务组或者数据源没有被 Seata 代理或者undo_log表缺失。此时按刚才提到的几个配置项逐一排查。6.4 查看 Seata 的事务记录如果配置了 db 模式的seata库可以去表global_table、branch_table里查。事务跑完后表里会留下记录。全局事务结束记录会清理或标记。如果发现global_table里状态一直挂起说明事务超时或分支卡住需要看日志里transactionManager的报错。这一步很多人忽略但实际上它是判断“Seata 到底有没有参与事务”的最直接证据。7. 排坑大全Docker 化 Nacos Seata 的典型问题速查我把实践中最常踩的坑整理成一张速查表。你遇到问题时先按表里的思路排查比自己瞎试效率高得多。现象可能原因排查与解决Seata 容器启动后反复重启日志提示拉不到配置没有执行 nacos-config.sh 写入配置registry.conf 的 group 和推送配置的 group 不一致到 Nacos 控制台确认SEATA_GROUP分组下是否有配置项确认 registry.conf 内容Seata 容器日志显示启动成功但 Nacos 服务列表里没有它SEATA_IP未能正确上报网络不通namespace 不一致检查SEATA_IP设置查看 registry.conf 中 namespace 是否为空用 curl 测试容器到 Nacos 的网络客户端启动报can not get cluster name事务分组映射没配好vgroup-mapping的集群名和 server 端 cluster 不一致确认 application.yml 中service.vgroup-mapping.tx-service-group映射到了default检查 server 端cluster配置客户端一直提示connect timeout或Connection refusedSeata Server 地址不对容器模式下grouplist写的是 localhost如果客户端在宿主机写宿主机局域网 IP如果在容器里写 seata 容器名分布式事务执行后分支服务没回滚分支服务未参与同一事务分组数据源未被 Seata 代理undo_log表缺失检查分支服务的 Seata 配置确认所有库都有 undo_log 表确认数据源代理生效Nacos 启动后服务注册正常但配置中心模块访问异常只映射了 8848没映射 9848补上-p 9848:98482.x 默认需要 gRPC 端口服务启动时日志大量报com.alibaba.nacos超时或Server check failNacos 版本和客户端版本不兼容网络不稳定检查 Nacos 版本和服务端是否一致查看 Nacos 日志有无异常在 Nacos 控制台改了配置Seata 服务不生效如果配置在 Nacos 上Seata 需要刷新部分配置项本身不支持动态持久化检查 Seata 是否配置了nacos-config的 group 一致必要时重启容器这张表基本覆盖了我在多个项目里遇到的高频问题。如果你遇到的情况不在这张表里要相信日志会告诉你答案。尤其要养成看docker logs -f seata-server的习惯它输出的每一条警告都可能是线索。再补充一个容易忽略的坑同一台机器上如果跑过多个版本的 Nacos 或 Seata遗留的端口占用和数据会产生干扰。用 Docker 的好处是删除容器很干净但挂载到宿主机目录的日志和配置不会自动清理。升级版本时先备份再清空旧目录避免混用。8. 版本选择与升级的一点建议版本问题在前面反复强调这里我再集中说一次因为它是影响整套链路稳定性的地基。8.1 为什么我推荐 Nacos 2.xNacos 1.x 到 2.x 是一次大版本升级2.x 引入了 gRPC 长连接服务注册发现速度、配置推送时效都有了质的提升。在 1.x 时代配置变更到客户端感知可能有秒级延迟2.x 基本能到毫秒级或准实时。对于 Seata 这种对注册发现时机敏感的场景用 2.x 明显更稳。8.2 Seata 版本选择的策略Seata 的迭代速度很快。我的习惯是不追最新选一个已经过大量项目验证的稳定版本比如 1.7.x 或 1.6.x。然后微服务里的 Seata 依赖版本严格跟随 Server 版本。查看对应版本的事务分组配置方式因为 1.5、1.6、1.7 之间的配置结构有调整。升级 Seata 版本时同时升级 Server 和所有客户端不能只升一边。我曾经遇到过一个案例Seata Server 从 1.5 升到 1.7但某个服务还停留在 1.4 的客户端配置结果事务分组一直解析不出来。最后统一升级并重写配置才解决。教训就是版本升级不是单点操作而是全链路操作。8.3 关于命名空间和分组的建议虽然 public 命名空间在开发环境够用但多人协作或多环境隔离时建议给每个环境建独立命名空间。比如dev、test、prod。命名空间 ID 是一串不直观的 UUID 或自定义字符串配置时要填 ID 而不是名称。如果命名空间设了那么Nacos 控制台上的服务列表会按命名空间隔离。Seata Server 的 registry.conf 里namespace要填对应命名空间 ID。微服务里spring.cloud.nacos.discovery.namespace也要填同样的 ID。这块配置只要有一处不一致表现就是服务列表零零散散谁和谁都连不上。排查时先确认三处的 namespace 是否完全一致。9. 最后说几句实操心得这套 Nacos Seata 的 Docker 部署方案我在本地开发环境和团队测试环境反复搭过很多遍。最开始也觉得麻烦后来理清了三个核心点就再没慌过第一先理清注册中心和配置中心的分工。Nacos 是服务发现和配置推送Seata 是事务协调两者之间有依赖关系但职责不同。理解了 Seata 启动时先拉配置、再上报注册这个顺序很多启动失败的谜团就解开了。第二版本对齐是个硬约束。无论是 Nacos 还是 Seata也无论是 Server 还是客户端版本不一致会引发各种牵连问题。宁可花五分钟查一下版本兼容矩阵也不要出了问题再来回试。第三事务不回滚时从三个方向排查事务分组是否映射正确、数据源是否被代理、undo_log 表是否存在。这三件事都检查完大部分问题都能定位。用 Docker 部署的好处是把环境差异降到最低。但也正因为容器把很多细节隐藏了排错时更要依赖日志和表记录。我的习惯是Seata 容器日志永远保持实时跟随Nacos 控制台时刻打开全局事务执行完就抽几秒看下global_table。坚持这样做之后分布式事务再也不是“玄学”。希望这篇走查能帮你少踩几个坑。你的环境也许和我略有不同但只要抓住“配置链路”和“版本对齐”这两条主线一定能顺利跑通。