Skip to content

服务注册发现

概述

服务注册发现是微服务架构中的核心基础设施,它解决了服务实例动态变化时的寻址问题。在 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 := &registry.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(&registry.Info{
        ServiceName: "echo",
        Addr:        addr,
        Weight:      100,
    }),
)

小结

本章介绍了 CloudWeGo 生态中的服务注册发现机制:

  1. 核心概念:理解服务注册发现的工作原理和基本流程
  2. Kitex 集成:掌握服务端注册和客户端发现的使用方法
  3. 注册中心支持:了解 Nacos、Consul、etcd、ZooKeeper 等主流注册中心的集成方式
  4. 自定义扩展:学会实现自定义的 Registry 和 Resolver
  5. 最佳实践:掌握注册中心选型、服务命名、故障处理等实践技巧

服务注册发现是微服务架构的基础设施,合理选择和使用注册中心对于构建稳定可靠的微服务系统至关重要。