Documentation
¶
Overview ¶
Package registry 提供与服务注册中心无关的服务注册与发现抽象接口。
本包定义核心接口(Registrar、Discoverer、Subscriber、ConfigStore), 不依赖任何具体的注册中心 SDK。各注册中心(如 Nacos)的实现放在**嵌套模块**里 (github.com/oekit/registry/nacos、github.com/oekit/registry/nacosimpl)—— 它们各自把 Nacos SDK 的重依赖隔离在模块边界之外,父仓保持零第三方依赖。
注意:registry 是底层 SPI 和框架薄适配,只供 NNS、测试、极简接入使用。 不包含缓存、降级、singleflight 等治理能力。新服务推荐通过 nns 包接入。
设计目标 ¶
- 解耦:上层(如 nns 包)依赖接口而非具体 SDK,便于测试和替换实现。
- 可测试:通过接口可以轻松注入 mock,解决上层核心逻辑难以测试的问题。
- 可扩展:未来新增 etcd/consul/k8s 等实现时,上层无需改动。
三层架构 ¶
registry/nacos Nacos 客户端封装(嵌套模块:Bootstrap 配置、client 工厂、config 加载) registry provider 无关的抽象接口(本包,根模块) registry/nacosimpl Nacos 实现(嵌套模块:封装 naming_client/config_client)
上层门面 nns 依赖 registry 接口,默认使用 registry/nacosimpl 实现, 也可通过依赖注入替换为 mock 或其他 provider。
快速接入 ¶
使用 Nacos 实现:
import nacosimpl "github.com/oekit/registry/nacosimpl"
reg, err := nacosimpl.NewRegistrar(namingClient, nacosimpl.WithRegistrarGroup("DEFAULT_GROUP"))
if err != nil {
log.Fatal(err)
}
err = reg.Register(ctx, registry.Instance{
Service: "my-service",
IP: "10.0.0.1",
Port: 8080,
Metadata: version.Metadata(),
})
发现服务实例:
disc, err := nacosimpl.NewDiscoverer(namingClient, nacosimpl.WithDiscovererGroup("DEFAULT_GROUP"))
if err != nil {
log.Fatal(err)
}
instances, err := disc.Discover(ctx, "user-service")
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidHostAddr = errors.New("registry: host is not a dialable IP literal")
ErrInvalidHostAddr 表示解析出的注册主机**根本不是 IP 字面量**(#77)。 ParseAddr 的文档承诺是「保证注册出去的实例地址对其他节点可拨号」—— 「不是 IP」的主机名/垃圾串(域名、注错的 POD_IP、多余空格、带了端口) 此前与回环共用「解析成功且是回环 ⇒ 拒」的判据,解析失败分支未被覆盖, 垃圾值原样放行且 err==nil ⇒ 实例以不可拨通的地址注册、全程无告警。 与 ErrLoopbackAddr 同族(#64 同一条「可拨号」契约的另一条失效路径), 可通过 errors.Is(err, ErrInvalidHostAddr) 判定。
var ErrLoopbackAddr = errors.New("registry: loopback address is not dialable by other nodes")
ErrLoopbackAddr 表示解析出的注册地址是回环地址(127.0.0.0/8、::1)。 回环地址对其他节点不可拨号——以它注册出去的实例永远无法被其他节点访问, 故 ParseAddr 对回环结果 fail-closed 拒绝(#64)。 可通过 errors.Is(err, ErrLoopbackAddr) 判定。
var ErrNoInstances = errors.New("registry: no instances found")
ErrNoInstances 表示服务发现未找到任何实例。
Functions ¶
func EncodeTargetTags ¶
EncodeTargetTags 将 host 和 tags 编码为确定性的缓存 key。 tags 的 key 按字典序排序,确保相同 tags 产生相同结果(Go map 迭代顺序不确定)。 当 tags 为空时直接返回 host。
tag 的 key 与 value 均经 url.QueryEscape 转义(#63):此前值原样拼接, 值里含 ?/&/= 时两个不同的 (host, tags) 组合会编码出同一个 key—— 如 ("h", {"a": "b?c=d"}) 与 ("h?a=b", {"c": "d"}) 都得到 "h?a=b?c=d"—— 碰撞的两个目标共享缓存条目,服务发现路由错乱且无任何报错。 转义后分隔符只由编码器产生,key 对 (host, tags) 单射。
注意 host 本身不转义:消费方(如 sdbridge.ServiceNameFromDesc)按 「首个 ? 之前是服务名」的规则解码,host 含 ? 时该语义本就二义, 服务名不应包含 ?、&、=。
func ParseAddr ¶
ParseAddr 从 net.Addr 解析出 IP 和端口号。 当 host 为未指定地址(空、"::" 或 "0.0.0.0"——kitex/hertz 对 ":9090" 这类 通配监听时,listener.Addr() 与 WithServiceAddr 会产生这些形式)时, 自动使用 network.GetPodIP() 获取本机 IP(支持 K8s POD_IP),保证注册出去 的实例地址对其他节点可拨号。
拒绝面(fail-closed):
- 回环地址(127.0.0.0/8、::1)⇒ 包装 ErrLoopbackAddr(#64):此前 GetPodIP 失败会静默回退 127.0.0.1——IPv6-only 环境、多网卡取错首卡、 POD_IP 未注入时,实例以 127.0.0.1 注册到注册中心,其他节点永远拨不通, 全程无 error、无告警。显式监听回环地址(如 127.0.0.1:9090)同样被拒绝: 该地址对其他节点同样不可拨号,大概率是本机调试误配。
- 不是 IP 字面量的主机(域名/垃圾串)⇒ 包装 ErrInvalidHostAddr(#77, net.ParseIP 判据只覆盖「解析成功且是回环」,解析失败分支此前原样放行; core#87 已在 GetLocalIP 上游把非法 POD_IP 拦下,本判据是注册面的纵深, 覆盖自定义 net.Addr / 上游兜底之外的一切透传路径)。
- 带 zone 的 IPv6(如 fe80::1%eth0)⇒ 同样包装 ErrInvalidHostAddr: 地址本身合法,但 zone 是**本机**接口名——注册中心消费方拿到 `fe80::1%eth0` 永远拨不通(zone 语义只在本机有效),违背「对其他节点 可拨号」承诺,显式拒绝并写进文档(#77 的遗留语义决定项)。
这是 ekit 中解析注册地址的唯一实现,kitex/registry、hertz/registry、kitex/nns 应委托至此,避免逻辑重复。
Types ¶
type ConfigStore ¶
type ConfigStore interface {
// GetConfig 拉取指定 dataID 的配置内容。
//
// 返回空字符串表示配置不存在(非错误)。
GetConfig(ctx context.Context, dataID, group string) (string, error)
// ListenConfig 监听指定 dataID 的配置变更,内容变化时回调 onChange。
//
// onChange 接收最新的配置内容字符串。实现应确保回调在独立 goroutine
// 中执行或不会阻塞监听循环。
ListenConfig(ctx context.Context, dataID, group string, onChange func(data string)) error
// StopListenConfig 停止监听指定 dataID 的配置变更。
StopListenConfig(ctx context.Context, dataID, group string) error
}
ConfigStore 提供服务配置的拉取和动态监听能力。
这与服务发现(Discoverer/Subscriber)是正交关注点: 服务发现返回实例列表(IP/Port),而 ConfigStore 返回服务的运行时配置 (如超时、重试、负载均衡策略等,通常以 JSON 等格式存储)。
nns 包的 ServiceClient 同时使用 ConfigStore 和服务发现接口, 将配置和实例信息组合为完整的 ServiceBasic。
type Discoverer ¶
type Discoverer interface {
// Discover 根据服务名称返回健康实例列表。
Discover(ctx context.Context, serviceName string) ([]Instance, error)
// DiscoverAll 根据服务名称返回全部实例列表(包括不健康的实例)。
// 用于调试、监控等场景;生产调用应优先使用 Discover。
DiscoverAll(ctx context.Context, serviceName string) ([]Instance, error)
}
Discoverer 提供服务实例的拉取发现能力。
type Instance ¶
type Instance struct {
// Service 是服务名称。
Service string
// IP 是实例的 IP 地址。
IP string
// Port 是实例的端口。
Port int
// Weight 是实例的权重,用于加权负载均衡。
Weight float64
// Metadata 是实例的元数据,可携带版本、颜色、区域等信息。
Metadata map[string]string
// Group 是分组名称。空值时使用 Registrar 的默认 Group。
Group string
// Cluster 是集群名称。空值时使用 Registrar 的默认 Cluster。
Cluster string
}
Instance 表示注册中心中的一个服务实例,与具体 provider 无关。
type RegisterOption ¶
type RegisterOption struct {
// Weight 是实例权重,默认 10。
Weight float64
// Metadata 是实例元数据。
Metadata map[string]string
// Cluster 是集群名称(部分 provider 支持)。
Cluster string
// Group 是分组名称(部分 provider 支持)。
Group string
}
RegisterOption 是服务注册的可选配置,与具体 provider 无关。
各 provider 实现会将这些字段映射到自身 SDK 的参数。 如果某个字段在目标 provider 中不存在,实现应安全地忽略它。
func Apply ¶
func Apply(opts ...RegisterOptionFunc) *RegisterOption
Apply 将多个选项函数应用到一个新的 RegisterOption 上,返回最终配置。
用法:
opt := Apply(registry.WithWeight(20), registry.WithMetadata(meta))
type RegisterOptionFunc ¶
type RegisterOptionFunc func(*RegisterOption)
RegisterOptionFunc 是配置 RegisterOption 的函数选项类型。
func WithMetadata ¶
func WithMetadata(metadata map[string]string) RegisterOptionFunc
WithMetadata 设置服务实例的元数据。
多次调用会合并而非覆盖。
type Registrar ¶
type Registrar interface {
// Register 将服务实例注册到注册中心。
Register(ctx context.Context, inst Instance) error
// Deregister 从注册中心注销服务实例。
Deregister(ctx context.Context, inst Instance) error
}
Registrar 提供服务实例的注册和注销能力。
type Subscriber ¶
type Subscriber interface {
// Subscribe 订阅指定服务的实例变更,当实例列表变化时回调 cb。
Subscribe(ctx context.Context, serviceName string, cb func([]Instance)) error
// Unsubscribe 取消订阅指定服务的实例变更。
Unsubscribe(ctx context.Context, serviceName string) error
}
Subscriber 提供服务实例变更的订阅推送能力。
实现契约:cb 由实现侧在 SDK 的推送 goroutine 上调用,实现必须就地 隔离 cb 的 panic(recover 后转错误日志/错误面),不得让消费方回调的 异常沿 SDK 内部派发链(通常全程无 recover)上抛打死宿主进程——一个 服务不稳定的消费代码不能拖崩同进程其他订阅(#96)。
Directories
¶
| Path | Synopsis |
|---|---|
|
nacos
module
|
|
|
nacosimpl
module
|
|
|
Package registrymocks 提供 registry 包 4 个接口(Registrar/Discoverer/Subscriber/ConfigStore) 的统一 mock 实现,供单元测试使用(原为 ekit internal 包,拆分后跨模块复用故公开)。
|
Package registrymocks 提供 registry 包 4 个接口(Registrar/Discoverer/Subscriber/ConfigStore) 的统一 mock 实现,供单元测试使用(原为 ekit internal 包,拆分后跨模块复用故公开)。 |
|
Package sdbridge 提供服务发现适配器的框架无关共享核心。
|
Package sdbridge 提供服务发现适配器的框架无关共享核心。 |