服务注册与发现(Consul/Etcd/Nacos)
服务注册与发现
服务注册与发现是微服务架构中的重要组成部分,它是实现服务治理的基础。在 sponge 微服务框架中,服务注册与发现机制由 Consul、Etcd、Nacos 等三种实现,下面是服务注册与发现使用示例:
服务注册示例代码
import "github.com/go-dev-frame/sponge/pkg/servicerd/registry"
func registerService(scheme string, host string, port int) (registry.Registry, *registry.ServiceInstance) {
var (
instanceEndpoint = fmt.Sprintf("%s://%s:%d", scheme, host, port)
cfg = config.Get()
iRegistry registry.Registry
instance *registry.ServiceInstance
err error
id = cfg.App.Name + "_" + scheme + "_" + host
logField logger.Field
)
switch cfg.App.RegistryDiscoveryType {
// registering service with consul
case "consul":
iRegistry, instance, err = consul.NewRegistry(
cfg.Consul.Addr,
id,
cfg.App.Name,
[]string{instanceEndpoint},
)
if err != nil {
panic(err)
}
logField = logger.Any("consulAddress", cfg.Consul.Addr)
// registering service with etcd
case "etcd":
iRegistry, instance, err = etcd.NewRegistry(
cfg.Etcd.Addrs,
id,
cfg.App.Name,
[]string{instanceEndpoint},
)
if err != nil {
panic(err)
}
logField = logger.Any("etcdAddress", cfg.Etcd.Addrs)
// registering service with nacos
case "nacos":
iRegistry, instance, err = nacos.NewRegistry(
cfg.NacosRd.IPAddr,
cfg.NacosRd.Port,
cfg.NacosRd.NamespaceID,
id,
cfg.App.Name,
[]string{instanceEndpoint},
)
if err != nil {
panic(err)
}
logField = logger.String("nacosAddress", fmt.Sprintf("%v:%d", cfg.NacosRd.IPAddr, cfg.NacosRd.Port))
}
if instance != nil {
msg := fmt.Sprintf("register service address to %s", cfg.App.RegistryDiscoveryType)
logger.Info(msg, logField, logger.String("id", id), logger.String("name", cfg.App.Name), logger.String("endpoint", instanceEndpoint))
return iRegistry, instance
}
return nil, nil
}
// ------------------------------------------------------------------------------------------
iRegistry, serviceInstance := registerService("http", "127.0.0.1", 8080)
// register service
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
if err := iRegistry.Register(ctx, serviceInstance); err != nil {
panic(err)
}
// deregister service
ctx, _ = context.WithTimeout(context.Background(), 3*time.Second)
if err := iRegistry.Deregister(ctx, serviceInstance); err != nil {
return err
}
服务发现示例代码
import "github.com/go-dev-frame/sponge/pkg/servicerd/discovery"
var cliOptions = []grpccli.Option{}
var endpoint string
switch grpcClientCfg.RegistryDiscoveryType {
// discovering services using consul
case "consul":
endpoint = "discovery:///" + grpcClientCfg.Name // Connecting to grpc services by service name
cli, err := consulcli.Init(cfg.Consul.Addr, consulcli.WithWaitTime(time.Second*5))
if err != nil {
panic(fmt.Sprintf("consulcli.Init error: %v, addr: %s", err, cfg.Consul.Addr))
}
iDiscovery := consul.New(cli)
cliOptions = append(cliOptions, grpccli.WithDiscovery(iDiscovery))
// discovering services using etcd
case "etcd":
endpoint = "discovery:///" + grpcClientCfg.Name // Connecting to grpc services by service name
cli, err := etcdcli.Init(cfg.Etcd.Addrs, etcdcli.WithDialTimeout(time.Second*5))
if err != nil {
panic(fmt.Sprintf("etcdcli.Init error: %v, addr: %s", err, cfg.Etcd.Addrs))
}
iDiscovery := etcd.New(cli)
cliOptions = append(cliOptions, grpccli.WithDiscovery(iDiscovery))
// discovering services using nacos
case "nacos":
// example: endpoint = "discovery:///serverName.scheme"
endpoint = "discovery:///" + grpcClientCfg.Name + ".grpc"
cli, err := nacoscli.NewNamingClient(
cfg.NacosRd.IPAddr,
cfg.NacosRd.Port,
cfg.NacosRd.NamespaceID)
if err != nil {
panic(fmt.Sprintf("nacoscli.NewNamingClient error: %v, ipAddr: %s, port: %d",
err, cfg.NacosRd.IPAddr, cfg.NacosRd.Port))
}
iDiscovery := nacos.New(cli)
cliOptions = append(cliOptions, grpccli.WithDiscovery(iDiscovery))
}
serverNameExampleConn, err = grpccli.DialInsecure(context.Background(), endpoint, cliOptions...)
if err != nil {
panic(fmt.Sprintf("dial rpc server failed: %v, endpoint: %s", err, endpoint))
}
在 gRPC 服务中使用服务注册与发现
sponge 创建的gRPC服务支持 Consul
、Etcd
、Nacos
作为服务注册与发现,下面以 Consul
作为示例,介绍如何启用服务注册和服务发现功能,帮助开发者快速完成配置和实现,如果使用 Etcd
或 Nacos
,操作也是一样的。
启用服务注册
服务注册功能用于将服务注册到服务注册中心(如 Consul、Etcd、Nacos 等),方便其他服务进行发现和调用。以下步骤演示如何在 Consul 上启用服务注册:
配置文件修改
打开配置文件
configs/xxx.yml
。在
app
配置块下,将host
的值设置为本机 ip 地址或域名,如果服务和 consul 不在同一个机器上,不能使用127.0.0.1。在
app
配置块下,将registryDiscoveryType
的值设置为consul
,并去掉该字段前面的注释符号(#
)。在配置文件末尾找到
consul
配置块,取消其注释,并填写 Consul 的地址,例如:consul: address: "192.168.3.37:8500"
修改服务初始化代码
- 打开文件
cmd/xxx/initial/createService.go
,根据以下步骤调整代码: - 注释掉
// case 1, create a grpc/http service without registry
下的代码块。 - 取消注释
// case 2, create a grpc service and register it with consul or etcd or nacos
下的代码块。 - 取消注释
// register service with consul or etcd or nacos, select one of them to use
部分,建议删除不使用的 Etcd 和 Nacos 的注册代码,仅保留 Consul 的代码。
- 打开文件
启用服务发现
服务发现功能用于从服务注册中心动态获取目标服务的地址,实现负载均衡和高可用。以下步骤演示如何在 Consul 上启用服务发现:
配置文件修改
打开配置文件
configs/xxx.yml
。在
grpcClient
配置块下,将registryDiscoveryType
的值设置为consul
,并去掉该字段前的注释符号(#
)。在配置文件末尾找到
consul
配置块,取消注释,并填写 Consul 的地址,例如:consul: address: "192.168.3.37:8500"
修改客户端代码
- 打开文件
internal/rpcclient/xxx.go
,如果文件不存在,请在 sponge 生成代码的页面通过【Public】 → 【生成 gRPC 服务连接代码】功能生成该文件。 - 按以下步骤调整代码:
- 取消注释
// discovery service with consul or etcd or nacos, select one of them to use
下的代码块,建议删除不需要的 Etcd 和 Nacos 相关代码,仅保留 Consul 代码。 - 取消注释
// using service discovery
下的代码块。
- 取消注释
- 打开文件
在 web 服务中使用服务注册与发现示例
sponge 创建的 web 服务默认没有集成服务注册与发现代码,如果需要使用,可以按照以下步骤进行配置:
添加服务注册代码
服务注册功能用于将服务注册到服务注册中心(如 Consul、Etcd、Nacos 等),方便其他服务进行发现和调用。以下步骤演示如何在 Consul 上启用服务注册:
配置文件修改
打开配置文件
configs/xxx.yml
。在
app
配置块下,将host
的值设置为本机 ip 地址或域名,如果服务和 consul 不在同一个机器上,不能使用127.0.0.1。在
app
配置块下,将registryDiscoveryType
的值设置为consul
,并去掉该字段前面的注释符号(#
)。在配置文件末尾找到
consul
配置块,取消其注释,并填写 Consul 的地址,例如:consul: address: "192.168.3.37:8500"
修改服务初始化代码
- 打开文件
cmd/xxx/initial/createService.go
,根据以下步骤调整代码: - 把文件 createService.go 中的
registerService
函数代码块复制过来,建议删除不使用的 Etcd 和 Nacos 的注册代码,仅保留 Consul 的代码。 - 把文件 createService.go 中的25到30行代码复制过来,替换
// create a http service
下的代码块。
- 打开文件
添加服务发现代码
服务发现功能用于从服务注册中心动态获取目标服务的地址,实现负载均衡和高可用。以下步骤演示如何在 Consul 上启用服务发现:
配置文件修改
打开配置文件
configs/xxx.yml
。在
grpcClient
配置块下,将registryDiscoveryType
的值设置为consul
,并去掉该字段前的注释符号(#
)。在配置文件末尾找到
consul
配置块,取消注释,并填写 Consul 的地址,例如:consul: address: "192.168.3.37:8500"
客户端服务发现代码
var rrIndex int
func pickOneRoundRobin(sis []discovery.ServiceInstance) (string, error) {
if len(sis) == 0 {
return "", fmt.Errorf("no available service instances")
}
addr := sis[rrIndex%len(sis)].Endpoints[0]
rrIndex++
return addr, nil
}
func discoveryAndCall() {
// 通过服务名称从consul服务获取地址
endpoint = "discovery:///" + your_service_name
cli, err := consulcli.Init(cfg.Consul.Addr, consulcli.WithWaitTime(time.Second*10))
if err != nil {
panic(fmt.Sprintf("consulcli.Init error: %v, addr: %s", err, cfg.Consul.Addr))
}
iDiscovery := consul.New(cli)
sis, err := iDiscovery.GetService(context.Background(), your_service_name)
if err != nil {
panic(fmt.Sprintf("GetService error:%v, serverName: %s", err, your_service_name))
}
addr, err := pickOneRoundRobin(sis) // 轮询策略
// 获取到addr地址后,http client调用请求
// ......
}