Skip to content

Nacos 基础

单体应用时代这些问题不明显:一个应用、一个配置文件、一个数据库连接,启动脚本里写死就行。服务拆多以后麻烦就来了——订单服务有多台实例,库存服务也有多台,某个实例发布重启后 IP 和端口可能完全变了;同时,连接池大小、限流开关、灰度参数这些配置,又不适合每次都登录机器改文件再重启。Nacos 解决的就是这两类问题:"服务地址会变化"和"配置需要集中变更"

Nacos 的全称是 Dynamic Naming and Configuration Service,名字已经把两条核心能力标出来了:Naming(服务注册与发现,管"order-service 下面当前有哪些可用的 IP:PORT")和 Configuration(配置中心,管"application.yaml 改了之后应用读到新值")。这两件事是独立的,排查时也要分清楚是哪条链路出问题。

一、组件构成

从运维角度看,Nacos 不只是浏览器里那个控制台页面。它至少包含这几部分:

部分做什么部署依赖
Nacos Server提供配置、注册、查询、推送接口的服务端进程Java 17+、端口、配置文件
控制台人在浏览器里查看和修改配置、服务、权限、集群状态8080 端口
客户端 SDK业务应用用它注册实例、读取配置、监听变更应用侧的 nacos-client 依赖
MySQL保存配置内容、用户账号、权限、历史版本集群模式必须依赖外部数据库
集群通信多个 Nacos 节点之间同步状态、保持一致性gRPC 和 Raft 端口互通

这里有个特别容易踩的误区:控制台能登录,只说明管理入口可用;业务应用还要能连到服务端 API、通过鉴权、注册实例、读取配置——这几个环节跟控制台是不同的端口和路径。排错时最容易卡在"控制台页面一切正常,但应用那边配置读不到、服务注册不上"这种状态,因为两边走的是不同的链路。

二、架构位置

请求进系统时先经过网关或 Nginx,Nacos 在旁边提供"查服务地址"和"取配置"的能力。调用方拿到实例列表后,请求由客户端框架直接发给目标实例——不会每次都穿过 Nacos。

这个位置决定了排查时的优先级:接口 502、网关超时、Pod 网络不通,第一现场通常在入口或网络层;如果服务列表里缺实例、配置没下发、客户端启动时就报 Nacos 连接异常,再回到 Nacos 排查。别一上来就怀疑 Nacos,先确认问题是不是真出在 Nacos 这一层

三、服务注册与发现

服务提供方把自己的地址登记到 Nacos,调用方向 Nacos 查询服务名下有哪些可用实例:

服务和实例是两个不同的对象,这个区分要记住。服务是逻辑名称(比如 order-service),实例是具体的进程地址(比如 192.168.10.21:8080)。一个服务下面可以有多个实例,发布、扩容、缩容、机器故障时实例列表会变化——这也是为什么不能把 IP 写死在代码里。

服务发现涉及的字段不少:服务名(逻辑服务名)、分组(服务分组)、命名空间(环境或租户隔离)、实例 IP/端口、健康状态、权重(客户端选择实例时的参考)、元数据(版本、机房、灰度标签)。Nacos 返回的不只是 IP:PORT,还带着健康状态、权重、元数据,客户端可以基于这些做负载均衡、灰度路由、就近访问。

Nacos 里有临时实例持久实例的区别,行为差别很大。普通微服务进程大多是临时实例——由客户端 SDK 保持心跳,进程停了、心跳断了,实例被标记为不健康然后摘除。持久实例更像一条人工维护的固定记录,不会因为客户端连接断开就自动消失,适合少量固定后端或需要手动管理的服务条目。

四、实例变更感知

服务实例列表不是静态的——发布、扩容、机器宕机都会让它变化。Nacos 让调用方保持最新列表,靠两种方式配合:服务端推送变更(Nacos 检测到实例变化后,通过 gRPC 长连接推给订阅了该服务的客户端,适合需要快速感知上下线的场景)和客户端定时拉取(SDK 每隔一段时间主动查询最新实例列表,作为兜底)。

实际运行时两种方式配合用:正常情况下靠推送,客户端同时保留定时拉取作为兜底——即使推送链路断了,定时拉取还能保证最终拿到新列表。这个双保险设计,是 Nacos 比较稳健的地方。

五、配置三段定位

配置中心保存应用的运行配置,YAML、properties、JSON、纯文本都可以。一份配置靠三段组合来定位,这是配置管理的核心:

text
namespace + group + dataId
字段说明示例
namespace命名空间,常用于环境隔离publicdevprod
group分组,同一命名空间内进一步分组DEFAULT_GROUP
dataId配置标识,习惯写成文件名形式application.yaml

配置发布后 Nacos 会推送变更通知给监听该配置的客户端。但应用能不能热更新,取决于客户端框架和业务代码——Nacos 只负责推送,"推送到了"和"业务变量已经换成新值"之间有距离。启动配置(数据源、端口等)通常需要重启;动态配置(开关、阈值、灰度比例)如果应用框架支持且代码写了监听,可以运行时生效。这个区别是排查"配置改了不生效"的关键。

配置中心几个核心运维价值:集中发布(不用登机器改文件,一个入口管理所有环境配置)、历史版本(知道什么时候谁改了什么)、回滚(改错了能退回)、权限控制(谁能改生产配置)、变更推送(应用实时感知配置变化不用重启)。这些能力里,历史版本和回滚是改配置出事时的救命稻草,别的可以没有,这两个一定要有

六、namespace 与 group

三段组合起来可以同时支持多个环境和多个业务线:

namespacegroupdataId含义
devDEFAULT_GROUPorder-service.yaml开发环境订单服务配置
prodDEFAULT_GROUPorder-service.yaml生产环境订单服务配置
prodPAY_GROUPpay-service.yaml生产环境支付服务配置

"配置读不到"时,namespace、group、dataId 三段必须逐个对照。比如控制台里能看到 prod / DEFAULT_GROUP / order-service.yaml,但应用启动参数里写的是 namespace=dev,客户端日志里又打印 dataId=order-service.yaml, group=DEFAULT_GROUP——基本能判断应用连到了 dev 命名空间,读不到 prod 那份配置。这种"三段对不上"的坑,是配置不生效最常见的原因。

整个配置管理的交互过程大致如下:

这段过程里最容易出问题的环节是两个:推送是否到达(网络、客户端连接状态),以及到达后应用是否真的刷新了(框架支持、代码监听)。两个环节出问题,表现都是"配置改了但不生效",但根因完全不同。

七、与 K8s Service 的关系

两者都能让应用找到服务,但不在同一层,职责不一样:

对比项NacosKubernetes Service
所在层应用层服务发现 + 配置管理集群网络抽象
使用方式客户端 SDK 查服务读配置Pod 通过 DNS 或 ClusterIP 访问
注册对象服务名、实例、配置、元数据Service、EndpointSlice、Pod
配置管理内置,带版本和回滚ConfigMap / Secret,无版本概念
常见体系Spring Cloud AlibabaK8s 原生工作负载

K8s 里也可以跑 Nacos。Spring Cloud 应用已经深度依赖 Nacos 做服务发现和配置中心时,迁到 K8s 后通常保留 Nacos,K8s Service 负责集群网络入口,两者并存、职责不同。新项目如果全跑在 K8s 里,是否继续用 Nacos 取决于团队技术栈、配置管理的复杂度、灰度能力需求和对 Nacos 的运维成本——没有标准答案,看实际情况。

八、Nacos 3.x 变化

实验使用的 Nacos 3.2.1 和旧版资料有几处差异,照着老资料操作会踩坑:

Nacos 3.2.1 实际情况
控制台端口默认 8080(旧版是 8848/nacos)
服务端 API 端口8848,/nacos 路径
Java 版本需要 Java 17+
API 版本新接口以 /v3 为主,旧 /v1 资料不能完全照搬
鉴权启动脚本对鉴权配置项检查更严格,Token Secret 等必须有效填充

旧资料经常直接访问 8848/nacos 打开控制台,Nacos 3.x 会提示控制台改到了 8080/next/8848 更偏服务端 API 和客户端通信入口。这个端口变化是最容易让新手懵的地方——照着老教程敲 8848/nacos,结果跳出来一个提示让你去 8080

九、运维关注点

运维 Nacos 要操心的方向不少:部署(Java 版本、端口、启动参数、systemd、集群文件)、存储(MySQL 连接、表结构、备份、schema 版本匹配)、配置(三段对齐、历史版本、回滚、灰度)、服务(临时/持久实例、心跳、健康状态、权重、元数据)、集群(节点状态、端口互通、版本一致、cluster.conf)、权限(登录账号、Token、鉴权参数三节点一致性)、排错(客户端连接、配置不生效、服务掉线、节点异常)。

最后再强调一遍:控制台正常不等于业务正常。控制台是给人看的,服务端 API 和客户端通信才是应用真正依赖的。排查时一定要分清是控制台层的问题,还是业务链路层的问题——这两个搞混,排查方向就会跑偏。