服务注册发现
概述
服务注册发现是微服务架构中的核心基础设施,它解决了服务实例动态变化时的寻址问题。在 CloudWeGo 生态中,Kitex 和 Hertz 都提供了完善的服务注册发现机制,支持多种主流注册中心。
为什么需要服务注册发现?
在传统单体架构中,服务之间的调用通过固定地址完成。但在微服务架构中:
- 服务实例数量动态变化(扩缩容、故障恢复)
- 服务实例地址动态分配(容器化环境)
- 需要实时感知服务实例的健康状态
服务注册发现机制通过注册中心统一管理服务实例信息,实现服务的自动发现与负载均衡。
核心内容
1. 服务注册发现原理
基本概念
- 服务提供者(Provider):提供服务的实例,启动时向注册中心注册自己的地址
- 服务消费者(Consumer):调用服务的客户端,从注册中心获取服务提供者列表
- 注册中心(Registry):存储服务实例信息,提供注册、发现、健康检查等功能
工作流程
1. 服务启动 → 向注册中心注册
2. 注册中心 → 维护服务实例列表
3. 消费者启动 → 订阅服务列表
4. 注册中心 → 推送/拉取服务实例变更
5. 消费者 → 根据实例列表进行调用
6. 服务下线 → 注销注册2. Kitex 服务注册
服务端注册
Kitex 服务端通过 registry 扩展点实现服务注册:
go
package main
import (
"github.com/cloudwego/kitex/server"
"github.com/kitex-contrib/registry-nacos/registry"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
"github.com/nacos-group/nacos-sdk-go/vo"
)
func main() {
cli, err := clients.NewNamingClient(
vo.NacosClientParam{
ServerConfigs: []constant.ServerConfig{
{
IpAddr: "127.0.0.1",
Port: 8848,
},
},
},
)
if err != nil {
panic(err)
}
r, err := registry.NewDefaultNacosRegistry(cli)
if err != nil {
panic(err)
}
svr := echo.NewServer(
new(EchoImpl),
server.WithRegistry(r),
server.WithServiceAddr(&net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8888}),
)
if err := svr.Run(); err != nil {
log.Println("server stopped with error:", err)
} else {
log.Println("server stopped")
}
}客户端发现
Kitex 客户端通过 resolver 扩展点实现服务发现:
go
package main
import (
"github.com/cloudwego/kitex/client"
"github.com/kitex-contrib/registry-nacos/resolver"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
"github.com/nacos-group/nacos-sdk-go/vo"
)
func main() {
cli, err := clients.NewNamingClient(
vo.NacosClientParam{
ServerConfigs: []constant.ServerConfig{
{
IpAddr: "127.0.0.1",
Port: 8848,
},
},
},
)
if err != nil {
panic(err)
}
r, err := resolver.NewDefaultNacosResolver(cli)
if err != nil {
panic(err)
}
c, err := echo.NewClient(
"echo",
client.WithResolver(r),
)
if err != nil {
panic(err)
}
ctx := context.Background()
resp, err := c.Echo(ctx, &api.Request{Message: "Hello"})
if err != nil {
panic(err)
}
log.Println(resp.Message)
}3. 支持的注册中心
Nacos
Nacos 是阿里巴巴开源的服务发现和配置管理平台,功能完善,适合生产环境:
go
import (
"github.com/kitex-contrib/registry-nacos/registry"
"github.com/kitex-contrib/registry-nacos/resolver"
)
r, _ := registry.NewDefaultNacosRegistry(cli)
resolver, _ := resolver.NewDefaultNacosResolver(cli)Consul
Consul 是 HashiCorp 开源的服务网格解决方案:
go
import (
"github.com/kitex-contrib/registry-consul/registry"
"github.com/kitex-contrib/registry-consul/resolver"
)
r, _ := registry.NewConsulRegister("127.0.0.1:8500")
resolver, _ := resolver.NewConsulResolver("127.0.0.1:8500")etcd
etcd 是 CoreOS 开源的高可用键值存储系统:
go
import (
"github.com/kitex-contrib/registry-etcd/registry"
"github.com/kitex-contrib/registry-etcd/resolver"
)
r, _ := registry.NewEtcdRegister("127.0.0.1:2379")
resolver, _ := resolver.NewEtcdResolver([]string{"127.0.0.1:2379"})ZooKeeper
ZooKeeper 是 Apache 开源的分布式协调服务:
go
import (
"github.com/kitex-contrib/registry-zookeeper/registry"
"github.com/kitex-contrib/registry-zookeeper/resolver"
)
r, _ := registry.NewZookeeperRegister([]string{"127.0.0.1:2181"}, 40*time.Second)
resolver, _ := resolver.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second)4. 自定义注册中心
实现自定义注册中心需要满足以下接口:
go
type Registry interface {
Register(info *Info) error
Deregister(info *Info) error
}
type Resolver interface {
Resolve(target string, desc string) (Result, error)
Target(ctx context.Context, target string) string
}自定义 Registry 示例
go
package myregistry
import (
"github.com/cloudwego/kitex/pkg/registry"
)
type MyRegistry struct {
endpoints []string
}
func NewMyRegistry(endpoints []string) *MyRegistry {
return &MyRegistry{endpoints: endpoints}
}
func (r *MyRegistry) Register(info *registry.Info) error {
return nil
}
func (r *MyRegistry) Deregister(info *registry.Info) error {
return nil
}自定义 Resolver 示例
go
package myresolver
import (
"github.com/cloudwego/kitex/pkg/discovery"
)
type MyResolver struct {
endpoints []string
}
func NewMyResolver(endpoints []string) *MyResolver {
return &MyResolver{endpoints: endpoints}
}
func (r *MyResolver) Resolve(target string, desc string) (discovery.Result, error) {
return discovery.Result{
CacheKey: target,
Instances: []discovery.Instance{
discovery.NewInstance("tcp", "127.0.0.1", 8888, 10, nil),
},
}, nil
}
func (r *MyResolver) Target(ctx context.Context, target string) string {
return target
}5. 服务元数据
服务注册时可以携带丰富的元数据信息:
go
info := ®istry.Info{
ServiceName: "echo",
Addr: &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: 8888,
},
Weight: 100,
Tags: map[string]string{
"version": "v1.0.0",
"env": "production",
"region": "cn-east-1",
},
}6. 健康检查
注册中心通过健康检查机制确保服务实例的可用性:
go
cli, err := clients.NewNamingClient(
vo.NacosClientParam{
ServerConfigs: []constant.ServerConfig{
{
IpAddr: "127.0.0.1",
Port: 8848,
},
},
ClientConfig: &constant.ClientConfig{
NotLoadCacheAtStart: true,
UpdateCacheWhenEmpty: true,
},
},
)最佳实践
1. 注册中心选型
| 注册中心 | 优势 | 适用场景 |
|---|---|---|
| Nacos | 功能全面、支持配置中心 | Spring Cloud 生态、阿里云 |
| Consul | 多数据中心、DNS 接口 | HashiCorp 生态、混合云 |
| etcd | 简单可靠、K8s 原生 | Kubernetes 环境 |
| ZooKeeper | 成熟稳定、强一致性 | Hadoop 生态、传统架构 |
2. 服务命名规范
go
serviceName := "user-service"
groupName := "DEFAULT_GROUP"
namespaceId := "public"3. 故障处理
go
svr := echo.NewServer(
new(EchoImpl),
server.WithRegistry(r),
server.WithRegistryInfo(®istry.Info{
ServiceName: "echo",
Addr: addr,
Weight: 100,
}),
)小结
本章介绍了 CloudWeGo 生态中的服务注册发现机制:
- 核心概念:理解服务注册发现的工作原理和基本流程
- Kitex 集成:掌握服务端注册和客户端发现的使用方法
- 注册中心支持:了解 Nacos、Consul、etcd、ZooKeeper 等主流注册中心的集成方式
- 自定义扩展:学会实现自定义的 Registry 和 Resolver
- 最佳实践:掌握注册中心选型、服务命名、故障处理等实践技巧
服务注册发现是微服务架构的基础设施,合理选择和使用注册中心对于构建稳定可靠的微服务系统至关重要。