consul服务注册与发现(go)-学习笔记

参考博客

1、服务实例接口与默认实现

type ServiceInstance interface {// 获取服务实例的唯一IDGetInstanceId() string// 获取服务IDGetServiceId() string// 获取服务实例的主机名或IP地址GetHost() string// 获取服务实例的端口号GetPort() int// 判断服务实例是否使用HTTPSIsSecure() bool// 获取服务实例的元数据(键值对形式)GetMetadata() map[string]string
}type DefaultServiceInstance struct {InstanceId stringServiceId  stringHost       stringPort       intSecure     boolMetadata   map[string]string
}// 构造函数
func NewDefaultServiceInstance(serviceId string, host string, port int, secure bool,metadata map[string]string, instanceId string) (*DefaultServiceInstance, error) {// 如果没有传入 IP 则获取一下,这个方法在多网卡的情况下,并不好用if len(host) == 0 {localIP, err := util.GetLocalIP()if err != nil {return nil, err}host = localIP}//若instanceId为空,自动生成“服务ID-时间戳-随机数(1000-9999)”if len(instanceId) == 0 {instanceId = serviceId + "-" + strconv.FormatInt(time.Now().Unix(), 10) + "-" + strconv.Itoa(rand.Intn(9000)+1000)}return &DefaultServiceInstance{InstanceId: instanceId, ServiceId: serviceId, Host: host, Port: port, Secure: secure, Metadata: metadata}, nil
}func (serviceInstance DefaultServiceInstance) GetInstanceId() string {return serviceInstance.InstanceId
}func (serviceInstance DefaultServiceInstance) GetServiceId() string {return serviceInstance.ServiceId
}func (serviceInstance DefaultServiceInstance) GetHost() string {return serviceInstance.Host
}func (serviceInstance DefaultServiceInstance) GetPort() int {return serviceInstance.Port
}func (serviceInstance DefaultServiceInstance) IsSecure() bool {return serviceInstance.Secure
}func (serviceInstance DefaultServiceInstance) GetMetadata() map[string]string {return serviceInstance.Metadata
}

2、定义服务注册和剔除的方法

type ServiceRegistry interface {Register(serviceInstance cloud.ServiceInstance) boolDeregister()
}

具体实现:

import ("errors""fmt""github.com/hashicorp/consul/api""strconv""unsafe"
)type consulServiceRegistry struct {// 服务实例缓存(服务ID->实例ID->实例)serviceInstances     map[string]map[string]cloud.ServiceInstance//Consul客户端client               api.Client//当前本地服务实例localServiceInstance cloud.ServiceInstance
}func (c consulServiceRegistry) Register(serviceInstance cloud.ServiceInstance) bool {// 创建注册到consul的服务到registration := new(api.AgentServiceRegistration)registration.ID = serviceInstance.GetInstanceId()registration.Name = serviceInstance.GetServiceId()registration.Port = serviceInstance.GetPort()var tags []stringif serviceInstance.IsSecure() {tags = append(tags, "secure=true")} else {tags = append(tags, "secure=false")}if serviceInstance.GetMetadata() != nil {var tags []stringfor key, value := range serviceInstance.GetMetadata() {tags = append(tags, key+"="+value)}registration.Tags = tags}registration.Tags = tagsregistration.Address = serviceInstance.GetHost()// 增加consul健康检查回调函数check := new(api.AgentServiceCheck)schema := "http"if serviceInstance.IsSecure() {schema = "https"}check.HTTP = fmt.Sprintf("%s://%s:%d/actuator/health", schema, registration.Address, registration.Port)check.Timeout = "5s"check.Interval = "5s"check.DeregisterCriticalServiceAfter = "20s" // 故障检查失败30s后 consul自动将注册服务删除registration.Check = check// 注册服务到consulerr := c.client.Agent().ServiceRegister(registration)if err != nil {fmt.Println(err)return false}//初始化服务实例缓存结构//若未初始化,服务ID-实例ID-实例if c.serviceInstances == nil {c.serviceInstances = map[string]map[string]cloud.ServiceInstance{}}//获取特定服务的实例集合//从外层map中查询该服务ID对应的内层mapservices := c.serviceInstances[serviceInstance.GetServiceId()]//初始化空实例集合//处理首次注册情况,创建新的内层map,用处存储该服务的实例集合if services == nil {services = map[string]cloud.ServiceInstance{}}//添加当前实例到集合services[serviceInstance.GetInstanceId()] = serviceInstance//更新外层缓存	//确保外层map中服务ID对应内层map是最新版本	c.serviceInstances[serviceInstance.GetServiceId()] = services//记录当前实例c.localServiceInstance = serviceInstancereturn true
}// deregister a service
func (c consulServiceRegistry) Deregister() {//检查服务实例缓存是否初始化if c.serviceInstances == nil {return}//从缓存中获取当前服务ID对应的实例集合(实例ID->实例对象)services := c.serviceInstances[c.localServiceInstance.GetServiceId()]//检查实例集合是否存在if services == nil {return}//从本地缓存移除当前实例delete(services, c.localServiceInstance.GetInstanceId())//清空服务记录if len(services) == 0 {delete(c.serviceInstances, c.localServiceInstance.GetServiceId())}//从Consul注销服务_ = c.client.Agent().ServiceDeregister(c.localServiceInstance.GetInstanceId())//重置当前实例记录c.localServiceInstance = nil
}// new a consulServiceRegistry instance
// token is optional
func NewConsulServiceRegistry(host string, port int, token string) (*consulServiceRegistry, error) {if len(host) < 3 {return nil, errors.New("check host")}if port <= 0 || port > 65535 {return nil, errors.New("check port, port should between 1 and 65535")}config := api.DefaultConfig()config.Address = host + ":" + strconv.Itoa(port)config.Token = tokenclient, err := api.NewClient(config)if err != nil {return nil, err}return &consulServiceRegistry{client: *client}, nil
}

在这里插入图片描述
测试用例:

func TestConsulServiceRegistry(t *testing.T) {//初始化Consul注册中心客户端host := "127.0.0.1"port := 8500registryDiscoveryClient, _ := extension.NewConsulServiceRegistry(host, port, "")//获取本地IP地址ip, err := util.GetLocalIP()if err != nil {t.Error(err)}//创建服务实例信息serviceInstanceInfo, _ := cloud.NewDefaultServiceInstance("go-user-server", "", 8090,false, map[string]string{"user":"zyn"}, "")//注册服务实例
registryDiscoveryClient.Register(serviceInstanceInfo)r := gin.Default()// 健康检测接口,其实只要是 200 就认为成功了r.GET("/actuator/health", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})err = r.Run(":8090")if err != nil{registryDiscoveryClient.Deregister()}
}

3、服务发现

  • 获取所有的服务列表
  • 获取指定的服务的所有实例信息

接口定义:

type DiscoveryClient interface {/*** Gets all ServiceInstances associated with a particular serviceId.* @param serviceId The serviceId to query.* @return A List of ServiceInstance.*/GetInstances(serviceId string) ([]cloud.ServiceInstance, error)/*** @return All known service IDs.*/GetServices() ([]string, error)
}

具体实现:

type consulServiceRegistry struct {serviceInstances     map[string]map[string]cloud.ServiceInstanceclient               api.ClientlocalServiceInstance cloud.ServiceInstance
}func (c consulServiceRegistry) GetInstances(serviceId string) ([]cloud.ServiceInstance, error) {//查询指定服务catalogService, _, _ := c.client.Catalog().Service(serviceId, "", nil)//若查询到服务实例if len(catalogService) > 0 {//转换Consul数据到标准格式result := make([]cloud.ServiceInstance, len(catalogService))for index, sever := range catalogService {s := cloud.DefaultServiceInstance{InstanceId: sever.ServiceID,ServiceId:  sever.ServiceName,Host:       sever.Address,Port:       sever.ServicePort,Metadata:   sever.ServiceMeta,}result[index] = s}return result, nil}return nil, nil
}
//返回服务名称列表
func (c consulServiceRegistry) GetServices() ([]string, error) {//查询所有服务services, _, _ := c.client.Catalog().Services(nil)result := make([]string, unsafe.Sizeof(services))index := 0for serviceName, _ := range services {result[index] = serviceNameindex++}return result, nil
}// new a consulServiceRegistry instance
// token is optional
func NewConsulServiceRegistry(host string, port int, token string) (*consulServiceRegistry, error) {if len(host) < 3 {return nil, errors.New("check host")}if port <= 0 || port > 65535 {return nil, errors.New("check port, port should between 1 and 65535")}config := api.DefaultConfig()config.Address = host + ":" + strconv.Itoa(port)config.Token = tokenclient, err := api.NewClient(config)if err != nil {return nil, err}return &consulServiceRegistry{client: *client}, nil
}

测试用例:

func TestConsulServiceDiscovery(t *testing.T) {host := "127.0.0.1"port := 8500token := ""registryDiscoveryClient, err := extension.NewConsulServiceRegistry(host, port, token)if err != nil {panic(err)}t.Log(registryDiscoveryClient.GetServices())t.Log(registryDiscoveryClient.GetInstances("go-user-server"))
}

结果:

consul_service_registry_test.go:57: [consul go-user-server      ] <nil>consul_service_registry_test.go:59: [{go-user-server-1602590661-56179 go-user-server 127.0.0.1 8090 false map[user:zyn]}] <nil>

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

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

相关文章

【AI】prompt engineering

prompt engineering ## prompt engineering ## prompt engineering ## prompt engineering 一、定义 Prompt 工程&#xff08;Prompt Engineering&#xff09;是指在使用语言模型&#xff08;如 ChatGPT、文心一言等&#xff09;等人工智能工具时&#xff0c;设计和优化输入提…

Python 字典和集合(常见的映射方法)

本章内容的大纲如下&#xff1a; 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响&#xff08;什么样的数据类型可作为键、不可预知的 顺序&#xff0c;等等&#xff09; 常见的映射方法 映射类型…

对抗Prompt工程:构建AI安全护栏的攻防实践

大语言模型的开放性与自然语言交互特性使其面临前所未有的Prompt工程攻击威胁。本文通过分析2021-2023年间157个真实越狱案例&#xff0c;揭示语义混淆、上下文劫持、多模态组合三重攻击路径的技术原理&#xff0c;提出融合动态意图拓扑分析&#xff08;DITA&#xff09;、对抗…

STL c++ list——模拟实现

结点类的模拟实现 list是一个带头双向循环链表 因需要实现一个节点类&#xff0c;其中包含哨兵位&#xff08;用来标识位置&#xff09;&#xff0c;节点信息&#xff08;val数据&#xff0c;prev后指针&#xff0c;next后指针&#xff09; template<class T> struct …

ORM、Mybatis和Hibernate、Mybatis使用教程、parameterType、resultType、级联查询案例、resultMap映射

DAY21.1 Java核心基础 ORM Object Relationship Mapping 对象关系映射 面向对象的程序到—关系型数据库的映射 比如java – MySQL的映射 ORM框架就是实现这个映射的框架 Hibernate、Mybatis、MybatisPlus、Spring Data JPA、Spring JDBC Spring Data JPA的底层就是Hiber…

【学习自用】配置文件中的配置项

server.port服务器端口&#xff0c;常被用于指定应用程序运行时所监听的端口号spring.datasource.url用于配置数据源的数据库连接URLspring.datasource.username用于指定连接数据库的用户名spring.datasource.password用于配置数据源时设置数据库连接密码的属性mybatis.mapper-…

使用protobuf编译提示无法打开包括文件: ‘absl/log/absl_log.h’: No such file or directory

问题原因 Protobuf 依赖 Abseil&#xff1a; Protobuf 3.20 版本开始依赖 Abseil&#xff0c;但你的系统未正确安装或配置 Abseil。 头文件路径未包含&#xff1a; 编译器找不到 absl/log/absl_log.h&#xff0c;可能是因为 Abseil 未正确安装或未在项目中设置包含路径。 …

Spring AI Alibaba 文档检索使用

一、文档检索 (Document Retriever)简介 1、核心概念 文档检索&#xff08;DocumentRetriever&#xff09;是一种信息检索技术&#xff0c;旨在从大量未结构化或半结构化文档中快速找到与特定查询相关的文档或信息。文档检索通常以在线(online)方式运行。 DocumentRetriever通…

前端面试核心知识点整理:从 JavaScript 到 Vue 全解析

一、JavaScript 异步编程核心:Promise 与 async/await 1. Promise 深度解析 定义:Promise 是处理异步操作的对象,代表一个异步操作的最终状态(成功 / 失败)。三种状态: pending(进行中):初始状态,异步操作未完成。fulfilled(已成功):异步操作成功,调用 resolve …

音视频(四)android编译

前言 前面已经讲了在windows上应用了&#xff0c;这章主要讲述android上编译 1&#xff1a;环境 git 如果失败 直接跑到相应网站 手动下载 ubuntu22.* android ndk r21e download:https://developer.android.google.cn/ndk/downloads/index.html?hluk 为什么用这个&#xff0…

【kind管理脚本-3】脚本函数说明文档 —— 便捷使用 kind 创建、删除、管理集群脚本

下面是一份详细的说明文档&#xff0c;介绍该脚本的功能、用法及各部分的含义&#xff0c;供您参考和使用&#xff1a; Kind 集群管理脚本说明文档 此脚本主要用于管理 Kind&#xff08;Kubernetes IN Docker&#xff09;集群&#xff0c;提供创建、删除、导出 kubeconfig、加…

【计算机行业发展与重塑】

计算机行业正经历前所未有的变革&#xff0c;AI技术的爆发式发展与产业升级的深度融合&#xff0c;正在重塑行业格局与就业市场。以下从行业趋势、AI的核心价值、就业需求三个维度展开分析。 一、行业趋势&#xff1a;AI驱动下的多极增长 AI成为核心引擎 生成式AI的突破&#…

(高频SQL50题)1667. 修复表中的名字

问题 表&#xff1a; Users ------------------------- | Column Name | Type | ------------------------- | user_id | int | | name | varchar | ------------------------- user_id 是该表的主键(具有唯一值的列)。 该表包含用户的 ID 和名字…

基于人工智能的医学影像关联分析:利用潜在空间几何混杂因素校正法|文献速递-深度学习医疗AI最新文献

Title 题目 AI-based association analysis for medical imaging using latent-spacegeometric confounder correction 基于人工智能的医学影像关联分析&#xff1a;利用潜在空间几何混杂因素校正法 01 文献速递介绍 人工智能&#xff08;AI&#xff09;已成为各个领域的…

开源免费虚拟化软件PVE功能介绍

Proxmox VE&#xff08;PVE&#xff09;提供了一个基于 Web UI&#xff08;管理界面&#xff09;的虚拟化管理平台&#xff0c;用户可以通过浏览器管理 虚拟机&#xff08;VM&#xff09;、容器&#xff08;LXC&#xff09;、存储、网络、备份、用户权限等。 一、PVE Web 界面…

新球体育比分状态监控

文章目录 目标分析监控逻辑代码目标分析 网页监控地址:aHR0cHM6Ly9saXZlLnRpdGFuMDA3LmNvbS9pbmRleDJpbjEuYXNweD9pZD0x 监控逻辑 比分等数据主要是依赖JS加载得到,通过ajax后端进行渲染 代码 # -*- coding: utf-8 -*-import warnings warnings.filterwarnings(ignore) f…

【lodash的omit函数详解 - 从入门到精通】

lodash的omit函数详解 - 从入门到精通 小白视角&#xff1a;什么是omit&#xff1f; omit在英文中意为"忽略"或"省略"。在编程中&#xff0c;它就是从一个对象中删除不需要的属性&#xff0c;返回一个新对象。 // 原始对象 const person {name: "…

软考笔记9——数据库技术基础

第九章节——数据库技术基础 数据库技术基础 第九章节——数据库技术基础一、基本概念1. 数据库与数据库系统2. 数据库的三级模式2.1 内模式2.2 概念模式2.3 外模式2.4 数据库的两级映射2.5 数据库设计的基本步骤 二、数据模型1. 基本概念2. E-R模型2.1 实体2.2 联系2.3 属性 3…

Django分页教程及示例

推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 完整代码示例:结论Django的分页模块允许你将大量数据分割成更小的块(页面)。这对于以可管理的方式显示项目列表,如博客文章或产品…

int 与 Integer 的区别详解

1. 本质区别 特性intInteger类型基本数据类型&#xff08;Primitive&#xff09;包装类&#xff08;Wrapper Class&#xff09;存储位置栈&#xff08;或作为对象成员在堆中&#xff09;堆&#xff08;对象实例&#xff09;默认值0null&#xff08;可能导致 NullPointerExcept…