Appearance
服务发现
配置中心管"应用读什么配置",服务发现管"一个服务名下面当前有哪些可用实例"。Nacos 同时做这两件事,部署后要分别验证配置读取和服务注册两条链路。
一、服务和实例——两个层级
服务是逻辑名称,实例是具体的可连接地址。order-service 是服务名,它下面可以有多个实例:
服务注册和查询时会反复出现这些字段:
| 字段 | 说明 | 示例 |
|---|---|---|
serviceName | 服务名 | order-service |
groupName | 服务分组 | DEFAULT_GROUP |
ip | 实例 IP | 192.168.10.13 |
port | 实例端口 | 18080 |
clusterName | 集群名 | DEFAULT |
healthy | 是否健康 | true |
weight | 权重 | 1.0 |
metadata | 附加信息 | version=v1、zone=az1 |
Nacos 返回的不只是 IP:PORT——还包含健康状态、权重、元数据。客户端可以基于这些信息做负载均衡(按权重分配请求)、灰度路由(按版本标签过滤)、就近访问(按 zone 筛选)。
二、临时实例和持久实例
临时实例:普通微服务最常用的方式。客户端 SDK 注册后持续发送心跳,Nacos 超过一定时间收不到心跳就标记不健康,再超时就摘除。服务进程停了,实例从注册中心消失,调用方后续不再拿到它。
持久实例:由人通过 API 或控制台注册的一条固定记录,不依赖客户端心跳自动删除。适合少量固定后端或需要人工维护的服务条目。
bash
# 注册临时实例(默认)
curl -sS -X POST 'http://127.0.0.1:8848/nacos/v3/client/ns/instance' \
-d 'serviceName=ops-demo-service' \
-d 'groupName=DEFAULT_GROUP' \
-d 'ip=192.168.10.13' \
-d 'port=18080' \
-d 'username=nacos' \
-d 'password=nacos'
# 注册持久实例
curl -sS -X POST 'http://127.0.0.1:8848/nacos/v3/client/ns/instance' \
-d 'serviceName=ops-demo-persistent' \
-d 'groupName=DEFAULT_GROUP' \
-d 'ip=192.168.10.13' \
-d 'port=18080' \
-d 'ephemeral=false' \
-d 'username=nacos' \
-d 'password=nacos'查询实例列表:
bash
curl -sS \
'http://127.0.0.1:8848/nacos/v3/client/ns/instance/list?serviceName=ops-demo-service&groupName=DEFAULT_GROUP&username=nacos&password=nacos'返回字段关注 healthy(是否健康)、enabled(是否启用)、ephemeral(是否临时实例)、weight(权重)。
命令行手工注册临时实例适合验证 API,但它没有真实客户端维持心跳——过一会儿实例会被标记不健康然后消失。这是正常的,不代表 Nacos 有问题。业务应用由 SDK 注册,SDK 处理心跳续约和断线重连。
三、心跳——临时实例的存活依据
临时实例依赖心跳。应用定期告诉 Nacos "我还活着",Nacos 超过一段时间没收到心跳就把实例标记为不健康。常见故障场景:应用日志里反复报 Nacos 连接失败,几分钟后调用方开始找不到该服务。此时控制台服务名还在,但实例健康状态变了——"服务名存在不等于调用正常",健康实例数和客户端日志才是关键。
四、权重和元数据
权重用于简单流量分配:权重越高,被客户端选中的概率越大。常见用途:
| 场景 | 操作 |
|---|---|
| 灰度少量流量 | 新版本实例权重调低(比如 0.1),老版本保持 1.0 |
| 下线前摘流量 | 权重调低到 0 或直接禁用实例 |
| 机器性能不同 | 高配机器给更高权重 |
元数据是实例上的键值对,常用于版本、机房、区域等标识:
text
version=v2
zone=shanghai-a
role=gray只能放稳定、可解释的字段。临时排查随手加的标签如果没有清理,后续做灰度或路由判断时可能变成脏条件——一个实例的元数据里同时有 version=v1 和 role=gray,而灰度规则又是按 role 过滤,行为就和预期不一致了。
五、服务发现的排查层次
"服务发现失败"不能笼统排查,要按链路分层:
| 层次 | 检查内容 | 常见问题 |
|---|---|---|
| 应用侧 | 客户端是否成功注册,日志里有没有连接/鉴权异常 | serviceName 为空、连错 Nacos 地址 |
| Nacos 服务侧 | 服务名、分组、命名空间是否一致 | namespace 不一致导致"查不到" |
| 实例侧 | 健康状态、IP/端口、权重 | 心跳断了、端口没有监听 |
| 网络侧 | 应用到 Nacos 的 8848/9848 是否通 | 防火墙只放了 8080 |
| 消费侧 | 调用方是否拿到最新实例列表,本地缓存是否过期 | 客户端缓存了旧列表 |
出现"服务不存在"时,把调用方使用的 namespace/group/serviceName 写出来,再和控制台逐一比对。大量"服务不存在"的问题最后发现是:开发调的是 dev namespace,测试同学在 test namespace 的 Nacos 控制台查——看起来同名服务,实际上两个命名空间互不相通。