服务发现与 McpBridge
Higress 区别于纯 K8s Ingress 最关键的能力——把 Nacos / ZK / Consul / Eureka 等注册中心的服务注入网关。本期 20 讲拆解 registry/ 各实现。
为什么要做服务来源
大型企业中,服务往往同时存在于多种注册中心:K8s Service + Nacos(Spring Cloud / Dubbo) + ZK(老 Dubbo) + 自建。Higress 一统这些来源,让 Ingress 可路由到任何 host,无需自己写 ServiceEntry。
McpBridge CRD
apiVersion: networking.higress.io/v1
kind: McpBridge
metadata: { name: default, namespace: higress-system }
spec:
registries:
- name: nacos1
type: nacos2
domain: nacos.example.com
port: 8848
nacosNamespaceId: public
nacosGroups: [DEFAULT_GROUP]
- name: zk1
type: zookeeper
domain: zk.example.com
port: 2181
zkServicesPath: [/dubbo]
一个 namespace 通常只有一份 default McpBridge,名称固定。
McpBridgeController 薄壳
49 行的控制器:监听 McpBridge 资源 → 把整个 spec 交给 IngressConfig 的 AddOrUpdateMcpBridge → IngressConfig 把它交给 registry/reconcile。Controller 自己不做协议解析。
registry/ 总览
registry/
watcher.go # 统一接口
auth_option.go # 鉴权选项
mcp_model.go # 服务模型
memory/ # 内存 ServiceRegistry
reconcile/ # 协调器
nacos/{,v2,address,mcpserver}
zookeeper/、consul/、eureka/{,client}
direct/ # 静态配置
proxy/ # 代理模式Watcher 接口
type Watcher interface {
Run()
Stop()
IsHealthy() bool
GetRegistryType() string
ReadyHandler(func(bool))
AppendServiceUpdateHandler(func(*v1.ServiceEntry, model.Event))
}
每种注册中心都要实现这套接口。统一把"服务变更 → Istio ServiceEntry"作为输出,下游无需关心具体协议。
reconcile 协调器
registry/reconcile/ 是真正的"大脑":
- 对比新旧 McpBridge.spec.registries;
- 需要新增的 → 工厂创建 Watcher 并 Run;
- 需要删除的 → Watcher.Stop;
- 变更(域名 / 端口)→ Stop 后重建。
所有 Watcher 共享同一份 memory.ServiceRegistry。
memory.ServiceRegistry
实现 Istio serviceregistry.Instance 接口的内存版本:所有注册中心来的 ServiceEntry 都注入这里。Pilot 通过 aggregate.Controller 从中读出 endpoints 推 EDS。
nacos/ v1
registry/nacos/watcher.go 适配 Nacos 1.x SDK。流程:登录 → SubscribeService → 收到 Instance 列表 → 转成 ServiceEntry → emit。Higress 维护 namespaceId × group 维度的订阅。
nacos/v2
registry/nacos/v2/ 适配 Nacos 2.x gRPC 协议。性能优于 1.x,但 SDK API 不同。Higress 通过 type=nacos2 区分。
nacos/address
registry/nacos/address/ 处理 Nacos 中存的"地址类型"配置(非服务实例,而是单纯的 ip:port 列表)。这是阿里内部常见用法,开源后保留。
nacos/mcpserver
Higress 把 Nacos 配置中心当作 MCP Server 注册表:通过监听 Nacos 配置发现 MCP Server 实例。代码在 registry/nacos/mcpserver/。
zookeeper Dubbo
registry/zookeeper/watcher.go:
- 连接 ZK,监听
/dubbo/{interfaceName}/providers/路径。 - 子节点是 URL(dubbo://ip:port/...?param=...),解析后转 ServiceEntry。
- 支持 Triple/Dubbo 协议。
consul
registry/consul/watcher.go 调 Consul HTTP API,watch /v1/health/service/{name} 拿健康实例。一个 watcher 一个 service。dc / token / namespace 通过 spec.consulDataCenter 等字段传入。
eureka
registry/eureka/{client,watcher}。Eureka 没有 watch 接口,只能定时 fetch /eureka/apps/。Higress 用 30s 定时 + delta API 优化。
direct 静态
registry/direct/ 提供"静态服务"能力:直接在 McpBridge 里写一份 ip:port 列表,不依赖外部注册中心。适合简单场景或调试。
proxy 代理模式
registry/proxy/ 把请求转发到外部 HTTP 注册中心代理(如自研服务发现)。这是兜底机制:协议不在标准列表里也能接。
健康检查与 IsHealthy
每个 Watcher 都要实现 IsHealthy()。控制面 /registry/status 端点会列出所有 watcher 状态,运维直接查。健康判定通常是"最后一次成功拉取距今 < 阈值"。
服务元数据合并
不同注册中心同名服务时,memory.ServiceRegistry 按 name + namespace + clusterId 去重。Endpoint 列表合并(按 ip:port 唯一)。这避免重复实例导致权重失衡。
ServiceEntry 注入
最终所有 watcher 把变更 emit 给 reconcile,reconcile 调用 memory.ServiceRegistry 的 UpdateService API,触发 PushContext 重建,进而 EDS / CDS 重推。
写一个新注册中心适配
步骤:
- 在
registry/下新建包myreg/。 - 实现
Watcher接口。 - 在 reconcile 工厂注册 type → 构造函数。
- 在 McpBridge CRD types 加 type 枚举。
- 写单测,参考
registry/nacos/watcher_test.go。