ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Nacos生产级集群部署实战:注册中心与配置中心一体化落地指南

Nacos生产级集群部署实战:注册中心与配置中心一体化落地指南

1. 为什么注册中心与配置中心要放在同一套 Nacos 里

很多团队在微服务起步阶段会走一条"经典弯路":注册中心用 Eureka,配置中心用 Spring Cloud Config 加 Git 仓库,再配一套消息总线做配置刷新。这套组合能跑,但运维成本高得离谱——Eureka 2.x 停止维护后社区信心崩塌,Config 的配置刷新依赖消息中间件,链路一长,出问题排查起来像剥洋葱。我见过一个六人小组,光维护这三套组件的版本兼容就耗掉了将近三分之一的人力。

Nacos 的价值就在于把服务注册发现和动态配置管理这两件事收进同一个控制台、同一套鉴权、同一份集群部署里。它同时支持 AP 和 CP 两种一致性模式:临时实例走 AP,靠心跳保活,适合大多数无状态服务;持久化实例走 CP,基于 Raft 协议,适合对一致性要求高的场景。这个设计不是拍脑袋来的,而是把"服务发现"和"配置管理"两类需求的本质差异想清楚了——服务列表可以短暂不一致,但配置数据不能乱。

这篇文章面向的是已经写过 Spring Cloud 项目、但对 Nacos 生产级部署还没底的人。我会从单机验证讲到集群搭建,从命名空间隔离讲到配置热更新,把每一步的"为什么"讲透。你跟着走一遍,能拿到一套可以直接改改就上预发环境的方案。

提示:本文所有 IP、端口、命名均为示例,实际部署时请替换为你自己的规划。生产环境务必开启鉴权,不要裸奔。

2. Nacos 的部署形态选择:单机模式与集群模式的分水岭

2.1 单机模式到底能扛多少量

Nacos 单机模式(standalone)默认使用内嵌的 Derby 数据库,数据存在本地文件里。这个模式启动快、零依赖,适合开发联调和功能验证。但它有两个硬伤:一是 Derby 不支持集群,多个节点之间数据不共享;二是单点故障,进程挂了整个注册中心就没了。

那单机模式能扛多少服务实例?根据我实际压测的经验,在 4 核 8G 的机器上,单机 Nacos 支撑 500 到 800 个服务实例的注册与心跳维持是没问题的,配置读取的 QPS 能到几千。但这是"能跑"的极限,不是"该跑"的舒适区。一旦实例数超过 1000,心跳续约的请求量会让 GC 压力明显上升,控制台操作也会变卡。

所以我的建议很明确:开发环境用单机,预发和生产必须上集群。不要心存侥幸觉得"我们服务不多,单机够了"——注册中心是微服务的地基,地基塌了上面全完。

2.2 集群模式的最小可用配置

Nacos 集群模式要求至少 3 个节点,这是 Raft 协议选举多数派的最低要求。2 个节点不行,因为无法形成多数派,一个节点挂了整个集群就不可写。3 个节点能容忍 1 个节点故障,5 个节点能容忍 2 个,但节点越多,Raft 的写性能越低,因为每次写都要同步到多数节点。

对于大多数中小规模团队,3 节点集群是性价比最高的选择。每个节点的配置建议不低于 4 核 8G,磁盘用 SSD,因为 Nacos 的持久化实例和配置数据都要落盘。网络方面,三个节点最好在同一个内网网段,跨机房部署会引入额外的网络延迟,影响 Raft 的心跳和选举。

集群模式必须使用外部数据库,官方推荐 MySQL 5.7 或 8.0。这里有个容易踩的坑:MySQL 的字符集必须是 utf8mb4,否则配置内容里有特殊字符时会插入失败。还有,数据库连接池的配置要调,默认的 HikariCP 连接数在集群高并发下可能不够,建议把db.pool.config.maximumPoolSize调到 50 以上。

2.3 数据库初始化:别跳过这一步

Nacos 集群依赖外部 MySQL,所以第一步是把建表脚本导入。脚本在 Nacos 安装包的conf目录下,叫mysql-schema.sql。这个脚本会创建十几张表,核心的有config_info(配置信息)、config_info_beta(灰度配置)、his_config_info(配置历史)、tenant_info(命名空间信息)等。

导入脚本时有个细节:先建库再导表,库名建议用nacos_config,字符集选 utf8mb4,排序规则选 utf8mb4_general_ci。我遇到过有人用默认的 latin1 建库,结果配置里写中文注释全变问号,排查了半天才发现是字符集问题。

导入完成后,检查一下config_info表是否存在,以及tenant_info表是否为空。如果tenant_info里有数据,说明之前有人用过这个库,需要清理干净再部署,否则命名空间 ID 会冲突。

3. 从零搭建三节点 Nacos 集群的完整操作链路

3.1 环境准备与安装包处理

假设你有三台内网机器,IP 分别是 192.168.1.101、192.168.1.102、192.168.1.103,操作系统是常见的 Linux 发行版。先确认三台机器都装了 JDK 8 或 JDK 11,Nacos 2.x 推荐 JDK 8 以上,JDK 17 也支持但需要额外配置启动参数。

下载 Nacos 安装包后,解压到统一目录,比如/opt/nacos。三台机器都要做同样的操作。解压后目录结构里,bin放启动脚本,conf放配置文件,target放 jar 包,logs是日志目录。

这里有个经验:不要把 Nacos 装在系统盘根目录或/tmp下,因为日志会持续增长,系统盘满了会引发一连串诡异问题。单独挂一块数据盘,把 Nacos 和 MySQL 的数据都放上去,运维起来省心很多。

3.2 集群配置文件 cluster.conf 的正确写法

进入conf目录,找到cluster.conf.example,复制一份改名为cluster.conf。这个文件里写的是集群所有节点的地址,格式是IP:端口,每行一个。注意,这里必须写 IP,不能写 localhost 或 127.0.0.1,否则节点之间无法互相发现。

192.168.1.101:8848 192.168.1.102:8848 192.168.1.103:8848

三台机器的cluster.conf内容必须完全一致。我见过有人只在主节点配了完整的列表,从节点只写了自己,结果集群一直选不出 Leader,控制台显示节点列表残缺。这个文件的同步是手工的,部署脚本里最好加一步校验,确保三台机器内容一致。

3.3 application.properties 的关键参数调优

conf/application.properties是 Nacos 的核心配置文件。集群模式下,必须修改以下几项:

# 数据库配置 spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://192.168.1.200:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai db.user.0=nacos db.password.0=你的密码 # 集群端口 server.port=8848 # 鉴权开关(生产必须开启) nacos.core.auth.enabled=true nacos.core.auth.server.identity.key=你的自定义key nacos.core.auth.server.identity.value=你的自定义value nacos.core.auth.plugin.nacos.token.secret.key=你的Base64密钥

db.url里的serverTimezone一定要设,否则 MySQL 8.0 会报时区错误。useSSL=false在内网环境可以关掉,减少握手开销。鉴权相关的三个参数是 Nacos 2.2 之后的新要求,token.secret.key必须是 Base64 编码的字符串,长度有要求,太短会启动失败。

注意:nacos.core.auth.server.identity.key和value是服务端之间通信的凭证,集群内所有节点必须一致。这个值泄露了等于鉴权形同虚设,所以不要用默认值,也不要用弱口令。

3.4 启动顺序与健康检查

三台机器配置完成后,依次启动。启动命令在bin目录下:

sh startup.sh -m cluster

-m cluster表示集群模式,不加这个参数默认是单机模式,会去连 Derby 而不是 MySQL。启动后看logs/start.out,如果看到 "Nacos started successfully in cluster mode" 就说明起来了。

三个节点都启动后,打开浏览器访问任意一个节点的http://IP:8848/nacos,用默认账号 nacos/nacos 登录(如果开了鉴权,第一次登录会要求改密码)。进入"集群管理"页面,应该能看到三个节点都是 UP 状态,Leader 只有一个。

如果某个节点显示 DOWN,先检查它的cluster.conf是否和其他节点一致,再检查防火墙是否放行了 8848 端口以及节点间通信的端口。Nacos 2.x 除了 8848,还用了 9848 和 9849 做 gRPC 通信,这两个端口也要放行。很多人只开了 8848,结果节点间心跳不通,集群一直不稳定。

4. Spring Cloud 服务接入 Nacos 的依赖与配置细节

4.1 版本对齐:Spring Cloud Alibaba 的坑

Spring Cloud Alibaba 的版本和 Spring Boot、Spring Cloud 有严格的对应关系。选错版本,启动时各种NoSuchMethodError和ClassNotFoundException会让你怀疑人生。下面这张表是我整理过的常用组合:

Spring BootSpring CloudSpring Cloud AlibabaNacos 客户端
2.3.xHoxton.SR92.2.6.RELEASE1.4.x
2.4.x2020.0.12021.11.4.x
2.6.x2021.0.12021.0.4.02.x
2.7.x2021.0.52021.0.5.02.x
3.0.x2022.0.12022.0.0.02.x

选版本的原则是:优先用 Spring Cloud Alibaba 官方文档里标注的推荐组合,不要自己乱配。如果项目已经用了某个 Spring Boot 版本,就去查对应的 Alibaba 版本,而不是反过来。

4.2 服务注册的配置项逐条解读

在pom.xml里引入依赖:

<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>

然后在bootstrap.yml(注意是 bootstrap 不是 application)里配置:

spring: application: name: order-service cloud: nacos: discovery: server-addr: 192.168.1.101:8848,192.168.1.102:8848,192.168.1.103:8848 namespace: dev group: DEFAULT_GROUP username: nacos password: 你的密码 ephemeral: true config: server-addr: ${spring.cloud.nacos.discovery.server-addr} namespace: ${spring.cloud.nacos.discovery.namespace} group: DEFAULT_GROUP file-extension: yaml username: ${spring.cloud.nacos.discovery.username} password: ${spring.cloud.nacos.discovery.password}

几个关键点:server-addr写多个地址用逗号分隔,客户端会轮询,一个节点挂了自动切到下一个。namespace用来做环境隔离,dev、test、prod 各一个命名空间,互不干扰。ephemeral: true表示临时实例,走 AP 模式,服务下线后自动摘除;如果设成 false,就是持久化实例,需要手动下线。

file-extension指定配置文件的后缀,Nacos 里配置的 Data ID 默认拼接规则是${spring.application.name}-${profile}.${file-extension}。比如 order-service 在 dev 环境下,会去找order-service-dev.yaml这个配置。

4.3 启动类注解与自动装配

启动类上加@EnableDiscoveryClient注解。虽然 Spring Cloud 新版里这个注解可以省略(自动装配会处理),但显式加上更清晰,也避免某些版本下自动装配失效的问题。

启动服务后,去 Nacos 控制台的"服务管理-服务列表"里看,应该能看到 order-service 这个服务,实例数是 1,健康状态是 true。如果看不到,先检查bootstrap.yml是否被加载了——Spring Boot 2.4 之后 bootstrap 默认不启用,需要引入spring-cloud-starter-bootstrap依赖,或者在application.yml里加spring.cloud.bootstrap.enabled=true。

这个坑我踩过:项目从 Spring Boot 2.3 升到 2.6,配置突然不生效了,查了半天才发现是 bootstrap 上下文没启动。所以升级 Spring Boot 版本时,一定要检查这个配置。

5. 配置中心实战:Data ID 规则、热更新与灰度发布

5.1 Data ID 的拼接逻辑与多环境管理

Nacos 配置的 Data ID 不是随便起的,它有一套拼接规则。默认情况下,Spring Cloud Alibaba 会按以下顺序查找配置:

  1. ${prefix}-${profile}.${file-extension}
  2. ${prefix}.${file-extension}
  3. ${prefix}

其中prefix默认是spring.application.name,profile是spring.profiles.active。比如应用名是 order-service,激活的 profile 是 dev,文件后缀是 yaml,那么它会先找order-service-dev.yaml,找不到再找order-service.yaml。

这个规则的好处是:公共配置放order-service.yaml,环境差异放order-service-dev.yaml。数据库连接、第三方密钥这类每个环境不同的配置放带 profile 的文件里,日志级别、线程池大小这类通用的放不带 profile 的文件里。

你还可以通过spring.cloud.nacos.config.prefix自定义前缀,或者用shared-configs和extension-configs引入共享配置。比如多个服务共用的 Redis 配置,可以单独建一个common-redis.yaml,然后在每个服务的配置里引用它。

5.2 @RefreshScope 与配置热更新的边界

配置热更新的核心是@RefreshScope注解。加了这个注解的 Bean,在 Nacos 配置变更后会被重新创建,从而拿到新的配置值。但这里有几个边界要注意:

第一,@RefreshScope只对 Spring 管理的 Bean 生效。你自己new出来的对象,或者静态变量,不会自动刷新。第二,@Value注入的配置能刷新,但@ConfigurationProperties需要配合@RefreshScope或者@EnableConfigurationProperties才能刷新。第三,刷新是有延迟的,Nacos 客户端默认长轮询超时是 30 秒,也就是说配置变更后最多 30 秒生效。

我见过有人把数据库连接池的配置放在 Nacos 里,期望改了之后连接池自动重建。这个想法很危险——连接池重建会导致正在处理的请求失败。不是所有配置都适合热更新,像连接池大小、线程池核心数这类,改了之后需要重启才稳妥。

5.3 灰度发布:用 beta 配置做小范围验证

Nacos 支持配置的灰度发布,也就是 beta 发布。你可以在控制台里对某个配置点"编辑",然后勾选"Beta 发布",指定哪些 IP 的实例能拿到这个新配置。这样你可以先让一台机器用新配置跑一段时间,观察没问题再全量推送。

这个功能在改关键配置时特别有用。比如你要调整某个服务的限流阈值,直接全量推可能引发雪崩,用 beta 发布先在一台机器上验证,风险可控得多。

beta 发布的配置存在config_info_beta表里,和正式配置分开。验证完成后,点"发布"会把 beta 配置合并到正式配置,同时删除 beta 记录。注意,beta 配置的 IP 列表是精确匹配的,不支持网段,所以如果实例 IP 会变(比如容器环境),这个功能用起来会有点麻烦。

6. 生产环境必须处理的几个运维问题

6.1 鉴权开启后客户端如何配置

生产环境必须开启鉴权,否则任何人都能往注册中心里注册服务、改配置,这是重大安全隐患。开启鉴权后,客户端连接 Nacos 需要提供用户名和密码,就是前面配置里的username和password。

但这里有个细节:Nacos 的鉴权是基于 token 的,token 有有效期。客户端会自动续期,但如果服务长时间不重启,token 过期后可能会连接失败。解决办法是在客户端配置里加上nacos.core.auth.plugin.nacos.token.secret.key对应的密钥,让客户端能自己生成 token。不过更稳妥的做法是定期滚动重启服务,或者用 Nacos 提供的 SDK 做健康检查。

另外,开启鉴权后,Nacos 控制台的默认密码一定要改。我见过有人开了鉴权但没改默认密码,等于没开。改密码在控制台的"权限控制-用户管理"里操作,改完后所有客户端配置也要同步更新。

6.2 监控指标与告警配置

Nacos 暴露了 Prometheus 格式的监控指标,路径是/nacos/actuator/prometheus。关键指标包括:

  • nacos_monitor{name="configCount"}:配置数量
  • nacos_monitor{name="serviceCount"}:服务数量
  • nacos_monitor{name="instanceCount"}:实例数量
  • nacos_monitor{name="longPolling"}:长轮询连接数
  • nacos_monitor{name="raftNotifyTask"}:Raft 通知任务数

其中longPolling和raftNotifyTask最值得关注。长轮询连接数过高说明客户端配置监听太多,可能需要优化;Raft 通知任务积压说明集群内部通信有问题,可能是网络延迟或节点负载过高。

告警规则建议设三条:实例数突降超过 30% 告警(可能是服务大面积掉线)、长轮询连接数超过阈值告警(可能是配置监听泄漏)、Raft 通知任务持续大于 100 告警(集群可能不稳定)。

6.3 数据备份与恢复策略

Nacos 的数据分两部分:配置数据在 MySQL 里,服务注册数据在内存和本地磁盘里。配置数据是核心资产,必须定期备份。最简单的办法是写个脚本,每天凌晨用mysqldump导出nacos_config库,保留最近 30 天。

服务注册数据不需要备份,因为服务重启后会自动重新注册。但命名空间、分组这些元数据在 MySQL 里,会跟着配置数据一起备份。

恢复的时候,先停掉所有 Nacos 节点,导入 MySQL 备份,再启动节点。注意,恢复时三台机器的cluster.conf和application.properties必须和备份时一致,否则可能出现数据不一致。我建议把这两个文件也纳入版本管理,每次变更都记录。

7. 几个真实踩过的坑与排查思路

7.1 服务注册上了但调用不通

这个问题的表现是:Nacos 控制台能看到服务实例,但 Feign 或 RestTemplate 调用时报 "No instances available"。排查思路分三步:

第一步,检查消费者的server-addr是否和提供者一致。如果消费者连的是另一个 Nacos 集群,或者命名空间不同,自然找不到服务。第二步,检查分组(group)是否一致。默认都是 DEFAULT_GROUP,但如果有人改了,两边对不上就找不到。第三步,检查实例的ephemeral设置。如果提供者是持久化实例,消费者是临时实例,在某些版本下会有兼容问题。

我遇到过一次,是因为消费者的spring.cloud.nacos.discovery.namespace写成了命名空间名称而不是 ID。Nacos 的命名空间在 API 层面用的是 ID,控制台显示的是名称,这两个不是一回事。配置里必须写 ID,写名称会找不到。

7.2 配置修改后不生效

配置改了但服务没反应,先确认三件事:配置的 Data ID 是否匹配、@RefreshScope是否加了、配置格式是否正确。Data ID 匹配问题前面讲过,这里说格式问题。

Nacos 的配置内容如果是 YAML,缩进必须严格正确。我见过有人从别处复制配置,缩进用了 Tab 和空格混用,YAML 解析失败,但 Nacos 控制台不报错,客户端也静默失败。排查这种问题,可以在客户端加日志级别logging.level.com.alibaba.nacos=DEBUG,看它拉取配置的详细过程。

还有一个隐蔽的坑:如果配置内容为空,或者只有注释,Nacos 会认为这个配置不存在,客户端拿不到。所以哪怕暂时不用某个配置,也至少写一个占位符。

7.3 集群节点频繁掉线又恢复

集群节点状态在 UP 和 DOWN 之间反复横跳,通常是网络问题或负载问题。先看 Nacos 的logs/naming-server.log,里面会记录节点心跳超时的日志。如果超时时间很短(比如几百毫秒),说明网络抖动严重,需要检查交换机、网卡或容器网络。

如果网络没问题,就看节点的 CPU 和内存。Nacos 的 Raft 选举对 CPU 敏感,如果节点 CPU 长期跑满,心跳处理不及时,就会被判定为下线。这种情况要么升配,要么减少节点上的服务实例数。

还有一个可能是系统时间不同步。Raft 协议依赖时间戳,如果三台机器的时间差超过几秒,选举会出问题。部署前务必用 NTP 同步三台机器的时间,这是很多团队容易忽略的基础工作。

8. 我个人的部署清单与经验沉淀

每次部署 Nacos 集群,我都会过一遍下面这个清单,能避开九成以上的问题:

  • 三台机器时间同步(NTP)
  • MySQL 字符集 utf8mb4,建库脚本已导入
  • cluster.conf三台一致,写 IP 不写 localhost
  • application.properties中数据库、鉴权、端口配置正确
  • 防火墙放行 8848、9848、9849 端口
  • 启动顺序:先 MySQL,再 Nacos 节点
  • 启动后检查集群管理页面,三节点 UP,一个 Leader
  • 客户端bootstrap.yml配置正确,bootstrap 上下文已启用
  • 鉴权开启后,默认密码已修改
  • Prometheus 监控已接入,告警规则已配置
  • MySQL 备份脚本已加入定时任务

关于版本选择,我的经验是:不要追最新版。Nacos 2.x 早期版本有过几次集群不稳定的问题,后来在 2.2.x 之后才稳定下来。Spring Cloud Alibaba 也是,新版本发布后等一两个小版本再上,让社区先踩踩坑。生产环境求稳,不是求新。

最后说一个容易被忽视的点:Nacos 的日志会一直增长,logs目录下的naming-server.log和config-server.log尤其大。一定要配置日志轮转,否则磁盘满了会导致 Nacos 写日志失败,进而引发各种诡异问题。我一般用 logrotate 每天切割,保留 7 天,这个配置在conf目录下可以调整。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进