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

news2024/11/17 13:56:49

背景

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode Python - 51. N 皇后

目录 题目答案运行结果 题目 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不同的 n …

深度学习——SAM(Segment-Anything)代码详解

目录 引言代码目录segment-anything 代码详解build_sam.pypredictor.pyautomatic_mask_generator.py 引言 从去年年初至今,SAM(Segment Anything )已经问世快一年了,SAM凭借其强大而突出的泛化性能在各项任务上取得了优异的表现,广大的研究者…

ChromeDriver 122 版本为例 国内下载地址及安装教程

ChromeDriver 国内下载地址 https://chromedriver.com/download 靠谱 千千万万别下载错了 先确认 Chrome 浏览器版本 以 win64 版本为例 那我们下载这一个啊,不要下载错了 下载地址贴在这哈 https://storage.googleapis.com/chrome-for-testing-public/122.0.…

linux安全--CentOS7安装Tomcat,远程管理ManagerApp

目录 1.Tomcat安装 2.Tomcat远程管理 1.Tomcat安装 下载安装包并解压 tar xf apache-tomcat-7.0.54.tar.gz -C /usr/local/apache-tomcat_7.0.54/tomcat启停 启动 ./startup.sh 停止 ./shutdown.sh 2.Tomcat远程管理 找到tomcat文件夹中webapps/manager/META-INF/contex…

IDEA中导入eclipse运行的java项目

本篇文章主要的内容是在IDEA中导入eclipse运行的java项目,亲测有效。 话不多说,直接开整。 前提:先打开idea软件,界面如下: 开始按下方步骤依次走即可。 1、file --> new --> Project from Existing Sources..…

OPPO后端二面,凉了!

这篇文章的问题来源于一个读者之前分享的 OPPO 后端凉经,我对比较典型的一些问题进行了分类并给出了详细的参考答案。希望能对正在参加面试的朋友们能够有点帮助! Java String 为什么是不可变的? public final class String implements java.io.Seri…

C++提高笔记(三)---STL容器(vector、deque)

1、vector容器 1.1vector基本概念 功能:vector数据结构和数组非常相似,也称为单端数组 vector与普通数组区别:不同之处在于数组是静态空间,而vector可以动态扩展 动态扩展:并不是在原空间之后续接新空间&#xff0…

ES6(三):Iterator、Generator、类的用法、类的继承

一、迭代器Iterator 迭代器是访问数据的一个接口,是用于遍历数据结构的一个指针,迭代器就是遍历器 const items[one,two,three];//创建新的迭代器const ititems[Symbol.iterator]();console.log(it.next()); done:返回false表示遍历继续&a…

Kafka MQ 生产者

Kafka MQ 生产者 生产者概览 尽管生产者 API 使用起来很简单,但消息的发送过程还是有点复杂的。图 3-1 展示了向 Kafka 发送消息的主要步骤。 我们从创建一个 ProducerRecord 对象开始,ProducerRecord 对象需要包含目标主题和要发送的内容。我们还可以…

linux命令深入研究——cat

cat命令,“猫”,可以理解为瞄一眼文件内容,其中可以用重定向符号对文件进行一些修改,如增加,删除文件内容,其命令参数如-n,-s,-b可以输出带有行号的行 如果想要快速删除文件内容&…

[全志T113]:Tina SDK安装

[全志T113]:Tina SDK安装 SDK安装与补丁 SDK下载地址 https://pan.baidu.com/s/1wxUeYQZaSgAPGorGOVcJxA?pwdtina 1.解压SDK tar -zxvf Tina-Linux-20220815.tar.gz cd Tina-Linux2.安装补丁: $ wget http://dl.mangopi.org/tina/prebuilt.tar.gz …

【数据结构】双向链表及LRU缓存的实现

目录 前言 1. 在原有的自定义链表类 Linked 的基础上,添加新的 “节点添加”方法 addNode(Node node) 测试用例 测试结果 2. 在自定义链表类的基础上,使用双重循环“强力” 判断两个节点是否发生相交 测试用例 测试结果 3. 在自定义链表类的基础上…

Linux基础开发工具之yum与vim

1. Linux软件包管理器——yum 1.1 什么是软件包? 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, …

JavaWeb06-MVC和三层架构

目录 一、MVC模式 1.概述 2.好处 二、三层架构 1.概述 三、MVC与三层架构 四、练习 一、MVC模式 1.概述 MVC是一种分层开发的模式,其中 M:Model,业务模型,处理业务 V: View,视图,界面展…

浅谈HTTP 和 HTTPS (中间人问题)

前言 由于之前的文章已经介绍过了HTTP , 这篇文章介绍 HTTPS 相对于 HTTP 做出的改进 开门见山: HTTPS 是对 HTTP 的加强版 主要是对一些关键信息 进行了加密 一.两种加密方式 1.对称加密 公钥 明文 密文 密文 公钥 明文 2.非对称加密 举个例子就好比 小区邮箱 提供一…

学习SSM的记录(八)-- SSM整合项目《任务列表案例》

前端程序搭建和运行 项目预览 接口分析 1.学习计划分页查询 需求:查询对应数据页数据 uri:schedule/{pageSize}/{currentPage} 请求方式:get 响应数据:json {"code":200,"flag":true,"data"…

MVP 聚技站|生成式 AI 系列(六):关于嵌入和 RAG 的那些有趣的事

点击蓝字 关注我们 MVP 聚技站 微软最有价值专家推出“MVP 聚技站”系列主题专栏,邀请多位微软最有价值专家,针对初学者、开发者感兴趣的技术话题,带来专业的技术课程讲解与实践经验分享,帮助大家更快掌握最新的技术技能。 随着人…

前端框架的发展史介绍框架特点

目录 1.前端框架的发展历程 2.官网、优缺点、使用场景 2.1 jQuery 2.2 AngularJS 2.3 React 2.4 Vue.js 2.5 Angular 1.前端框架的发展历程 jQuery(2006年):jQuery是一个非常流行的JavaScript库,用于简化DOM操作和事件处理…

从零开始学习深度学习库-1:前馈网络

你好!欢迎来到这个系列的第一篇文章,我们将尝试用Python构建自己的深度学习库。在这篇文章中,我们将开始编写一个简单的前馈神经网络。我们将仅在这篇文章中处理前向传播,并在下一篇文章中处理网络的训练。这篇文章将介绍基本的前…

3.2 Beautiful Soup 的使用

目录 一、Beautiful Soup 的简介 二、解析器 三、基本使用 四、节点选择器 1 选择元素 2 获取名称、属性、文本内容 五、方法选择器 1 find_all 传入 name 节点名 传入 attrs 属性 传入 text 2 find 六、CSS 选择器 1 实例 2 获取属性 3 获取文本 七、结语 一…