Nacos 寓言:会搬家的店铺与城市总务处
在群山之间,有一座叫“微光城”的小城。
城里最初只有几家店:订单铺负责接单,库存铺记录货物,支付铺管理钱款。每家店都有固定门牌,店主们把彼此的地址抄在墙上的通讯录里:
订单铺要查库存,就去青石路 10 号;要收款,就去河岸街 3 号。
那时城市很小,地址很少变化。即使偶尔换一盏招牌,也只要几位店主相互通知。整座城看起来简单而可靠。
城市开始长大
后来,生意越来越多。
库存铺忙不过来,于是开了三处分店;节日期间又临时增加两处,节后再撤掉。新店每天可能在不同街区开门,旧店也可能因房屋维修突然关门。
订单铺墙上的地址很快失去了可信度。它照着旧通讯录派出信使,有时信使抵达后只看到一扇锁着的门;有时新开的库存分店明明空闲,却因为没人知道它的地址,一整天都接不到请求。
这对应微服务里的一个朴素问题:服务实例的 IP 和端口会变化。特别是在 Kubernetes 中,Pod 被重建后 IP 可能改变,扩缩容又会不断增加或移除实例。把地址写死在代码或配置文件里,规模一大便很难维持。
与此同时,另一种混乱也在发生。
过去每家店都在自己的墙上贴营业规则:超时时间是多少、是否开启促销、数据库入口在哪里。规则改变时,城主只能派人逐店修改。有人漏改,有人抄错,还有人改完忘了重新开门。最后,同一种店竟按不同规则工作。
最危险的并不是没有规则,而是大家都以为自己拿到的是同一份规则。
总务处出现了
城市没有再要求每家店记住所有地址,而是设立了一个“城市总务处”。它负责两本册子:
- 一本是店铺名册,记录某类店铺当前有哪些实例、地址是什么、是否健康;
- 一本是公共告示,集中保存各类店铺需要读取的配置。
这个总务处,就是故事里的 Nacos。
Nacos 的名字来自 Dynamic Naming and Configuration Service。在常见的微服务系统中,它主要承担两类职责:
- 服务注册与发现 / Service Registration and Discovery
- 配置管理 / Configuration Management
它能回答“库存服务现在在哪里”,也能保存并发布“订单服务应该使用什么配置”。
但它不是万能的。Nacos 通常不替订单服务执行库存查询,也不负责把每一个业务请求代理到库存服务;真正发起请求、选择实例并完成调用的,仍然是应用程序、客户端 SDK 或与它集成的框架。它也不能代替数据库保存订单,不能代替 Redis 做业务缓存,更不能代替 Prometheus 观察完整的系统指标。
它管理的是服务地址、健康状态、配置及相关元数据,而不是整个业务世界。
店铺先报到:服务注册
一间新的库存铺开门时,不再挨家挨户通知地址。它先向总务处登记:
我是
inventory-service的一个实例,住在10.0.3.17:8080。
这叫做 服务注册 / Service Registration。
总务处把它归入 inventory-service 名下。另一家库存分店也会登记在同一个服务名下,因此一个服务可以对应多个实例。
现实中,这个动作通常由应用内的 Nacos 客户端或框架集成完成。例如 Spring Cloud Alibaba 应用启动后,可以根据配置把自己的服务名、IP、端口和元数据注册到 Nacos。谁负责注册、注册哪些字段,取决于客户端、框架和具体配置,并不是 Nacos 凭空扫描出了所有服务。
这里要分清三个角色:
- 库存服务实例负责“报到”;
- Nacos 负责保存并维护实例名册;
- 订单服务负责在调用前查询或订阅名册。
订单铺怎样找到库存铺:服务发现
订单铺要查询库存时,只记住一个稳定的名字:inventory-service。
它向总务处询问:“这个名字下面,现在有哪些可用店铺?”总务处返回一组地址。订单铺的客户端再从可用实例中选出一个并发起请求。
这叫做 服务发现 / Service Discovery。
订单服务 |
“谁找到谁、谁真正执行”在这里很重要:
Nacos 帮订单服务找到库存服务,但库存查询仍由库存服务执行;Nacos 返回地址列表,却通常不位于业务请求的数据通路中。负载均衡由客户端、框架、网关或其他组件完成,具体由谁完成取决于系统实现。
为了避免每次调用都去总务处排队,客户端通常会维护本地实例列表,并通过订阅、推送或定期更新等机制感知变化。具体通信和缓存行为会随 Nacos 版本及客户端实现而不同,但核心思想不变:调用方持有一份可更新的服务视图,而不是永久相信一张写死的地址表。
关门的店为什么还会出现在地图上:健康检查
仅仅登记一次还不够。
有一家库存铺虽然门牌还在,却因掌柜生病停止营业。如果总务处仍把它当作正常店铺,订单铺的信使就会不断扑空。
于是,店铺需要持续证明自己还活着,或者接受总务处的巡查。这叫做 健康检查 / Health Check。
在不同模式下,健康状态可能通过客户端心跳上报,也可能通过服务端主动探测等方式维护。临时实例与持久实例的处理方式也不完全相同;实际行为取决于 Nacos 版本、实例类型和配置,不能简单理解为“所有实例都每隔固定时间发一次心跳”。
当某个实例被判定为不健康时,Nacos 会更新名册,让服务消费者尽量不再选择它。实例恢复后,是否以及怎样重新变为健康,同样由相应的健康检查机制决定。
但要注意:健康检查只能说明某种探测条件是否通过。端口能连接,不一定代表业务完全正确;接口返回成功,也不一定代表下游数据库没有异常。探测得有多深,取决于程序和配置。
公共告示怎样改变全城:配置管理
总务处的第二本册子保存配置。
例如,订单铺需要知道请求库存服务的超时时间:
inventory: |
过去,这行字可能被打包在每个应用里。现在,它可以作为一份配置发布到 Nacos。应用启动时读取它,并在配置变化时通过客户端的监听机制获知更新。
这就是 配置管理 / Configuration Management,其中运行期间感知并应用变化的能力常被称为 动态配置 / Dynamic Configuration。
不过,“Nacos 中的配置改了”不等于“应用行为一定立刻改变”。完整链路是:
管理员发布配置 |
Nacos 负责保存和传播变化;应用是否支持热更新、哪些字段能够刷新、是否需要重启,取决于框架、程序写法和配置。数据库连接池大小、线程池参数等配置即使被客户端读到,也未必能在运行中安全重建。
因此,配置中心解决的是配置分散、变更困难和环境管理混乱的问题,而不是替应用自动实现所有动态刷新逻辑。
不让同名告示互相覆盖
城市继续扩大后,出现了测试城区和生产城区。两边都有一张名为 order-service.yaml 的告示,但内容显然不能混用。
总务处于是用不同层次整理资料。Nacos 配置中常见的标识包括:
- 命名空间 / Namespace:常用于隔离环境或租户;
- 分组 / Group:用于对配置或服务进一步分类;
- 数据标识 / Data ID:标识一份具体配置。
可以把一份配置理解为由 Namespace + Group + Data ID 共同定位。实际命名规范由团队约定。例如,可以让测试环境和生产环境使用不同 Namespace,再通过 Group 和 Data ID 区分应用与配置类型。
服务注册同样有 Namespace、Group、Service 等组织概念。隔离边界和命名方式应根据团队设计,不能只靠名字里写一个 prod 就假定安全。
一次真实的 Pod 更替
假设 Kubernetes 中运行着三个库存服务 Pod,并通过 Spring Cloud Alibaba 接入 Nacos。
- 每个库存 Pod 启动后,客户端将实例信息注册到 Nacos。
- 订单服务订阅
inventory-service,获得当前健康实例列表。 - 订单服务客户端选择其中一个实例,直接发起 HTTP 或 RPC 请求。
- Kubernetes 因发布新版本删除一个旧 Pod,并创建一个新 Pod。
- 旧实例停止续约、主动注销或被健康机制判定不可用;新实例启动后完成注册。
- Nacos 中的实例列表发生变化,订单服务客户端更新本地列表,后续请求转向仍然可用的实例。
在这条链路中:
- Kubernetes 真正创建、删除和调度 Pod;
- Nacos 保存微服务注册信息并把变化传递给消费者;
- 应用客户端选择实例并发出业务请求;
- 库存服务处理请求;
- 数据库保存库存数据。
Nacos 并没有接管 Kubernetes,也没有亲自转发订单请求。两者处理的是相邻但不同的问题。
Kubernetes 本身也有 Service、EndpointSlice 和 DNS 服务发现机制。如果应用只运行在单一 Kubernetes 集群内,Kubernetes 原生发现可能已经足够;如果系统同时存在虚拟机、多个集群、不同微服务框架,或者团队同时需要动态配置能力,Nacos 可能更合适。是否同时使用,以及谁作为主要服务发现来源,取决于架构和配置,重复维护两套注册信息反而可能制造不一致。
它与 Nginx、Jenkins、Redis、Filebeat 分别是什么关系
城市里不止一个机构,但每个机构应该各守其职。
Nginx 或 API Gateway 更像城门和分流站:它们接收流量并转发请求。它们可以通过集成机制获得后端地址,但真正转发流量的是它们,不是 Nacos。
Jenkins 像施工队调度室:它构建和发布新版本,也可以在流水线中更新配置,但 Nacos 不负责替 Jenkins 编译或部署应用。
Redis 像高速临时仓库:它保存缓存、会话或其他快速访问的数据。Nacos 的本地缓存和服务信息不能让它变成业务缓存。
Filebeat 像巡城的日志收集员:它把各处日志送往后端。Nacos 可以提供某些采集参数,但不会代替 Filebeat 读取日志文件。
数据库像城市档案馆:订单、用户和库存等业务数据最终由它持久化。Nacos 保存的是自身负责的配置、服务及元数据状态,不是业务数据库的替代品。
当总务处自己停摆
如果 Nacos 集群发生故障,影响要分两部分看。
对于服务发现,已经运行的客户端通常可能保有一份本地实例信息,因此短时间内未必立刻停止调用;但它可能无法及时知道实例新增、下线或健康状态变化。能维持多久、失败时如何降级,取决于客户端版本、缓存和程序策略。
对于配置管理,应用可能继续使用内存中或本地缓存的旧配置,但新配置无法正常获取或发布。若应用启动时必须从 Nacos 取得配置,而本地没有可用快照,它也可能启动失败。这同样取决于客户端和配置。
所以生产环境中的 Nacos 自身也需要高可用部署、持久化、监控、备份和变更管理。管理别人的名册,并不意味着自己不会丢失方向。
最容易产生的误解
最常见的误解是:“用了 Nacos,服务之间的请求就会经过 Nacos。”
这只对了一小部分——调用方确实可能先从 Nacos 获得服务信息,但获得地址以后,业务请求通常由调用方直接发往目标实例,或者交给网关、代理转发。Nacos 主要处在控制信息的流动中,而不一定处在业务数据的流动中。
也可以换一种说法:Nacos 更像维护地图和告示的机构,而不是运送每一件货物的马车。
当一座城市无法再靠每个人记住所有门牌运转时,真正需要的不是一张永不变化的地图,而是一套让变化能够被登记、被发现、也被正确对待的秩序。

