1. 项目概述:为什么必须从Nacos 1.3升级到2.3?
最近在梳理手头的几个微服务项目,发现一个历史遗留问题:好几个项目的配置中心和注册中心还在用Nacos 1.3.2版本。这个版本是2020年发布的,虽然稳定,但已经落后主流社区好几个大版本了。正好趁着一次服务器迁移的机会,我决定把生产环境的Nacos集群从1.3.2一次性升级到最新的2.3.0版本。这个决定不是一时兴起,而是基于几个现实的痛点:首先是社区支持,老版本遇到问题,官方基本不再提供修复;其次是功能缺失,像服务网格集成、更完善的鉴权体系、性能更好的长连接模型,这些在1.x时代要么没有,要么是实验特性;最后是安全风险,老版本可能存在一些已知但未修复的漏洞。
这次升级不是简单的替换JAR包,它涉及到架构模型的根本性变化。Nacos 2.x版本引入了gRPC和RSocket,用于替代1.x中基于HTTP和UDP的服务发现与配置推送通道,这带来了更高的性能和更低的延迟,但同时也意味着客户端和服务端都需要适配。如果你的系统像我的一样,包含了Spring Boot、Spring Cloud Alibaba、Dubbo等多种技术栈,那么升级就需要一个周全的计划。本文将详细记录我从Nacos 1.3.2升级到2.3.0的全过程,包括升级策略选择、详细的操作步骤、客户端适配、以及升级过程中踩过的坑和解决方案,希望能为有类似需求的同行提供一个可靠的参考。
2. 升级前的深度评估与准备工作
在动手之前,盲目操作是运维大忌。升级Nacos,尤其是跨越大版本,必须对现有环境、依赖关系和潜在风险有清晰的认知。
2.1 环境与依赖盘点
首先,我列出了一个详细的清单,用于评估升级的影响范围:
服务端现状:
- 版本:Nacos Server 1.3.2
- 部署模式:3节点集群,采用内嵌Derby数据库(这是最需要警惕的点,后面会详细说)。
- 存储:配置文件约500个,注册服务实例约200个。
- 网络:集群节点间通过
8848端口通信,客户端通过VIP访问8848端口。
客户端现状:
- Spring Cloud Alibaba版本:大部分项目用的是
2.2.6.RELEASE,其默认集成的Nacos Client版本是1.4.2。 - Dubbo版本:部分服务使用Dubbo
2.7.x,通过dubbo-registry-nacos进行服务注册。 - 其他客户端:包括一些Python、Go的微服务,使用的是对应的Nacos SDK。
- Spring Cloud Alibaba版本:大部分项目用的是
配置内容检查:
- 检查是否有使用Nacos 1.x特有的参数或配置项,例如某些过时的监控端点或特定的集群配置。
- 特别注意
dataId和group的命名规范,确保没有使用特殊字符,避免在2.x的解析中出现问题。
2.2 关键决策:升级路径与数据迁移
这是升级的核心决策点。Nacos从1.x到2.x,数据存储格式和集群通信协议发生了重大变化。官方提供了两种主要方式:
- 平滑升级(推荐但复杂):搭建一个全新的Nacos 2.x集群,然后通过官方工具或手动导出导入的方式,将1.x集群的数据(配置和服务信息)迁移到新集群。最后将客户端指向新集群。这种方式服务中断时间短,风险相对可控,但操作步骤多。
- 原地升级(直接但风险高):在原有1.x集群的服务器上,直接替换Nacos的应用程序文件(JAR包或Docker镜像),然后启动2.x版本。这种方式依赖于Nacos内置的升级逻辑来兼容旧数据。
我的选择与理由: 我选择了平滑升级。原因如下:
- 数据安全:内嵌Derby数据库的数据文件(
~/nacos/data/derby-data)在跨大版本升级时,存在兼容性风险。官方文档也未对Derby的原地升级做强力保证。平滑升级允许我将数据先导出为明文(SQL或配置文件),这是一种更可靠的备份。 - 回滚便捷:如果新集群出现问题,我只需将客户端的连接地址改回老集群,瞬间就能回退,业务影响最小。原地升级一旦失败,回滚涉及数据降级,非常麻烦。
- 环境隔离:可以在新集群上充分测试,而完全不影响现有的生产流量。
注意:如果你使用的是外置MySQL数据库,并且版本在5.6.5以上,原地升级的风险会小很多,因为2.x版本兼容1.x的MySQL表结构。但即便如此,完整的备份仍然是第一步。
2.3 准备工作清单
在开始升级前,我完成了以下准备工作,建议你也逐一核对:
数据备份:
- 配置备份:使用Nacos 1.x的控制台或API,将所有配置(Data ID和Group)的详情页面手动截图存档,并利用
curl命令批量导出配置内容到本地文件。 - 数据库备份:如果使用MySQL,执行
mysqldump全量备份nacos数据库。如果使用内嵌Derby,则直接复制整个nacos/data和nacos/conf目录到安全位置。 - 服务列表备份:在控制台的服务列表页面截图,记录所有服务名及其集群信息。
- 配置备份:使用Nacos 1.x的控制台或API,将所有配置(Data ID和Group)的详情页面手动截图存档,并利用
客户端兼容性确认:
- Spring Cloud Alibaba:查阅官方版本说明,
2021.0.1.0(对应Spring Cloud 2021.0.x)及以上版本对Nacos 2.x的支持最好。我的2.2.6.RELEASE(对应SCA2.2.6.RELEASE)需要将Nacos Client升级到2.x版本,可能存在一些兼容性问题,需要测试。 - Nacos Client SDK:确保所有语言的客户端SDK版本支持连接Nacos 2.x服务器。Java的
nacos-client需要升级到2.x。
- Spring Cloud Alibaba:查阅官方版本说明,
新环境准备:
- 准备3台新的服务器(或容器),用于部署Nacos 2.3.0集群。硬件配置参考原有标准。
- 下载Nacos Server 2.3.0发布包(
nacos-server-2.3.0.tar.gz)并解压。 - 如果使用外置MySQL,在新环境中提前创建好数据库,并执行2.3.0发布包中
conf目录下的mysql-schema.sql文件初始化表结构。
制定操作时间窗口:与业务方沟通,确定一个低流量时段(例如凌晨)进行切换,并明确预计的中断时间(我的目标是5分钟内完成切换)。
3. 分步实施:搭建Nacos 2.3.0新集群
平滑升级的第一步是建立一个全新的、稳定的Nacos 2.3.0集群。
3.1 解压与基础配置
将下载的nacos-server-2.3.0.tar.gz上传到新服务器的/opt目录下并解压。
cd /opt tar -zxvf nacos-server-2.3.0.tar.gz cd nacos关键的配置文件是conf/application.properties。以下是我根据生产环境调整的核心配置:
# 指定服务器模式(集群/单机),这里必须为cluster spring.datasource.platform=mysql # 配置MySQL数据库连接,替换为你实际的数据库信息 db.num=1 db.url.0=jdbc:mysql://your-mysql-host:3306/nacos_config_2?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=nacos db.password.0=your_strong_password # 集群节点配置,这是2.x集群通信的关键 # 格式为 ip:port,其中端口偏移量1000和1001是固定的 nacos.core.cluster.members=192.168.1.101:8848,192.168.1.102:8848,192.168.1.103:8848 # 设置本机IP,不能使用127.0.0.1或localhost nacos.inetutils.ip-address=192.168.1.101 # 开启鉴权(生产环境强烈建议开启) nacos.core.auth.enabled=true nacos.core.auth.system.type=nacos nacos.core.auth.plugin.nacos.token.secret.key=YourSecretKey012345678901234567890123456789 # 2.x新增端口,用于gRPC通信,默认9848。如果服务器有防火墙,需开放此端口。 server.port=8848实操心得:
nacos.inetutils.ip-address这个配置非常关键。在云服务器或有多网卡的机器上,Nacos可能无法自动获取到正确的IP,导致集群节点间无法通信。务必手动设置为服务器对内的、其他节点可访问的IP地址。
3.2 集群节点配置与启动
Nacos 2.x的集群通信端口有变化,除了原有的8848(HTTP),还固定使用9848(gRPC)和9849(gRPC for raft)。因此,在每台服务器的conf目录下,需要编辑cluster.conf文件,明确列出所有集群节点的地址和9848端口。
cluster.conf内容示例(在三台服务器上内容一致):
192.168.1.101:9848 192.168.1.102:9848 192.168.1.103:9848配置完成后,分别在三台服务器上启动Nacos。启动顺序没有严格要求,但建议逐个启动,方便观察日志。
# 进入Nacos目录 cd /opt/nacos # 以集群模式启动 sh bin/startup.sh -m cluster启动后,立即查看日志,确认节点是否正常加入集群:
tail -f logs/start.out在日志中搜索关键词“Cluster”和“gRPC”,看到类似“Server is ready now. current cluster ips:”并列出所有配置的节点IP,以及“gRPC server started at port 9848”的日志,即表示集群启动成功。
3.3 验证新集群状态
- 控制台访问:在浏览器中访问任意节点的
http://192.168.1.101:8848/nacos。使用默认账号nacos/nacos登录(如果开启了鉴权,则需要用配置的密钥生成的Token或配置的账号密码)。 - 集群状态检查:在控制台顶部,点击“集群管理” -> “节点列表”。你应该能看到三个节点,且它们的状态都是“健康”。
- 端口检查:使用
netstat命令检查端口监听情况,确保8848、9848、9849、7848(用于Jraft)等端口都已正常监听。
至此,一个全新的、空白的Nacos 2.3.0生产集群已经就绪。
4. 数据迁移与客户端切换实战
这是升级过程中最核心、也最容易出错的环节。
4.1 从Nacos 1.3.2导出数据
由于我使用的是内嵌Derby,无法直接进行数据库层面的迁移。我采用了最稳妥的API导出方式。
导出配置列表:首先,获取所有配置的元数据。
curl -X GET "http://old-nacos-vip:8848/nacos/v1/cs/configs?dataId=&group=&pageNo=1&pageSize=500" -H "Authorization: Bearer YOUR_TOKEN_IF_NEEDED"这个API会返回一个JSON,包含了所有配置的dataId、group、content等信息。你需要编写一个简单的脚本(Python/Shell均可)来解析这个JSON,并循环调用获取配置详情的API。
导出单个配置内容:
# 假设有一个配置 dataId=example.yaml, group=DEFAULT_GROUP curl -X GET "http://old-nacos-vip:8848/nacos/v1/cs/configs?dataId=example.yaml&group=DEFAULT_GROUP" -o example.yaml我写了一个Python脚本,自动完成列表获取和内容导出,最终将所有配置保存为本地文件,文件名格式为{group}-{dataId}。
导出服务列表:服务注册信息无法通过简单API批量导出。我的做法是:在切换前,记录下老控制台“服务列表”页面的完整截图。因为服务信息是动态的,客户端重新注册即可,所以这不是关键数据,主要是用于核对。
4.2 向Nacos 2.3.0导入数据
在新集群的控制台上,我选择了手动创建命名空间(Namespace),因为我希望在新环境有一个更清晰的结构。然后,使用新集群的API,将导出的配置文件逐个导入。
导入配置的API调用示例:
curl -X POST "http://new-nacos-vip:8848/nacos/v1/cs/configs" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "dataId=example.yaml&group=DEFAULT_GROUP&content=$(cat example.yaml | base64 | tr -d '\n')" \ -H "Authorization: Bearer NEW_CLUSTER_TOKEN"注意:这里
content参数的值需要是Base64编码后的内容。也可以直接使用-d "content=文件内容",但要注意特殊字符的转义。
这个过程比较耗时,但对于配置数量不多的情况是可行的。如果配置量巨大(成千上万),可以考虑使用Nacos官方提供的config-export和config-import工具,或者基于OpenAPI编写更完善的迁移脚本。
4.3 客户端配置升级与切换
数据迁移完成后,最关键的一步是切换客户端。这需要分批次、分应用进行,并做好快速回滚的准备。
升级客户端依赖:
- 对于Spring Boot项目,在
pom.xml中,将spring-cloud-starter-alibaba-nacos-config和spring-cloud-starter-alibaba-nacos-discovery的版本升级到与Nacos 2.x兼容的版本。例如,我升级到了2021.0.1.0。 - 同时,确保底层
nacos-client的版本被间接升级到2.x(如2.1.0或更高)。可以在依赖树中检查。 - 对于Dubbo项目,升级
dubbo-registry-nacos到与Dubbo和Nacos 2.x兼容的版本。
- 对于Spring Boot项目,在
修改客户端配置:
- 最重要的变化是:连接地址需要包含新端口。Nacos 2.x客户端默认会尝试连接服务端的
9848端口(gRPC)。因此,在bootstrap.yml或application.yml中,配置需要更新:
spring: cloud: nacos: config: server-addr: new-nacos-vip:8848 # 如果网络策略需要,也可以显式指定gRPC端口,但通常不需要 # grpc.server-port: 9848 discovery: server-addr: new-nacos-vip:8848- 看起来和以前一样?是的,客户端会通过
8848端口的HTTP接口获取到服务器提供的9848gRPC地址,然后建立长连接。所以只需保证客户端能访问到服务器的8848和9848端口即可。
- 最重要的变化是:连接地址需要包含新端口。Nacos 2.x客户端默认会尝试连接服务端的
分批切换与验证:
- 选择非核心、流量小的服务作为第一批“试验田”。
- 修改其配置,指向新集群地址,然后重启服务。
- 立即观察:
- 服务日志:是否有连接错误?是否成功注册到新Nacos?
- 新Nacos控制台:该服务是否出现在“服务管理”列表中?实例IP和端口是否正确?
- 配置读取:该服务是否能从新Nacos正确拉取到配置?
- 进行简单的接口调用测试,验证服务发现链路是否通畅。
全量切换与回滚预案:
- 第一批服务验证稳定运行一段时间(如30分钟)后,开始分批切换其他服务。
- 务必准备好回滚方案:记录下每个服务原有的Nacos服务器地址。如果某个服务切换后出现无法解决的问题,立即将其配置改回老集群地址并重启。只要老集群还在运行,回滚就是分钟级别的事情。
5. 升级后必须验证的核心功能点
当所有客户端都切换到新集群后,不要以为大功告成。必须对新集群的各个功能进行完整验证。
5.1 服务发现与注册验证
- 服务列表完整性:核对新控制台中的服务列表,是否与老环境(或之前记录的截图)中的核心服务一致。重点关注那些调用链路上的关键服务。
- 实例健康检查:点击进入几个核心服务,查看实例列表。确认所有实例的“健康”状态都是绿色。Nacos 2.x的心跳检测机制有所优化,需要观察一段时间。
- 客户端负载均衡:通过Gateway或Feign/Dubbo进行一次完整的业务调用,验证服务消费者是否能从新Nacos正确获取到提供者列表并进行调用。可以使用
@LoadBalancerClient或Dubbo的Telnet命令来调试。
5.2 配置管理功能验证
- 配置读取:确保所有应用都能正确读取到配置。可以在应用启动日志中搜索“[Nacos Config]”关键字,确认配置加载的来源是新集群的地址。
- 配置动态刷新:这是核心功能。修改一个非关键的配置项(如某个日志级别),发布后,观察依赖该配置的应用是否在不重启的情况下收到了刷新通知。可以在应用日志中搜索“Refresh keys changed”或类似字样。
- 历史版本与回滚:测试配置的“历史版本”和“回滚”功能是否正常。这是生产环境配置误操作后的救命稻草。
5.3 集群与监控检查
- 集群节点状态:再次检查“集群管理”->“节点列表”,确保所有节点持续健康,没有频繁的上下线告警。
- 监控指标:Nacos 2.x提供了更丰富的Prometheus监控指标。访问
http://节点IP:8848/nacos/actuator/prometheus,查看nacos_monitor开头的指标,关注连接数、配置变更次数、服务心跳数等是否正常。 - 日志监控:关注
logs/nacos.log中是否有持续的ERROR或WARN日志。特别关注与鉴权、集群通信(Cluster)、gRPC相关的错误。
6. 常见问题与故障排查实录
在升级和后续验证过程中,我遇到了几个典型问题,这里分享排查思路和解决方案。
6.1 客户端连接失败,报错“Client not connected, current status:STARTING”
问题现象:Spring Boot应用启动后,日志中不断刷此错误,无法从Nacos获取配置或注册服务。
排查过程:
- 检查网络:
telnet new-nacos-vip 8848和telnet new-nacos-vip 9848,确保端口通。 - 检查客户端依赖:发现项目中通过
<exclusion>排除了nacos-client的传递依赖,然后显式引入了过时的1.x版本。 - 检查客户端配置:
server-addr配置正确。
根本原因与解决:根本原因是客户端SDK版本不匹配。Nacos 2.x服务器必须使用Nacos Client 2.x来连接。1.x的客户端无法理解2.x服务器的gRPC协议。
- 解决方案:确保所有依赖中,
com.alibaba.nacos:nacos-client的版本是2.x.x。在Spring Cloud Alibaba项目中,应通过升级spring-cloud-alibaba-dependencies的BOM版本来统一管理。
6.2 集群节点无法形成集群,日志提示“Connection refused”或“Fail to get leader”
问题现象:Nacos 2.x集群启动后,在控制台节点列表看到某个节点状态不健康,或者日志中持续报错无法选举Leader。
排查过程:
- 检查
cluster.conf文件:确认IP和端口(9848)书写正确,且没有多余空格或空行。 - 检查防火墙/安全组:这是最常见的原因。除了
8848,必须开放9848、9849、7848端口供集群内部通信。 - 检查
nacos.inetutils.ip-address配置:确认每个节点配置的IP是其他节点能访问到的真实IP,不是127.0.0.1或localhost。
根本原因与解决:网络策略未开放2.x新增的集群通信端口。
- 解决方案:在服务器防火墙或云平台安全组中,添加规则,允许集群节点IP之间通过
7848、8848、9848、9849、9555(JMX,可选)端口互相访问。可以使用iptables或firewalld命令临时开放测试。
6.3 配置变更后,部分客户端没有动态刷新
问题现象:在控制台修改了某个配置并发布,只有部分服务收到了通知并刷新了配置,另一部分服务“无动于衷”。
排查过程:
- 检查客户端日志:在没刷新的服务日志中,搜索“configData”或“Refresh”关键词,看是否有异常。
- 对比能刷新和不能刷新的服务:发现它们的
spring.cloud.nacos.config.group配置不一致。一个配置了明确的GROUP_A,另一个使用的是默认的DEFAULT_GROUP。 - 在控制台检查该配置:发现该配置存在于
DEFAULT_GROUP下,而不在GROUP_A下。
根本原因与解决:配置的Group不匹配。Nacos的配置定位由Data ID+Group+Namespace三者唯一确定。客户端订阅的Group必须与服务器上存储的Group完全一致,才能收到该配置的变更通知。
- 解决方案:统一配置的Group命名规范。或者在客户端配置中,使用
spring.cloud.nacos.config.extension-configs或shared-configs来指定多个Group的配置监听。
6.4 开启鉴权后,客户端无法连接
问题现象:在application.properties中设置了nacos.core.auth.enabled=true并配置了secret.key后,原有的客户端(未配置用户名密码或Token)全部无法连接。
排查过程:
- 服务端日志显示“
access token is empty”。 - 客户端日志显示“
status: 403, msg: unknown user”。
根本原因与解决:Nacos开启鉴权后,所有请求都需要携带有效的访问凭证。
- 解决方案:
- 服务端创建用户:在Nacos控制台(系统管理 -> 用户管理)中,创建具有相应权限的用户(如
dev_user)。 - 客户端配置凭证:
- 方式一(用户名密码):在客户端配置文件中添加。
spring: cloud: nacos: config: username: dev_user password: dev_user_password discovery: username: dev_user password: dev_user_password- 方式二(AccessToken):先从Nacos API接口获取Token,然后在客户端配置中设置。
推荐在生产环境使用方式一,并配合RBAC给不同团队分配不同的账号和权限。spring.cloud.nacos.config.context-path=/nacos spring.cloud.nacos.config.access-token=你的Token字符串
- 服务端创建用户:在Nacos控制台(系统管理 -> 用户管理)中,创建具有相应权限的用户(如
7. 性能调优与生产环境建议
升级到2.3.0并稳定运行后,还可以根据实际情况进行一些优化,让集群更稳健。
7.1 JVM与容器参数调整
默认的启动脚本(startup.sh)中的JVM参数可能不适合高负载场景。我修改了bin/startup.sh中的JAVA_OPT变量:
# 修改前(示例) JAVA_OPT="${JAVA_OPT} -Xms2g -Xmx2g -Xmn1g" # 修改后(根据机器内存调整,例如8G内存机器) JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m" JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=4 -XX:ConcGCThreads=2" JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/nacos/logs/java_heapdump.hprof" JAVA_OPT="${JAVA_OPT} -Dnacos.core.auth.enabled=true -Dnacos.core.auth.server.identity.key=yourKey -Dnacos.core.auth.server.identity.value=yourValue"-Xms和-Xmx设置为相同值,避免堆内存动态调整带来的性能波动。- 使用G1垃圾收集器,在大内存和追求低延迟的场景下表现更好。
- 添加OOM时的堆转储参数,便于事后分析。
如果使用Docker部署,需要在docker-compose.yml或Kubernetes的Deployment中设置相应的环境变量来覆盖这些参数。
7.2 数据库连接池与监控告警
对于使用MySQL的生产集群,数据库性能是关键。建议:
- 在MySQL端为Nacos创建单独的数据库用户,并限制其连接数和权限。
- 监控Nacos的数据库连接数。可以在
application.properties中调整连接池参数(如HikariCP)。 - 搭建Prometheus + Grafana监控体系,采集Nacos的JVM指标、HTTP/gRPC请求量、配置变更QPS、服务实例数等核心指标,并设置告警规则(如实例数突降、配置推送失败率升高)。
7.3 定期备份与灾难恢复演练
即使升级完成,运维工作也不能停。
- 配置备份:定期(如每天)通过API或脚本,将重要命名空间(Namespace)下的配置导出备份到对象存储或其它安全位置。
- 数据库备份:对MySQL数据库执行定期的全量备份和Binlog增量备份。
- 恢复演练:每季度至少进行一次灾难恢复演练。模拟一个Nacos节点宕机,甚至整个集群数据丢失,测试从备份中恢复数据和重新搭建集群的能力。这能确保你的备份是有效的,并且团队熟悉恢复流程。
从Nacos 1.3升级到2.3,绝不仅仅是一个版本的跳跃,它是一次架构的演进。整个过程下来,最深的体会是:预案比操作更重要,验证比执行更关键。尤其是在数据迁移和客户端切换环节,多花时间设计可回滚的方案、分批验证的步骤,远比遇到问题后手忙脚乱地排查要高效得多。升级后,最直观的感受是配置推送的速度和服务的最终一致性有了可感知的提升,新的鉴权体系也让运维管理更规范。如果你也面临类似的升级任务,希望这份详实的记录能帮你避开我踩过的那些坑。