nacos做注册注册中心go语言实战教程(服务的注册与获取)

背景

随着访问量的逐渐增大,单体应用结构渐渐不满足需求,在微服务出现之后引用被拆分为一个个的服务,服务之间可以互相访问。初期服务之间的调用只要知道服务地址端口即可,而服务会出现增减、故障、升级等变化导致端口和ip也变化,被调用者的变化也会导致调用者变化。这样很不方便。

注册中心就诞生了,注册中心就像DNS服务器,注册中心是C/S架构,服务调用者通过Client调用服务名称,被调用者通过Client上传服务名称和ip并发送心跳检测该服务的健康状态。注册中心为server端保存服务名称和服务的ip地址及端口,这样不论被调用者服务如何变化,只要服务名称不变,调用者都不说影响。

常见的注册中心:

  • etcd
  • consul
  • eureka
  • nacos
  • zookeeper

go实现nacos注册中心

Nacos的核心API中定义了两个接口NamingService和ConfigService。服务注册与发现围绕着NamingService展开,而配置管理则围绕着ConfigService展开。

Nacos的4个核心特性:服务发现和服务健康监测、动态配置服务、动态DNS服务、服务及其元数据管理。

在这里插入图片描述

作为注册中心的功能来说,Nacos提供的功能与其他主流框架很类似,基本都是围绕服务实例注册、实例健康检查、服务实例获取这三个核心来实现的。

在这里插入图片描述

nacos注册中心基本流程:

  • 服务实例启动将自身注册到Nacos注册中心,随后维持与注册中心的心跳;
  • 心跳维持策略为每5秒向Nacos Server发送一次心跳,并携带实例信息(服务名、实例IP、端口等);
  • Nacos Server也会向Client主动发起健康检查,支持TCP/Http;
  • 15秒内无心跳且健康检查失败则认为实例不健康,如果30秒内健康检查失败则剔除实例;
  • 服务消费者通过注册中心获取实例,并发起调用;

其中服务发现支持两种场景:第一,服务消费者直接向注册中心发送获取某服务实例的请求,注册中心返回所有可用实例,但一般不推荐此种方式;第二、服务消费者向注册中心订阅某服务,并提交一个监听器,当注册中心中服务发生变化时,监听器会收到通知,消费者更新本地服务实例列表,以保证所有的服务均可用。

nacos数据模型

Nacos数据模型的Key由三元组唯一确定,Namespace默认是空串,公共命名空间(public),分组默认是DEFAULT_GROUP

在这里插入图片描述
在这里插入图片描述Nacos基于namespace的设计是为了做多环境以及多租户数据(配置和服务)隔离的。如果用户有多套环境(开发、测试、生产等环境)。

一个服务模型如下:

在这里插入图片描述

在这里插入图片描述

图片来源官方网站:nacos.io

服务注册

go nacos SDK

首先需要有一个rpc框架例如Zero,kit,grpc,kitex等,生成rpc服务的代码来模拟服务注册与获取。如下所示使用kitex框架生成rpc service,这里使用nacos官方go语言的sdk和rpc框架无关联,任选框架即可。

本项目demo

server端:
在这里插入图片描述

client直接连接:

import (
	"github.com/cloudwego/kitex/client"
	"order/rpc/orderclient"
)

func Client() orderclient.RPCClient {
	rpcClient, err := orderclient.NewRPCClient("orderserver", client.WithHostPorts("192.168.5.118:10000"))
	if err != nil {
		panic(err)
	}
	return rpcClient
}

在上述的代码中添加nacos配置中心,首先区别存在一个运行的nacos服务,如下:

在这里插入图片描述

go连接nacos实现服务注册参考go-nacos-example

公网域名连接参考

包装工具库简化连接注册配置的方法

服务注册在启动类连接nacos注册中心,注册服务,如下:

package main

import (
	...
	"github.com/flairamos/go-component/nacos"
	...
)
func main() {
	opts := kitexInit()

	svr := orderservice.NewServer(new(OrderServiceImpl), opts...)

	param := vo.RegisterInstanceParam{
		Ip:          "127.0.0.1",
		Port:        8848,
		Enable:      true,
		Healthy:     true,
		Weight:      10,
		Metadata:    map[string]string{"version": "1.0"},
		ClusterName: "test",
		GroupName:   "dev_food_platform",
		Ephemeral:   true,
		ServiceName: "test_app",
	}
	config := nacos.DefaultClient("public", "mysql", "dev_food_platform", nil)
	service := nacos.RegisterService(config, param)
	if !service {
		log.Println("nacos register failed")
		return
	}
	log.Println("nacos register success")
	err := svr.Run()
	if err != nil {
		klog.Error(err.Error())
	}
}

代码中的nacos是小编封装的包,sdk源码参考nacos-go-sdk,如下:

// 官方源码
success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
    Ip:          "10.0.0.11",
    Port:        8848,
    ServiceName: "demo.go",
    Weight:      10,
    Enable:      true,
    Healthy:     true,
    Ephemeral:   true,
    Metadata:    map[string]string{"idc":"shanghai"},
    ClusterName: "cluster-a", // 默认值DEFAULT
    GroupName:   "group-a",   // 默认值DEFAULT_GROUP
})

启动服务:
在这里插入图片描述
nacso注册中心查看:
在这里插入图片描述

注册配置如下:

"github.com/nacos-group/nacos-sdk-go/vo"

vo.RegisterInstanceParam{
		Ip:          "127.0.0.1",
		Port:        8848,
		Enable:      true,
		Healthy:     true,
		Weight:      10,
		Metadata:    map[string]string{"version": "1.0"},
		ClusterName: "test",
		GroupName:   "dev.food_platform",
		Ephemeral:   true,
		ServiceName: "test_app",
	}

在这里插入图片描述
在上述过程中服务已经注册到nacso注册中心了,完成了第一步。

服务健康检查

nacos服务健康检查是客户端进行的,通过配置来开启,无需手敲发送心跳,判断活跃,更新服务,剔除亚健康实例等代码。

Nacos中临时实例会定时发送心跳维持活性,基本的健康检查流程基本如下:Nacos客户端会维护一个定时任务,每隔5秒发送一次心跳请求,以确保自己处于活跃状态。Nacos服务端在15秒内如果没收到客户端的心跳请求,会将该实例设置为不健康,在30秒内没收到心跳,会将这个临时实例摘除。

这些都不需要开发者手敲代码,在nacos中有一个github.com/nacos-group/nacos-sdk-go/vo.RegisterInstanceParam配置参数,在服务注册的时候需要用到,其中Ephemeral属性表示临时实例,将其设置为true则开启服务心跳模式。

这个维护心跳的模式的线程是基于主函数的,主要主函数服务一直运行,发送心跳就会一直进行下去。

如果把他设置为false,如下:

在这里插入图片描述

不管服务有没有正常启动这个记录都在注册中心,只能通过代码注销实例:


success, err := namingClient.DeregisterInstance(vo.DeregisterInstanceParam{
    Ip:          "127.0.0.1",
    Port:        8848,
    ServiceName: "test_app",
    Ephemeral:   true,
    Cluster:     "test", // 默认值DEFAULT
    GroupName:   "dev_food_platform",   // 默认值DEFAULT_GROUP
})

多服务实例注册

注意区分服务与实例的区别,一个服务包含若干实例,如user服务可能在不同主机注册那么该服务包含若干ip地址。

如果只有一个实例,该实例宕机系统就崩了,多实例通过服务名获取健康实例提高了系统稳定性。

为了系统的稳定性服务一般都是集群部署,因此在注册的时候可以看到,如下配置:


success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
    Ip:          "10.0.0.11",
    Port:        8848,
    ServiceName: "demo.go",
    Weight:      10,
    Enable:      true,
    Healthy:     true,
    Ephemeral:   true,
    Metadata:    map[string]string{"idc":"shanghai"},
    ClusterName: "cluster-a", // 默认值DEFAULT
    GroupName:   "group-a",   // 默认值DEFAULT_GROUP
})

在这里插入图片描述
在nacos注册时首先由配置信息确定集群Cluster,再去更具服务实例的信息查找如namespace,group,servicename等信息定位服务。注册阶段没有dataId,dataid在注册阶段就是servicename。

多个服务注册重复调用注册方法即可:


success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
    Ip:          "10.0.0.11",
    Port:        8848,
    ServiceName: "demo.go",
    Weight:      10,
    Enable:      true,
    Healthy:     true,
    Ephemeral:   true,
    Metadata:    map[string]string{"idc":"shanghai"},
    ClusterName: "cluster-a", // 默认值DEFAULT
    GroupName:   "group-a",   // 默认值DEFAULT_GROUP
})

注意事项:

  • 没有使用集群(ClusterName),自定义字符串即可但同一名称的服务要保持一致。
  • 注册时的配置ip与端口并没有验证,可以随意写,在不同机器上需要获取实际值。
  • 不同主机注册同一服务服务名称(ServiceName)和组(GroupName)必须一致

开发的不同阶段以namespace区分如dev,prod;不同的项目以GroupName区分,如order,user;不同的实例以ServiceName区分,如demo服务可能有,192.168.5.117:8000与192.168.5.118:8000两个实例。

同一服务不同实例的表现形式如下:

在这里插入图片描述
在这里插入图片描述
记录了服务的两个实例的信息。

获取服务

rpc服务也是基于c/s架构的,在之前的章节中通过nacos client注册服务,该服务处于运行状态nacos server会维护该服务的活性。接下来就是服务的获取了。

服务获取也是基于nacos client的,而且是在rpc 的client。在很多的rpc框架如grpc等框架rpc的客户端与服务端都是生成式的,通过生成的方法创建服务端与客户端。这种方式也被称为直连方式。如下:

import (
	"github.com/cloudwego/kitex/client"
	"order/rpc/orderclient"
)
// order/rpc/orderclient是框架生成的创建客户端对的目录
// 调用生成方法创建客户端实例
// 传入服务名与ip端口地址
func Client() orderclient.RPCClient {
	rpcClient, err := orderclient.NewRPCClient("orderserver", client.WithHostPorts("192.168.5.118:10000"))
	if err != nil {
		panic(err)
	}
	return rpcClient
}

其实上述代码的服务名没起作用,传入空字符串也可以,关键是ip与端口。

这种直连的方式弊端也很明显,打那个传入的ip:port宕机后,该客户端也无法使用,其所在服务也受影响。当然也可以将所有ip配置,形成ip列表,使用一些算法获取其中一个作为参数创建客户端实例等一些方法解决,但是了注册中心是目前最好的方法。

引入nacos后,任然需要使用生成的方法,但是此时地址就不在是通过ip:port获取了,而是nacos client通过服务名称获取,nacos client通过namespace,servicename,cluster,group等信息获取一个服务或者一个服务实例列表,当然最好是获取一个健康的正在运行的实例,将其ip:port传递,即完成调用。

这样一来,服务调用者不用保存任何ip信息,提前约定服务名称即可,十分方便。

在这里插入图片描述
图片显示的是nacos-go-sdk提供的获取实例的方法。最好直接使用获取一个健康的实例的方法(免去开发者筛选),如下:

// SelectOneHealthyInstance将会按加权随机轮询的负载均衡策略返回一个健康的实例
// 实例必须满足的条件:health=true,enable=true and weight>0
instance, err := namingClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
    ServiceName: "demo.go",
    GroupName:   "group-a",             // 默认值DEFAULT_GROUP
    Clusters:    []string{"cluster-a"}, // 默认值DEFAULT
})
// "github.com/nacos-group/nacos-sdk-go/model"
// model.Instance
type Instance struct {
    Valid       bool              `json:"valid"`
    Marked      bool              `json:"marked"`
    InstanceId  string            `json:"instanceId"`
    Port        uint64            `json:"port"`
    Ip          string            `json:"ip"`
    Weight      float64           `json:"weight"`
    Metadata    map[string]string `json:"metadata"`
    ClusterName string            `json:"clusterName"`
    ServiceName string            `json:"serviceName"`
    Enable      bool              `json:"enabled"`
    Healthy     bool              `json:"healthy"`
    Ephemeral   bool              `json:"ephemeral"`
}

获取的实例对象如上,将其ip与端口作为参数传递给rpc client即可。


import (
	"fmt"
	"github.com/cloudwego/kitex/client"
	"github.com/flairamos/go-component/nacos"
	"github.com/nacos-group/nacos-sdk-go/vo"
	"order/rpc/orderclient"
)

// 直接连接
func Client() orderclient.RPCClient {
	rpcClient, err := orderclient.NewRPCClient("orderserver", client.WithHostPorts("192.168.5.118:10000"))
	if err != nil {
		panic(err)
	}
	return rpcClient
}

// nacos注册中心连接
func ClientFormNacos() orderclient.RPCClient {
	var param = vo.SelectOneHealthInstanceParam{
		Clusters:    []string{"test"},
		ServiceName: "test_app1",
		GroupName:   "dev_food_platform",
	}
	config := nacos.DefaultClient("public", "mysql", "dev_food_platform", nil)
	instance, err := nacos.SelectOneHealthyInstance(config, param)
	if err != nil {
		panic(err)
	}
	addr := fmt.Sprintf("%s:%d", instance.Ip, instance.Port)
	rpcClient, err := orderclient.NewRPCClient("test_app1", client.WithHostPorts(addr))
	return rpcClient
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/455525.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

欧科云链做客Google Cloud与WhalerDAO专题论坛,畅谈Web3数据机遇

3月10日,由Google Cloud、WhalerDAO和baidao data主办,以Web3AI 2024 DATA POWER为主题的分享会在北京中关村举行。欧科云链高级研究员Jason Jiang受邀参加活动,带来“从链上数据发掘Web3时代的无限机遇”的主题分享。 Web3.0核心要素始终是链…

如何从 Mac 电脑外部硬盘恢复删除的数据文件

本文向您介绍一些恢复 Mac 外置硬盘数据的快速简便的方法。 Mac 的内部存储空间通常不足以存储所有数据。因此,许多用户通过外部驱动器扩展存储或创建数据备份。然而,与几乎所有其他设备一样,从外部硬盘驱动器丢失有价值的数据并不罕见。由于…

第二证券|炒股最好用的6个指标?

炒股存在以下好用的6个目标: 1、kdj目标 当k线从下方往上穿过d线时,构成金叉,是一种买入信号,投资者能够考虑在此刻买入一些个股,其间kdj金叉方位越低,买入信号越强;当k线从上往下穿过d线时&a…

HTML静态网页成品作业(HTML+CSS)——电影肖申克的救赎介绍设计制作(1个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有1个页面。 二、作品演示 三、代…

“SRP模型+”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI 指数的生态质量评价及拓展应用教程

原文链接:“SRP模型”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI 指数的生态质量评价及拓展应用教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247597452&idx5&snf723d9e5858a269d00e15dbe2c7d3dc0&chksmfa823c6…

Python算法(列表排序)

一。冒泡排序: 列表每两个相邻的数,如果前面比后面大,则交换这两个数 一趟排序完成后,则无序区减少一个数,有序区增加一个数 时间复杂度:O(n*n) 优化后:已经排序好后立马停止,加快…

Ubuntu 14.04:PaddleOCR基于PaddleHub Serving的服务部署(失败)

目录 一、为什么使用一键服务部署 二、安装 paddlehub 1.8 2.1 安装前的环境准备 2.2 安装paddlehub 1.8 2.2.1 安装paddlehub 2.2.2 检测安装是否成功 2.2.3 检查本地与远端PaddleHub-Server的连接状态 2.2.4 测试使用 2.3 其他 2.3.1 如何卸载、pip常用命令、常见…

FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+HLS图像缩放+多路视频拼接,提供4套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收发送本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收OSD动态字符叠加输出应用本方案的SDI接收HLS多路视频融合叠加应用本方案的SDI接收G…

Pandas DataFrame 写入 Excel 的三种场景及方法

一、引言 本文主要介绍如何将 pandas 的 DataFrame 数据写入 Excel 文件中,涉及三个不同的应用场景: 单个工作表写入:将单个 DataFrame 写入 Excel 表中;多个工作表写入:将多个 DataFrame 写入到同一个 Excel 表中的…

2024考研计算机考研复试-每日重点(第十九期)

公众号“准研计算机复试”,超全大佬复试资料,保姆级复试,80%的题目都是上岸大佬提供的。 研宝们,App更新啦! 操作系统: 10.★什么是中断? 中断是指计算机运行过程中,出现某些意外时…

win11 ubuntu子系统 开代理 调试 openai 接口

我的是laravel项目,步骤如下 步骤1:配置WSL以使用代理 首先,确保WSL中的所有请求都通过你的代理服务器。你可以通过在WSL的shell配置文件(如~/.bashrc或~/.zshrc)中设置环境变量来实现。打开终端,编辑对应…

snowny-小诺框架-标签tabs消失不见

可能是由于,在配置菜单时,排序数字过小造成的,将排序数字改成大于0的数字就好使了。

数码管的静态显示(二)

1.原理 要按照上图的顺序传递位选和段选的数据。 因为q0是最高位,共阳极数码管结构是dp....a,所以应该先传入低位a,而a在上图中的8段2进制编码中是seg[7],所以段选信号的顺序是seg[0],...seg[7]。 因为输出信号是两个时钟&#x…

【绩效管理】某连锁购物中心绩效考核体系搭建咨询项目

随着企业规模的扩大,员工数量不断增加,与之相关的人事管理工作的复杂性也随之增大。但是由于行业的特点,该购物中心的人员整体素质偏低,且自成立以来,该中心重经营轻管理,其人力资源管理水平也有待提升。在…

雅特力车规级MCU-AT32A403A开发板评测 06 GC9A01 SPI-LCD 1.28圆形屏幕

雅特力车规级MCU-AT32A403A开发板评测 06 GC9A01 SPI-LCD 1.28圆形屏幕 硬件平台 AT32A403A Board开发板 1.28寸圆形彩色TFT显示屏高清IPS 模块240X240 SPI接口GC9A01 产品介绍 推荐一个屏幕资料参考网站 http://www.lcdwiki.com/1.28inch_IPS_Module 1.28寸圆形IPS彩屏&…

2024.3.13 C++

思维导图 设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream>using namespace…

微信小程序一次性订阅requestSubscribeMessage授权和操作详解

一次性订阅&#xff1a;用户订阅一次发一次通知 一、授权 — requestSubscribeMessage Taro.requestSubscribeMessage({tmplIds: [], // 需要订阅的消息模板的id的集合success (res) {console.log("同意授权", res)},fail(res) {console.log(拒绝授权, res)}})点击或…

【Hibernate-Validate】常用注解

常用注解: NotNull:被注释的元素(任何元素)必须不为 nul, 集合为空也是可以的。NotEmpty:用来校验字符串、集合、map、数组不能为null或也不能为空(字符串传入空格也不可以)(集合需至少包含一个元素)NotBlank:被注释的字符串的必须非空&#xff0c;空格也不行&#xff0c;空字…

在ubuntu20通过docker部署zabbix6

部署Zabbix 6.x服务器在Ubuntu 20.04 LTS系统上使用Docker的方式可以简化安装过程并实现容器化管理。以下是一个简化的步骤指南&#xff1a; 步骤1&#xff1a;安装Docker和Docker Compose 确保你的Ubuntu系统已经安装了Docker和Docker Compose。如果没有&#xff0c;请执行以…

下载指定版本的pytorch

下载网址&#xff1a;https://download.pytorch.org/whl/torch_stable.html 参考博客网址&#xff1a;https://blog.csdn.net/wusuoweiieq/article/details/132773977