讲真的微服务架构里事务和流控这两块最容易让团队在“测试环境一切正常、一上线就出事”的怪圈里打转。Nacos、Seata、Sentinel这套组合基本是Java微服务生态里绕不开的三件套。但网上教程大多是单机版演示真到要部署成高可用集群尤其是用Docker跑在实体服务器上时坑远比想象的多。这篇文章我把最近在模拟项目X的微服务改造中用Docker Compose搭建Nacos、Seata、Sentinel集群的完整过程记录下来。包含我为什么这么拆分、每个服务的核心参数怎么定、实操命令怎么写以及我踩过的那些文档里查不到的低级错误。无论你是刚接触微服务运维还是已经在生产环境摸爬滚打这套部署方案都可以直接参考。1. 整体设计与组件选型1.1 为什么一定要用集群而不是三套单机很多团队最开始都是Nacos、Seata、Sentinel各起一个容器跑得也挺好。但等到一个核心服务重启或者流量峰值一来问题就暴露了注册中心挂了所有服务都找不到彼此整个调用链直接瘫痪配置中心不可用服务启动时拉不到配置业务容器疯狂报错事务协调器单点故障分布式事务卡在中间状态数据不一致只能靠人工订正流控规则放在本地内存里Sentinel重启后规则全部丢失限流策略一夜回到解放前。所以我这次的目标很明确Nacos至少三节点Seata至少两节点Sentinel控制台虽然不需要注册中心那样严格高可用但也要有数据持久化和多实例管理的能力。整体集群不是“越多越好”而是要保证任意一台物理机宕机后整个微服务链路还能正常对外提供核心能力。1.2 组件选型与版本搭配版本搭配是这次踩坑的第一个大头。直接说结论我最终用的是组件版本说明Nacos2.2.32.x版本性能比1.x提升明显尤其是gRPC长连接集群模式配置更简单Seata1.6.1兼容Nacos作为注册配置中心seata-server内嵌Raft或基于DB的高可用都可用Sentinel1.8.6Dashboard与客户端版本需保持兼容否则规则推送会失败MySQL8.0.32Seata事务会话存储、Nacos配置持久化、Sentinel规则持久化都走同一个库Docker20.10宿主机至少要有2核4G内存集群总共建议4核8G以上Docker Composev2编排工具比纯docker run命令管理方便得多这个版本组合我实测过很多轮稳定度比较高。如果你要用Nacos 2.x要注意客户端版本和服务器版本尽量一致否则会时不时出现“临时实例心跳超时被剔除”的诡异问题。Seata 1.6.x对Nacos配置文件格式有要求后面我会单独说。Sentinel版本更要谨慎Dashboard和客户端依赖的sentinel-core版本差太多控制台就不能实时看到流量监控了。1.3 部署拓扑与端口规划我采用了三个“容器节点”的模拟集群但实际上可以跑在两台实体机上。为了便于说明我给出逻辑主机规划节点角色开放端口node1宿主机ANacos、Seata、Sentinel、MySQL8848, 9848, 9849, 8091, 8858, 3306node2宿主机BNacos、Seata8848, 9848, 9849, 8091node3宿主机CNacos8848, 9848, 9849这里有个很多新手容易忽略的点Nacos 2.x除了8848这个HTTP端口还必须有9848和9849两个gRPC端口。9848是客户端gRPC端口9849是集群内部节点间通信端口。如果你在Docker映射端口时只映射了8848服务能注册上去但客户端推送配置、订阅服务变更都会失败表现就是“看着在线其实不通”。端口映射错了还不报错排查特别费劲。后面我在常见问题里详细聊。还有一个决策点Sentinel控制台要不要单独部署集群如果只是开发测试环境一个控制台完全够用。如果要支持生产环境多人同时操作建议用Nginx做负载均衡后面挂两个Sentinel Dashboard实例共享同一个数据库。我这次采用的是一个控制台加MySQL持久化的方案。2. 核心配置解析与初始化准备2.1 宿主机环境准备与内核参数在开容器前先把宿主机环境收拾好。这一步看起来废话但很多部署不稳定的源头就是内核参数没调。确认Docker和Compose版本docker -v docker compose version如果Compose是旧版v1建议直接升级到v2。我的操作记录里旧版Compose在解析depends_on条件时会漏掉健康检查的依赖导致MySQL还没初始化完成Seata和Nacos就继续启动最终以报错结束。调整宿主机文件句柄限制。Seata和Nacos在运行期间会打开大量文件描述符默认1024肯定不够cat /etc/security/limits.conf EOF * soft nofile 65535 * hard nofile 65535 EOF还要打开IP转发和桥接流量过滤方便容器间网络通信modprobe br_netfilter cat /etc/sysctl.conf EOF net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 net.ipv4.ip_forward 1 EOF sysctl -pNacos集群模式对时钟偏差比较敏感三台宿主机要做时间同步。否则节点之间的心跳判断会出问题某些节点被误判为下线。可以用ntpdate或者chrony这块属于常规操作不再展开。2.2 MySQL初始化三套组件共用持久化库Nacos、Seata、Sentinel都需要持久化但需求不一样Nacos需要把配置内容和服务注册信息存下来Seata需要保存全局事务、分支事务、锁记录Sentinel需要保存规则和权限数据。我选择共用一台MySQL实例但每个组件用独立数据库和独立账号避免互相干扰。这是很多生产事故的伏笔一旦混在一起某个组件误操作会把别人的表删掉。登录MySQL执行CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE seata_transaction DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE sentinel_rule DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER nacos% IDENTIFIED BY Nacos123456; CREATE USER seata% IDENTIFIED BY Seata123456; CREATE USER sentinel% IDENTIFIED BY Sentinel123456; GRANT ALL PRIVILEGES ON nacos_config.* TO nacos%; GRANT ALL PRIVILEGES ON seata_transaction.* TO seata%; GRANT ALL PRIVILEGES ON sentinel_rule.* TO sentinel%; FLUSH PRIVILEGES;Nacos官方脚本在conf/nacos-mysql.sqlSeata在script/server/db/mysql.sqlSentinel的建表语句在源码的sentinel-dashboard模块下。按顺序执行即可。这里有个细节Nacos 2.x初始化脚本里的config_info表有encrypted_data_key字段MySQL 8.0对字段名大小写敏感导入时最好直接使用官方脚本不要手建表否则后续配置文件加密功能会异常。2.3 Nacos集群配置的“为什么”Nacos集群配置看起来就是写三个IP但背后有几个关键点想清楚第一为什么要三节点Nacos集群采用Raft协议2.x默认是JRaft做节点间数据一致性。如果只有两个节点当其中一个宕机剩余一个无法形成多数派整个集群会变为只读状态配置无法更新、服务注册也会受影响。三个节点挂一个还能正常读写这是最经济的最小高可用配置。第二为什么Nacos集群模式选了“持久化模式”因为Nacos 2.x支持AP和CP两种模式服务发现走AP保证可用性配置管理走CP保证数据一致性。在同一个集群中这两种模式是并行存在的。使用内置Derby数据库无法支撑多节点数据同步必须外接MySQL。第三NACOS_SERVERS这个环境变量怎么写格式是“主机名:端口主机名:端口”。注意不是IP冒号端口加空格而是逗号分隔。很多人写成了空格分隔导致节点间无法互相发现。我的Nacos节点容器配置核心如下environment: - PREFER_HOST_MODEhostname - MODEcluster - NACOS_SERVERSnacos-node1:8848,nacos-node2:8848,nacos-node3:8848 - SPRING_DATASOURCE_PLATFORMmysql - MYSQL_SERVICE_HOSTmysql-server - MYSQL_SERVICE_PORT3306 - MYSQL_SERVICE_DB_NAMEnacos_config - MYSQL_SERVICE_USERnacos - MYSQL_SERVICE_PASSWORDNacos123456 - MYSQL_SERVICE_DB_PARAMcharacterEncodingutf8connectTimeout5000socketTimeout3000autoReconnecttrueuseSSLfalseallowPublicKeyRetrievaltrue这里有个大坑MYSQL_SERVICE_DB_PARAM里如果没有allowPublicKeyRetrievaltrue连MySQL 8.0时可能会报Public Key Retrieval is not allowed而且这个错误时有时无非常迷。我在模拟环境里第一次部署就被这玩意卡了很久。加上这个参数后一次性通过。2.4 Seata配置的“三份文件”和“六个参数”Seata通过Nacos获取配置但Seata自身启动时也需要知道自己怎么连Nacos、怎么发现事务组。其配置分散在registry.conf、config.txt、bootstrap.yml里。我这次用的是docker镜像内置的Seata 1.6.1所以强烈建议用环境变量而不是改容器内文件。registry.conf决定了Seata注册中心和配置中心是什么registry { type nacos nacos { serverAddr nacos-node1:8848,nacos-node2:8848,nacos-node3:8848 namespace group SEATA_GROUP username nacos password Nacos123456 } }需要用环境变量SEATA_REGISTRY_NACOS_SERVER_ADDR和SEATA_CONFIG_NACOS_SERVER_ADDR覆盖不要手改容器内文件因为镜像重建后文件会被还原。Seata配置存储也放在Nacos里核心配置项是store.mode、store.db.datasource等。这些配置通过Nacos的配置列表来管理配置内容以config.txt格式上传。建议把所有Seata配置放到一个单独的Nacos命名空间seata_config与服务配置隔离。事务组配置service.vgroupMapping.my_test_tx_group要和你业务代码里的事务组名称一致。我在部署时顺手把事务组名称统一成summer_tx_group这样业务方接入时不必改代码默认值。Seata的docker-compose片段seata-server: image: seataio/seata-server:1.6.1 container_name: seata-node1 ports: - 8091:8091 environment: - SEATA_IPseata-node1 - SEATA_PORT8091 - SEATA_REGISTRY_NACOS_SERVER_ADDRnacos-node1:8848,nacos-node2:8848,nacos-node3:8848 - SEATA_CONFIG_NACOS_SERVER_ADDRnacos-node1:8848,nacos-node2:8848,nacos-node3:8848 - SEATA_REGISTRY_NACOS_NAMESPACE - SEATA_REGISTRY_NACOS_GROUPSEATA_GROUP - STORE_MODEdb - STORE_DB_DATASOURCEdruid - STORE_DB_TYPEmysql - STORE_DB_URLjdbc:mysql://mysql-server:3306/seata_transaction?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue - STORE_DB_USERseata - STORE_DB_PASSWORDSeata123456 depends_on: mysql-server: condition: service_healthy这里特别注意SEATA_IP。docker容器内主机名默认是容器IDSeata注册到Nacos时会把容器ID当作IP注册业务服务去连这个IP时必然失败。所以必须设置SEATA_IP为宿主机可达的地址如果Seata和业务服务在同一个Docker网络里可以填容器名如果在不同宿主机上要填宿主机IP。2.5 Sentinel Dashboard改造从内存态到持久化原生Sentinel Dashboard的规则默认存内存里重启后规则全部消失。生产环境绝对不能这样。我做了一个简单改造在Dashboard启动时增加MySQL持久化配置。但这里有个很隐蔽的问题原生Dashboard的数据库脚本只建了authority_rule、cluster_config、cluster_map、degrade_rule、flow_rule、param_flow_rule、system_rule这些表没有把规则与具体应用关联的表做完整。后来我参考了社区方案改造了数据源。核心思路是在Dashboard里增加一个SentinelDataSource规则变更时自动写入MySQL启动时从MySQL加载规则。如果不想改代码也可以采用nacos作为Sentinel规则持久化的数据源业务客户端从Nacos拉取规则。这个方案更主流Dashboard不需要改造只需要在业务应用的sentinel.properties里配置csp.sentinel.dashboard.serverlocalhost:8858 csp.sentinel.datasource.nacos.nacos-serverlocalhost:8848 csp.sentinel.datasource.nacos.groupIdSENTINEL_GROUP csp.sentinel.datasource.nacos.dataId${spring.application.name}-flow-rules csp.sentinel.datasource.nacos.rule-typeflow我个人更推荐这个方案因为规则配置统一放到Nacos里被管理还能复用Nacos的权限控制比直接依赖MySQL可靠得多。但要注意用Nacos持久化时Dashboard本身只能看监控和手动推送规则规则实际存储发生在客户端与Nacos之间。如果你在控制台改了规则它会推给客户端客户端再写入Nacos相当于还是走了一遍客户端。所以控制台的nacos数据源插件也需要配置好否则控制台修改后客户端不认账。2.6 Docker网络规划所有容器统一放在一个自定义桥接网络里。Docker默认的bridge网络虽然也能用但容器间访问时DNS解析不稳定尤其是容器重启后IP变化依赖别名才能稳定连接。所以一定要自定义网络docker network create --driver bridge --subnet172.20.0.0/24 --gateway172.20.0.1 microservices-net在docker-compose里声明外部网络networks: default: external: name: microservices-net这样所有容器都可以用服务名访问彼此比如mysql-server:3306、nacos-node1:8848。对外只需要暴露少量端口内部通信全部走容器网络既安全又稳定。3. 实操部署过程与核心环节实现3.1 Nacos集群部署实操我建议先单独部署Nacos确认集群健康后再往下走。三节点部署使用同一套镜像但通过环境变量区分身份。创建nacos-cluster目录编写docker-compose.yml。每个节点的配置用YAML气道语法定义容器名称、端口和NACOS_SERVERS依次组合。我实际启动时用了docker compose up -d nacos-node1 nacos-node2 nacos-node3。启动后立即查看日志docker logs -f nacos-node1日志里出现The Nacos cluster node successfully joined这类关键词说明节点加入成功。然后访问任意节点控制台http://node1:8848/nacos默认用户名密码都是nacos。登录后进入“集群管理-节点列表”应该能看到三个节点状态为UP。如果只有一个节点多半是NACOS_SERVERS格式或9849端口不通。检查防火墙是否放行9849端口宿主机间需要开放TCP 8848、9848、9849。这里有一个值得说的细节Nacos集群模式下的健康检查不仅检查8848还检查9849之间的心跳。如果你用的云服务器安全组只开了8848节点永远看不到彼此。我第一遍部署时就是忘了放行9849结果三台机器各自为战互相隔离。3.2 将Nacos配置导入Nacos集群启动后把Seata、Sentinel以及业务服务需要的配置写到Nacos里。我建议通过控制台页面手工添加也可以调用Open API批量导入但要注意Open API写入配置时会自动创建历史版本后期追踪变更很方便。以Seata为例在Nacos控制台里新建命名空间seata-config然后在配置列表里手动创建以下配置项Data ID说明service.vgroupMapping.summer_tx_group事务分组到TC集群映射默认值defaultstore.mode设置为dbstore.db.urlJDBC连接串store.db.user数据库账号store.db.password数据库密码transport.type通信方式保持默认TCPservice.enableDegrade降级开关false这些配置如果不放到Nacos里Seata启动时会报can not get config from registry。这是Seata 1.6以后最常见的启动错误。配置内容里有一个容易忽略的项config.txt里的store.db.driverClassName在MySQL 8.0下需要写成com.mysql.cj.jdbc.Driver不是com.mysql.jdbc.Driver。如果写错驱动类Seata启动会报ClassNotFoundException。很多教程里还是老驱动类名照抄必挂。3.3 Seata集群部署实操Seata集群我这里部署了两个节点。两个节点使用同一事务组在Nacos中的服务列表里会同时存在两个实例。业务客户端基于Seata的负载均衡策略选择其中一个。Seata节点启动顺序要注意一定在MySQL和Nacos都健康之后。所以compose文件里加上健康检查mysql-server: healthcheck: test: [CMD, mysqladmin, ping, -h, 127.0.0.1, -uroot, -pRoot123456] interval: 10s timeout: 5s retries: 5然后Seata依赖它depends_on: mysql-server: condition: service_healthy启动Seata后观察日志里的关键行The server started successfully. Register to Nacos successfully.再通过一个测试微服务调用Seata的io.seata.sample接口如果事务成功提交且回滚正常说明TC工作正常。如果一直卡在“未找到全局事务”之类的状态优先检查vgroupMapping的配置是否指向了正确的TC集群名。双节点Seata下我还要验证一个事杀掉其中一个Seata容器看业务是否自动切换到另一个节点。实测下来Seata客户端会在下一次获取TC地址时自动剔除故障实例但正在执行中的事务会因为TC切换而失败。这要求你的业务代码做好事务重试或手动补偿属于分布式事务的既有代价。另外Seata节点间的数据一致性问题1.6.1默认的DB模式并没有内建多节点事务会话同步。也就是说节点A写入的全局锁在节点B查不到。我为了解决这个问题引入了基于数据库的全局锁方案保证所有分支事务对应的业务表主键锁记录在同一个数据库里这样多TC节点共享同一份数据不会发生锁记录丢失。如果你的团队没有额外做补偿机制建议先单Seata节点跑稳定后再上双节点否则数据一致风险会扩大。3.4 Sentinel Dashboard部署与持久化规则打通Sentinel控制台本身不参与业务链路部署相对轻量。我在宿主机上跑一个容器docker run -d \ --name sentinel-dashboard \ -p 8858:8858 \ -e TZAsia/Shanghai \ --network microservices-net \ -v /data/sentinel/logs:/logs \ bladex/sentinel-dashboard:1.8.6默认账号密码是sentinel/sentinel。登录后可以看到所有接入Sentinel的应用列表。为了让规则能通过Nacos持久化业务服务在启动时读取Nacos中的规则。这一步其实不依赖Dashboard而是客户端的数据源配置。以Spring Cloud应用为例在application.yml里加spring: cloud: sentinel: transport: dashboard: sentinel-dashboard:8858 port: 8719 datasource: flow: nacos: server-addr: nacos-node1:8848,nacos-node2:8848,nacos-node3:8848 dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP >version: 3.8 networks: default: external: name: microservices-net services: mysql-server: image: mysql:8.0.32 container_name: mysql-server restart: always ports: - 3306:3306 environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: Root123456 MYSQL_CHARACTER_SET: utf8mb4 MYSQL_COLLATION: utf8mb4_unicode_ci volumes: - /data/mysql:/var/lib/mysql - /data/mysql-init:/docker-entrypoint-initdb.d:ro healthcheck: test: [CMD, mysqladmin, ping, -h, 127.0.0.1, -uroot, -pRoot123456] interval: 10s timeout: 5s retries: 10 nacos-node1: image: nacos/nacos-server:v2.2.3 container_name: nacos-node1 env_file: ./nacos-node1.env ports: - 8848:8848 - 9848:9848 - 9849:9849 volumes: - /data/nacos-node1/logs:/home/nacos/logs depends_on: mysql-server: condition: service_healthy nacos-node2: image: nacos/nacos-server:v2.2.3 container_name: nacos-node2 env_file: ./nacos-node2.env ports: - 8849:8848 - 9850:9848 - 9851:9849 volumes: - /data/nacos-node2/logs:/home/nacos/logs depends_on: mysql-server: condition: service_healthy seata-node1: image: seataio/seata-server:1.6.1 container_name: seata-node1 ports: - 8091:8091 environment: SEATA_IP: seata-node1 SEATA_PORT: 8091 SEATA_REGISTRY_NACOS_SERVER_ADDR: nacos-node1:8848,nacos-node2:8848,nacos-node3:8848 SEATA_CONFIG_NACOS_SERVER_ADDR: nacos-node1:8848,nacos-node2:8848,nacos-node3:8848 STORE_MODE: db STORE_DB_URL: jdbc:mysql://mysql-server:3306/seata_transaction?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue STORE_DB_USER: seata STORE_DB_PASSWORD: Seata123456 depends_on: mysql-server: condition: service_healthy nacos-node1: condition: service_started sentinel-dashboard: image: bladex/sentinel-dashboard:1.8.6 container_name: sentinel-dashboard ports: - 8858:8858 environment: TZ: Asia/Shanghai volumes: - /data/sentinel/logs:/logs如果你用nacos-node2映射8849到内部8848的方式要注意服务注册时暴露的地址。尽量在应用侧使用nacos-node1:8848等容器DNS名称外部通过宿主机IP访问时再走映射端口。不然内部地址和外部地址混淆容易注册错地址。4. 常见问题与排查技巧实录4.1 Nacos集群节点互相隔离只有本机UP这是最普遍的问题。现象是三个Nacos控制台都能打开但节点列表孤单一只。排查步骤确认三个节点能互相ping通确认宿主机的9849端口开放telnet node2 9849测试检查NACOS_SERVERS环境变量格式一定是英文逗号分隔逗号前后不要有空格查看日志中是否有Unable to connect to server关键字如果用了云服务器安全组务必放行8848、9848、9849三个端口不要只放8848。还有一个隐蔽点Nacos节点间的JRaft通信还会用到raft目录下生成的元数据文件。如果你挂载了持久化目录但目录权限不对节点会报Failed to create lock file。解决办法是给目录赋权和chown -R nacos:nacos。4.2 Seata启动成功却报“无法从Nacos获取配置”这个错误很典型。Seata启动时不直接读本地文件而是先从注册中心拉取配置。如果config.txt没有上传到Nacos或者Data ID不匹配启动日志里会有Failed to get server config from registry解决办法是在Nacos里手动创建配置并把service.vgroupMapping等信息补齐。注意group要一致Seata默认是SEATA_GROUP如果业务侧自定义了group必须全部对齐。还有一次我发现Seata报错“Illegal character in path”原因是Nacos里某个Data ID里包含特殊字符比如store.db.url中符号被URL编码。解决方法是配置时用完整的字符不要被解析成参数分隔。4.3 业务服务连不上Seata注册地址是容器ID业务日志里会看到类似can not connect to 169.17.0.5:8091这个IP是Seata容器在Docker网络里的IP表面上看起来没问题但业务服务如果不在同一网络内就永远连不上。这是因为SEATA_IP没有设置。在docker-compose里为Seata设置SEATA_IP为宿主机内网IP或者直接用容器名seata-node1并让业务服务和Seata在同一Docker网络。如果你有多个Seata节点每个节点的SEATA_IP必须不同并且能被业务服务网络路由到。我们曾经踩过两个节点共用同一个IP的坑结果所有请求被路由到一个节点上另一个节点永远空闲节点状态还一直显示异常。4.4 Sentinel控制台看不到某台机器Sentinel客户端随机端口默认是8719。如果业务容器端口占用或防火墙拦截客户端与Dashboard之间的心跳会失败。检查客户端日志看有没有“Failed to send heartbeat”字样。端口冲突情况下客户端会自动加1重试所以偶尔能看到业务容器虽然开着但Sentinel列表里没有。解决办法是显式指定端口spring: cloud: sentinel: transport: port: 18720同时确保业务服务所在容器能访问Dashboard的8858端口。如果是Kubernetes环境还要注意Pod IP漂移问题最好用Service域名配置Dashboard地址。4.5 规则推送后不生效出现这个问题的常见原因有三个客户端和Dashboard版本不匹配推送的规则格式理解不一致规则推给了客户端但没有持久化到Nacos客户端重启后丢失规则数据源配置了Nacos但groupId、dataId与控制台不一致。排查时先在客户端日志中查看是否有规则推送记录。然后进入Nacos控制台查看对应的Data ID下是否已经有规则内容。如果Nacos里有规则但客户端不加载多半是>deploy: resources: limits: memory: 1024M reservations: memory: 512M同时在启动参数里设置JVM堆大小。Nacos可以通过JVM_XMS、JVM_XMX、JVM_XMN环境变量控制Seata可以通过JAVA_OPTS传JAVA_OPTS: -Xms512m -Xmx1024m堆设太大反而会浪费内存太小则GC频繁。我测试下来Nacos每个节点512M堆可以支撑几十个服务注册Seata默认256M不够遇到高并发事务时会频繁Full GC要升到512M以上。容器内存限额不要等于堆大小要留出Metaspace和线程栈的空间。比如堆512M容器内存限制给1G比较稳。否则容易触发OOM Killer。5.2 日志滚动与磁盘保护Java应用跑集群日志增长非常快。如果日志目录不做滚动一段时间后磁盘满Nacos直接写入失败。我建议在宿主机上配置logrotate以Nacos日志目录为例cat /etc/logrotate.d/nacos EOF /data/nacos-node1/logs/*.log { daily rotate 14 copytruncate compress delaycompress missingok notifempty } EOF同样配置Seata和Sentinel日志。如果业务量很大日志保留超过两周意义不大排查问题一般就在最近几天。5.3 定期备份MySQL与配置整个集群的“真相”都在MySQL里。Nacos配置、Seata会话记录、Sentinel规则全在库里。我每周自动备份一次全量库每天增量binlog备份。备份策略很简单mysqldump -uroot -pRoot123456 --all-databases --master-data2 /backup/all_$(date %F).sql恢复时只要MySQL可用Nacos、Seata、Sentinel启动后都能从库里读到历史数据。但不能只备份数据库Nacos的namespace和配置组信息也需要同步导出一份YAML或者JSON方便在外置配置丢失时快速重建。5.4 监控告警配置部署完集群不要以为就结束了。至少要对这几个指标做监控Nacos节点的健康状态任意一个DOWN都要告警Seata的活跃事务数、回滚事务数Sentinel的拒绝QPS和规则命中次数MySQL的连接数、主从复制延迟。我这次用Prometheus加Grafana做监控这套可以写在另一篇博文里但这次直接用传统方式Nacos暴露了Metrics接口Seata也自带Prometheus端点Sentinel控制台提供HTTP API。把它们都接到告警里能在用户感知之前发现问题。关于告警阈值Nacos节点低于3台就要告警Seata如果活跃事务数超过100且时长超过30秒可能是事务卡死Sentinel拒绝率如果持续上升说明有人在打你的接口或者服务容量不足。这些阈值要结合业务压测结果来定不建议照抄网上的模板。5.5 升级与回滚注意事项组件升级是生产环境最需要谨慎的操作。Nacos 1.x升2.x因为端口多了9848/9849很多防火墙规则要提前调整。Seata升级要确保配置文件格式兼容否则启动即崩溃。Sentinel版本升级尤其要小心客户端与Dashboard的版本匹配。我建议升级前先做全量备份然后在模拟环境完整演练一次包括“业务服务接入、规则下发、故障切换”三个环节。升级完成后再观察一两天不要马上把旧版本镜像删掉。回滚方案也要预演。比如Seata如果升级后出现问题最稳妥的方式是切回旧镜像但因为Nacos里的配置可能已经被新版本改写回滚后不一定能正常读取。所以升级前要把Nacos配置也做好版本快照。6. 个人踩坑总结与避坑清单我把这轮部署里最值得记住的经验写成一个清单给后面部署的同行们少走弯路坑点后果解决方案Nacos只映射8848端口配置推送、服务订阅异常同时映射9848、9849Nacos节点列表互相隔离集群实际不可用放行9849检查NACOS_SERVERS格式Seata未设置SEATA_IP业务连不上TC显式设置宿主机可达IP或容器名Seata config.txt未导入Nacos启动报错在Nacos里逐项创建配置Sentinel无持久化重启规则丢失接入Nacos数据源/MySQL持久化MySQL8连接报公钥检索错误偶发连接失败JDBC参数附加allowPublicKeyRetrievaltrueDocker重启导致重复注册流量打到死实例优雅停机延长心跳超时JVM参数与容器限额不匹配OOM或GC频繁预留堆外内存空间这四条是共性问题里最高频的几乎每个新环境部署都会遇到其中一两个。我在一开始部署时也把这些坑一个个踩完才总结出来。如果是照着官方文档直接干很容易卡在这些细节上几天时间。最后再分享一个小技巧部署三套组件时不要一次性全部启动。先把Nacos和MySQL跑通注册中心健康后再上Seata最后才接Sentinel。这样问题定位会清晰得多因为有的时候Seata启动失败不是Seata自身的问题而是Nacos里配置缺失。逐层递进虽然慢但成功率最高。我后来在实际项目里还会在Nacos中给每个环境建一个独立的命名空间比如dev、test、prodNacos集群在不同命名空间下可以完全隔离配置但共用同一套基础设施。这样一套Docker集群可以复用于多环境大大减少资源浪费。你可以在这次部署完成后继续沿着这个方向扩展。