多注册中心概览
Higress 相比原生 Istio 的一大特色:不只从 K8s 发现服务,还能从 Nacos/ZK/Eureka/Consul/DNS 发现。今天看统一的 Watcher 抽象怎么屏蔽这些异构注册中心。第 1 周(Day 01-05)我们走通了"配置怎么翻译并喂给 istiod";第 2 周换一条线——网关要转发流量,得先知道"目标服务的实例都在哪台机器",这就要靠服务发现。今天是这条线的总览,为 Day 07-09 拆具体注册中心铺路。
Watcher 接口就是一群"抄录员",不管原始通讯录长什么样,都按同一张标准表格抄录(订阅→转成 ServiceEntry→回调通知)。上层拿到的永远是统一格式,根本不用关心原始通讯录是哪种——这就是"接口屏蔽异构",你在 Envoy/Istio 课已见过好几次的老朋友。为什么要多注册中心
八种类型
// registry/watcher.go:27 支持的注册中心类型
Zookeeper / Eureka / Consul
Nacos (老 SDK v1)
Nacos2 (新 SDK v2)
Nacos3 (v2 + MCP Server 发现,AI 网关特性)
Static (配置里写死)
DNS (域名解析)
registry/<类型>/)。Nacos 有三代——v1(基础)、v2(鉴权+地址服务器)、nacos3(MCP Server 发现,Day 08)。代码在 registry/ 各子目录。Watcher 接口
// registry/watcher.go:54 统一 Watcher 接口(所有注册中心都实现它)
type Watcher interface {
Run(); Stop(); IsHealthy() bool; IsReady() bool
GetRegistryType() string
AppendServiceUpdateHandler(f func()) // 挂"服务变化回调"
ReadyHandler(f func(bool)) // 挂"就绪回调"
}
Watcher 接口把它们抽象成同一套:Run(开始订阅)、Stop(停)、IsReady(就绪没)、AppendServiceUpdateHandler(服务变了叫我)。每个注册中心只需实现这个接口——"订阅本注册中心 → 生成 ServiceEntry → 写共享缓存 → 回调通知"。上层(Reconciler,Day 07)只跟 Watcher 打交道,不管底层是 Nacos 还是 ZK。这是"接口/实现分离"的又一次应用——和 Envoy 的 LoadBalancer、Istio 的 ServiceDiscovery、OpenClaw 的 ChannelPlugin 同一个思想。BaseWatcher 组合
BaseWatcher(watcher.go:64)提供接口默认实现,各具体 watcher 匿名嵌入 provider.BaseWatcher 复用。UpdateService(服务变更通知上层)和 Ready(就绪状态)两个回调是与 Reconciler 联动的关键。
BaseWatcher 就自动获得回调管理等通用能力,只需实现自己独特的"怎么订阅本注册中心"。比继承更灵活(Go 没有类继承,用组合)。两个回调
UpdateService——注册中心的服务实例变了(新增/下线),watcher 调它通知上层"配置该刷新了",触发向 istiod 推送新配置。②Ready——watcher 首次同步完注册中心的全部服务,调它报告"我准备好了"。Reconciler 等所有 watcher 都 Ready 才算整体就绪(Day 07)。这是"生产者(watcher 发现服务)→ 通知(回调)→ 消费者(Reconciler/istiod 刷新)"的事件驱动联动。order-svc 加了一个实例 10.0.0.9:8080 →Nacos watcher 订阅到变化 → 重算
order-svc 的 ServiceEntry(多了个 endpoint)→ 写共享缓存 →调
UpdateService 回调 → 触发向 istiod 推送 → 最终 Envoy 的负载均衡池里就多了 10.0.0.9,开始分流量给它。整条链你不用碰任何 K8s Service——服务始终注册在 Nacos。
👶 小白:为什么要分 UpdateService 和 Ready 两个回调,不能合一个吗?
👨🏫 老师:它俩管的事不同。Ready 是"我第一次把整本通讯录抄完了"——只在启动同步完成时报一次,Reconciler 靠它判断"能不能对外服务了"(没抄完就服务,会漏掉一半实例)。UpdateService 是"通讯录后来又改了"——运行期每次增删实例都会调,触发增量刷新。一个管"就绪门禁",一个管"持续同步",合并了反而分不清是首次还是后续变更。
探活与 vport
ProbeWatcherStatus(host, port)(watcher.go:91)用 net.DialTimeout 三秒 TCP 探活,作为 IsHealthy() 依据。GetServiceVport(watcher.go:101)虚拟端口机制——把注册中心里各实例真实端口统一映射成一个对外服务端口。
认证选项
registry/auth_option.go:17 AuthOption + Secret key 常量(nacosUsername/Password、consulToken、etcdUsername/Password)。认证信息不写在 CRD 明文里,而是引用一个 K8s Secret。
getAuthOption)。这是安全实践——敏感凭据和配置分离(和 Istio 的 SDS、OpenClaw 的密钥管控同理)。今日小结 + 动手
🧠 今天你应该能回答
- 为什么 Higress 要支持多注册中心?解决什么迁移痛点?
- 支持哪八种类型?Nacos 三代的区别?
- Watcher 接口的核心方法?它怎么屏蔽异构?
- UpdateService/Ready 两个回调的作用?
- vport 解决什么?认证信息怎么存?
✋ 动手
cd /Users/bitmart/work/codes/github/higress-group/higress
sed -n '27,99p' registry/watcher.go
ls registry/
cat registry/auth_option.go | head -35