Nacos 注册表
Nacos 是 Higress 最重用的注册源(阿里生态)。今天拆一个具体 watcher:怎么订阅 Nacos、轮询全量服务、把实例转成 Istio ServiceEntry。三代实现体现能力演进。昨天(Day 07)看的是"Reconciler 怎么管这一群 watcher",今天挑最常用的 Nacos watcher 钻进去看它内部到底怎么干活,为 Day 09"转出的 ServiceEntry 怎么进 Istio config store"铺路。
三代 Nacos
Higress 有三套 Nacos 实现:registry/nacos/(v1 SDK)、registry/nacos/v2/(v2 SDK)、registry/nacos/mcpserver/(MCP Server 发现)。
watcher 结构
// registry/nacos/watcher.go:54
type watcher struct {
provider.BaseWatcher // 嵌入基类(Day 06)
apiv1.RegistryConfig
namingClient naming_client.INamingClient // Nacos 官方 SDK
}
// 默认:超时 5000ms、刷新间隔默认 30s(下限 10s)、分页 50、Group/Service 连接符 @@
BaseWatcher(复用回调管理)+ 持有 Nacos 官方 SDK 的 INamingClient。NewWatcher 用 Option 模式配置(WithNacosNamespaceId 空值默认 public 等)。Run 轮询
// watcher.go:196 Run()
// 起 ticker 按 NacosRefreshInterval 周期跑
// 先探活设 Status → fetchAllServices() → Ready(true)
fetchAllServices 完成后 Ready(true) 报告就绪(Day 06 回调)。fetchAllServices
// watcher.go:212 fetchAllServices()
// 对每个 group 用 GetAllServicesInfo 分页拉全量服务列表
// 与本地 WatchingServices diff:
// 消失的 → unsubscribe;新增的 → subscribe
// shouldSubscribe(:414)过滤掉 consumers: 前缀(Dubbo 消费者,不是服务提供者)
consumers: 前缀)——只关心服务提供者,消费者不是可路由的目标。这是 Nacos + Dubbo 场景的实战细节。订阅回调
// watcher.go:297 getSubscribeCallback —— 实例变化时被 Nacos SDK 调用
// 拼 host(serviceName.group.namespace.type,下划线转连字符)
// 空实例时删缓存
// 跳过 register-resource=mcp-bridge 的自注册回环
// 否则 generateServiceEntry 后 cache.UpdateServiceWrapper
// 最后 defer w.UpdateService() 通知上层(Day 06 回调)
generateServiceEntry
// watcher.go:331 把 Nacos 实例转成 Istio ServiceEntry
// 每个实例转 WorkloadEntry(IP+端口+Metadata 作 Labels)
// 从 metadata 读 protocol,权重 math.Round(service.Weight)
// ServiceEntry{Location: MESH_INTERNAL, Resolution: STATIC}
WorkloadEntry(Istio 课 Day 03 的概念);一个 Nacos 服务 → 一个 ServiceEntry(含所有实例、协议、权重)。Resolution: STATIC 表示端点是明确的 IP(Istio 课 Day 15 的服务发现类型)。转成 ServiceEntry 后,它就融入了 Istio 的配置体系——istiod 拿去生成 Envoy 的 Cluster/Endpoint,和 K8s 服务一视同仁。这就是"多源统一"的落点。order-svc 有两个实例:10.0.0.8:8080 (weight=10)、10.0.0.9:8080 (weight=10) →每个实例 → 一个
WorkloadEntry(address=IP、ports、labels=Nacos metadata);整个服务 → 一个
ServiceEntry(hosts=order-svc.…、含 2 个 endpoint、Resolution: STATIC、Location: MESH_INTERNAL)。从此 istiod 看它就跟一个普通 K8s 服务一样,能生成 Envoy 的 Cluster/Endpoint。
👶 小白:为什么要"跳过 mcp-bridge 自注册回环"?
👨🏫 老师:Higress 有时会把自己的东西也注册到 Nacos 上(带 register-resource=mcp-bridge 标记)。如果 watcher 又把它当普通服务发现回来、转成 ServiceEntry、再触发推送……推送可能又引起注册变化,绕成一个自己发现自己的死循环。所以回调里一眼认出这个标记就直接跳过——相当于抄录员看到"这条是我自己刚填进去的",就不再重复登记。
v2 / nacos3 演进
registry/nacos/v2/watcher.go:结构多了 addrProvider(地址服务器动态解析 Nacos 集群地址)、mcpWatcher(MCP Server 子 watcher)。ClientConfig 多了 AccessKey/SecretKey/Username/Password(鉴权)。若 EnableMCPServer=true 且类型 nacos3,创建 mcpserver 子 watcher,把 Nacos 上的 MCP Server 转成 ServiceEntry + WasmPlugin 规则。
fetchAllServices/回调/generateServiceEntry 逻辑三代类似。今日小结 + 动手
🧠 今天你应该能回答
- Nacos 三代的区别?
- watcher 怎么复用 BaseWatcher + 用官方 SDK?
- "轮询 + 订阅"双机制各管什么?
- fetchAllServices 怎么 diff?为什么过滤 Dubbo 消费者?
- generateServiceEntry 怎么把 Nacos 实例转成 ServiceEntry?
✋ 动手
cd /Users/bitmart/work/codes/github/higress-group/higress
grep -n 'func.*Run\|func.*fetchAllServices\|func.*generateServiceEntry\|getSubscribeCallback' registry/nacos/watcher.go
ls registry/nacos/
convertServiceEntry、完整数据流。