Golang基于consul实现服务注册与发现

SpringCloud微服务架构之注册中心 | Consul、Nacos 介绍SpringCloud注册中心,包括Consul,Nacos。 阅读详情

前提搭建consul集群,至少需要一个consul agent

consul服务注册与发现相关文档见官网:

 

consul api https://www.consul.io/api-docs/agent/service

服务注册

 

服务注销

 

服务发现

https://www.consul.io/api-docs/health

 

 

代码实现

服务注册与发现

discovery/discovery_client.go

实现服务注册、服务注销和服务发现的通用功能

package discovery

import (
	"log"
	"fmt"
	"time"
	"bytes"
	"strconv"
	"context"
	"net/http"
	"encoding/json"
)

// 服务实例结构体
type InstanceInfo struct {
	ID                string                     `json:"ID"`                // 服务实例ID
	Service           string                     `json:"Service,omitempty"` // 服务发现时返回的服务名
	Name              string                     `json:"Name"`              // 服务名
	Tags              []string                   `json:"Tags,omitempty"`    // 标签,可用于进行服务过滤
	Address           string                     `json:"Address"`           // 服务实例HOST
	Port              int                        `json:"Port"`              // 服务实例端口
	Meta              map[string]string          `json:"Meta,omitempty"`    // 元数据
	EnableTagOverride bool                       `json:"EnableTagOverride"` // 是否允许标签覆盖
	Check             `json:"Check,omitempty"`   // 健康检查相关配置
	Weights           `json:"Weights,omitempty"` // 权重
	CurWeight         int                        `json:"CurWeights,omitempty"` // 当前权重
}

//健康检查相关的配置
type Check struct {
	DeregisterCriticalServiceAfter string   `json:"DeregisterCriticalServiceAfter"` // 多久之后注销服务
	Args                           []string `json:"Args,omitempty"`                 // 请求参数
	HTTP                           string   `json:"HTTP"`                           // 健康检查地址
	Interval                       string   `json:"Interval,omitempty"`             // Consul 主动检查间隔
	TTL                            string   `json:"TTL,omitempty"`                  // 服务实例主动维持心跳间隔,与Interval只存其一
}

//权重
type Weights struct {
	Passing int `json:"Passing"`
	Warning int `json:"Warning"`
}

//服务发现的客户端
type DiscoveryClient struct {
	host string // Consul 的 Host
	port int    // Consul 的 端口
}

func NewDiscoveryClient(host string, port int) *DiscoveryClient {
	return &DiscoveryClient{
		host: host,
		port: port,
	}
}

//服务注册
func (consulClient *DiscoveryClient) Register(ctx context.Context, serviceName, instanceId, healthCheckUrl string, instanceHost string, instancePort int, meta map[string]string, weights *Weights) error {

	instanceInfo := &InstanceInfo{
		ID:                instanceId,
		Name:              serviceName,
		Address:           instanceHost,
		Port:              instancePort,
		Meta:              meta,
		EnableTagOverride: false,
		Check: Check{
			DeregisterCriticalServiceAfter: "30s",
			HTTP:                           "http://" + instanceHost + ":" + strconv.Itoa(instancePort) + healthCheckUrl,
			Interval:                       "15s",
		},
	}

	if weights != nil {
		instanceInfo.Weights = *weights
	} else {
		instanceInfo.Weights = Weights{
			Passing: 10,
			Warning: 1,
		}
	}

	byteData, err := json.Marshal(instanceInfo)

	if err != nil {
		log.Printf("json format err: %s", err)
		return err
	}

	req, err := http.NewRequest("PUT",
		"http://"+consulClient.host+":"+strconv.Itoa(consulClient.port)+"/v1/agent/service/register",
		bytes.NewReader(byteData))

	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json;charset=UTF-8")
	client := http.Client{}
	client.Timeout = time.Second * 2
	resp, err := client.Do(req)

	if err != nil {
		log.Printf("register service err : %s", err)
		return err
	}

	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		log.Printf("register service http request errCode : %v", resp.StatusCode)
		return fmt.Errorf("register service http request errCode : %v", resp.StatusCode)
	}

	log.Println("register service success")
	return nil
}

//服务注销
func (consulClient *DiscoveryClient) Deregister(ctx context.Context, instanceId string) error {
	req, err := http.NewRequest("PUT",
		"http://"+consulClient.host+":"+strconv.Itoa(consulClient.port)+"/v1/agent/service/deregister/"+instanceId, nil)

	if err != nil {
		log.Printf("req format err: %s", err)
		return err
	}

	client := http.Client{}
	client.Timeout = time.Second * 2

	resp, err := client.Do(req)

	if err != nil {
		log.Printf("deregister service err : %s", err)
		return err
	}

	resp.Body.Close()

	if resp.StatusCode != 200 {
		log.Printf("deresigister service http request errCode : %v", resp.StatusCode)
		return fmt.Errorf("deresigister service http request errCode : %v", resp.StatusCode)
	}

	log.Println("deregister service success")

	return nil
}

//服务发现
func (consulClient *DiscoveryClient) DiscoverServices(ctx context.Context, serviceName string) ([]*InstanceInfo, error) {

	req, err := http.NewRequest("GET",
		"http://"+consulClient.host+":"+strconv.Itoa(consulClient.port)+"/v1/health/service/"+serviceName, nil)

	if err != nil {
		log.Printf("req format err: %s", err)
		return nil, err
	}

	client := http.Client{}
	client.Timeout = time.Second * 2

	resp, err := client.Do(req)
	if err != nil {
		log.Printf("discover service err : %s", err)
		return nil, err
	}

	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		log.Printf("discover service http request errCode : %v", resp.StatusCode)
		return nil, fmt.Errorf("discover service http request errCode : %v", resp.StatusCode)
	}

	var serviceList []struct {
		Service InstanceInfo `json:"Service"`
	}
	err = json.NewDecoder(resp.Body).Decode(&serviceList)
	if err != nil {
		log.Printf("format service info err : %s", err)
		return nil, err
	}

	instances := make([]*InstanceInfo, len(serviceList))
	for i := 0; i < len(instances); i++ {
		instances[i] = &serviceList[i].Service
	}
	return instances, nil

}


 

服务注册代码示例

register.go  (注意修改consul和服务器参数配置)

package main

import (
	"io"
	"os"
	"log"
	"fmt"
	"flag"
	"syscall"
	"strings"
	"context"
	"net/http"
	"os/signal"

	"consul_study /discovery"
	
	"github.com/google/uuid"
)

func main() {
	consulAddr := flag.String("consul.addr", "192.168.20.165", "consul address")  //consul addr
	consulPort := flag.Int("consul.port", 8500, "consul port") //consul端口
	servicePort := flag.Int("service.port", 12310, "service port")  //服务端口
	serviceName := flag.String("service.name", "instance", "service name")  //服务名称
	serviceAddr := flag.String("service.addr", "192.168.7.41", "service addr")  //服务地址


	flag.Parse()
	ctx,_ := context.WithCancel(context.Background())

	instanceId := *serviceName + "-" + strings.Replace(uuid.New().String(),"-","",-1)

	client := discovery.NewDiscoveryClient(*consulAddr, *consulPort) //获取consul客户端,用于服务注册和发现

	//将服务注册到consul中
	err := client.Register(ctx , *serviceName, instanceId, "/health", *serviceAddr, *servicePort, nil, nil)

	if err != nil {
		log.Fatal(err)
	}

	//开启http服务,并注册handle
	go func() {
		http.HandleFunc("/health",checkHealth)
		http.ListenAndServe(fmt.Sprintf("%s:%d",*serviceAddr,*servicePort),nil)
	}()

	// 监控系统信号,等待 ctrl + c 系统信号通知服务关闭
	c := make(chan os.Signal, 1)
	go func() {
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	}()
	log.Printf("exit %s", <-c)
	client.Deregister(ctx,instanceId)
	log.Printf("Deregister service %s",instanceId)

}

func checkHealth(w http.ResponseWriter, _ *http.Request) {
	io.WriteString(w,"SUCCESS")
}

 

服务发现代码示例

discovery.go  (注意修改consul和服务器参数配置)


package main

import (
	"os"
	"log"
	"fmt"
	"flag"
	"time"
	"syscall"
	"context"
	"os/signal"
	
	"consul_study/discovery"
)

func main() {
	consulAddr := flag.String("consul.addr", "192.168.20.165", "consul address")  //consul addr
	consulPort := flag.Int("consul.port", 8500, "consul port") //consul端口
	serviceName := flag.String("service.name", "instance", "service name")  //服务名称



	flag.Parse()
	ctx,_ := context.WithCancel(context.Background())

	client := discovery.NewDiscoveryClient(*consulAddr, *consulPort) //获取consul客户端,用于服务注册和发现


	c := make(chan os.Signal,1)
	go func() {
		signal.Notify(c,syscall.SIGINT,syscall.SIGTERM)
	}()

	//定时刷新示例
	ticker := time.NewTicker(time.Second*5)

	for {
		select {
		case <- ticker.C:
			instance,err := client.DiscoverServices(ctx,*serviceName)
			if err != nil {
				log.Fatal(err)
			}

			fmt.Println("get instance num",len(instance))
			for _,v := range instance {
				fmt.Printf("instanceID:%s,address:%s,port:%d\n",v.ID,v.Address,v.Port)
			}

		case <-c:
			log.Println("discovery service exit!")
		}
	}

}

测试

 

1.我们先启动服务发现模块

> go run discovery.go

此时没有可用的服务实例

 

 

2.启动一个服务注册模块(我们称为instance1)

> go run register.go -service.port=12310

启动成功后我们观察服务发现模块的日志,发现了一个实例

 

3. 再启动一个服务注册模块(我们称为instance2)

> go run register.go -service.port=12311

 

 

此时我们通过consul的控制台也可以发现注册到consul的instance1和instance2实例信息

 

 

以上部分代码摘自以下课程,如有兴趣可以扫码学习

【Spring Cloud】面试攻略:Consul与Nacos简单比较篇 在微服务架构中,服务发现和配置管理是至关重要的环节。Consul和Nacos都是优秀的注册中心和配置中心解决方案。本文将为大家梳理Consul的相关知识点,并与Nacos进行比较,同时提供一些常见的面试题,助力大家在面试中脱颖而出。 阅读详情

相关推荐

go微服务系列(七):consul给微服务添加服务注册与发现

微服务架构按业务划分微服务的特点,使得原本聚合了大量业务模块的单体应用被划分为众多的微服务。而大量微服务的出现,势必会带来运维管理上的巨大挑战,于是服务注册与发现这类自动化策略应运而生。但是引入服务注册与发现就可能引入额外技术栈,增加系统总体的复杂性,比如会引入中心化的服务注册与发现中心这类基础组件。在本课时,我们将基于 Consul 给微服务添加服务注册与发现的能力。首先,我们会基于 Kubernetes 搭建一个接近生产环境的 Consul 集群;接着再基于搭建好的 Consul 集群,为我们的微服务添

阿白, 2328

微服务注册中心产品ZooKeeper、Eureka、Consul、Nacos对比

服务注册中心本质上是为了解耦服务提供者和服务消费者。对于任何一个微服务,原则上都应存在或者支持多个提供者,这是由微服务的分布式属性决定的。更进一步,为了支持弹性扩缩容特性,一个微服务的提供者的数量和分布往往是动态变化的,也是无法预先确定的。因此,原本在单体应用阶段常用的静态LB机制就不再适用了,需要引入额外的组件来管理微服务提供者的注册与发现,而这个组件就是服务注册中心。

meser88的博客 2657

使用 Go 语言和 Consul 作为服务注册和配置中心

以下是一个使用 Go 语言和 Consul 作为服务注册和配置中心的实现示例。Consul 是一个开源的分布式服务发现和配置工具,提供了服务注册、健康检查、键值存储等功能。

游戏全栈,技术合作 1374

Nacos、Eureka、Zookeeper、Consul对比

开发中,经常需要对微服务进行管理,所以需要引入一些服务治理的中间件,用于注册、发现服务,常见的服务治理中间件为。

神也在Cpoy 4693

【Consul】构建高效的服务治理体系:基于Golang实现Consul服务的注册、注销、修改、监控注册的服务变化、实时同步服务信息机制

【Consul】基于Golang实现Consul服务的注册、注销、修改、监控注册的服务变化、实时同步服务信息机制 寸铁手把手带你实现Consul服务的注册、注销、修改、监控服务变化,实时同步长轮询信息机制!

寸铁的博客 3153

springcloud整合nacos和consul

SpringCloud 构建微服务系统之服务注册和发现(nacos和consul)

go 使用consul实现服务注册发现

目标 既然是学习使用consul实现服务注册发现,目标自然是实现一个程序,可以通过consul,发现另一个程序。 为此我准备了3个机器: 1.云服务器A(ubuntu):运行consul agent 2.云服务器B(ubuntu):运行一个服务,并在服务启动时注册到consul上 3.本机(mac):运行一个程序,可以通过云服务器A上的consul,发现云服务器B上的服务 启动cons...

djqueen的博客 2万+

用Multisim仿真AD630锁定放大器:从2012年电赛A题实战到避坑指南

本文详细介绍了如何使用Multisim仿真AD630锁定放大器,从2012年电赛A题实战出发,提供完整的电路搭建、参数优化及避坑指南。重点解析AD630的开关调制架构和双相位检测的工程实现,帮助读者在强噪声背景下有效提取微弱信号,提升电子设计竞赛和工程实践中的信号处理能力。

weixin_42549451的博客 203

Go语言Gin框架接入Consul实现微服务注册发现

Gin是一个使用Go语言开发的Web框架。它提供类似Martini的API,但性能更佳,速度提升高达40倍。本文使用Gin框架简单的实现了数据库的查询功能,基于Go ORM的查询;然后又接入Consul微服务实现了服务注册和发现。

码农兴哥的技术笔记 1805

从AI画稿到3D虚拟时装:Illustrator与Substance 3D的服装设计工作流

本文旨在解决传统服装与纺织品设计师在产品开发流程中,面临的“2D印花图案无法直观预见3D上身效果”、“物理打样成本高昂且周期漫长”的核心痛点。我们将介绍一套纯数字化的3D可视化工作流,核心是利用 Adobe Illustrator 进行矢量印花图案创作,通过 Adobe Substance 3D Sampler 将其转化为逼真的PBR(基于物理渲染)布料材质,并最终在 Adobe Substance 3D Stager 中,将该材质应用于3D服装模型,渲染出照片级的虚拟样衣。本指南将帮助设计师以极低的成本和

Kingsdesigner的博客 1401

【CTF-misc】java盲水印BlindWatermark工具使用

​ 盲水印是一种肉眼不可见的水印方式,对图片资源使用图片盲水印或者文字水印,借此避免数字媒体未经授权的复制和拷贝,可通过对原图进行解码操作,得到水印图来证明版权归属。 题目来源:NewStarCTF 2023 公开赛道 WEEK2|MISC:Jvav

qq_39972370的博客 6452

启动go服务_go-micro+gin+consul微服务实战之服务注册与发现

在构建微服务时,使用服务发现可以减少配置的复杂性,本文以go-micro为微服务框架,使用consul作为服务发现服务,使用gin开发golang服务。使用gin 的原因是gin能够很好的和go-micro进行集成。本文主要介绍服务注册和发现的实现关于如何搭建consul服务可以移步:ubuntu+docker+consul安装部署及使用​www.jianshu.com本文默认以搭建好了consu...

weixin_30060575的博客 770

【FPGA】Verilog代码实现温湿度传感器DHT11

#今天也是咸鱼的一天~ 因为参加Robei 杯 是要做一个机器人,先不说这个机器人具体怎么机器法,但是和外界互通的传感器肯定少不了,通过获取外界环境数据,进行处理,然后做出各种各样的功能。 先来讲个简单的模块,温湿度传感器DHT11。 DHT11介绍 DHT11是一款价格便宜,易于使用的温度湿度测量二合一传感器。它具有超小体积、极低功耗的特点。它使用单根总线与单片机进行双向的串行数据传输,信号传...

Ninquelote的博客 9163

Consul实现http或者grpc服务的注册与发现,Golang、Python的使用记录

consul官网Consul包含多个组件,但是作为一个整体,为你的基础设施提供服务发现和服务配置的工具.他提供以下关键特性:服务发现 Consul的客户端可用提供一个服务,比如 api 或者mysql ,另外一些客户端可用使用Consul去发现一个指定服务的提供者.通过DNS或者HTTP应用程序可用很容易的找到他所依赖的服务.健康检查 Consul客户端可用提供任意数量的健康检查,指定一个服务(比如:webserver是否返回了200 OK 状态码)或者使用本地节点(比如:内存使用是否大于90%). 这个信

Neo 8316

如何通过常规测井曲线识别砂岩、泥岩、碳酸盐岩和煤层

常规测井曲线通过不同岩性的物理性质差异识别砂岩、泥岩、碳酸盐岩和煤层。砂岩表现为低自然伽马(GR)、中等密度(RHOB)和声波时差(DT);泥岩以高GR、高中子(NPHI)和高DT为特征;碳酸盐岩显示低GR、高RHOB和低DT;煤层则具有极低RHOB、极高NPHI和DT的独特组合。综合GR与三孔隙度曲线(RHOB、NPHI、DT)可有效区分岩性,其中密度测井对煤层识别最可靠。电阻率(RT)曲线辅助判断流体性质,但需结合其他参数综合分析。

love code, love life. 2597

无符号整数、带符号整数溢出问题

让我们详细讲解一下带符号整数溢出和无符号整数溢出问题中,符号标志位 (SF)、零标志位 (ZF) 和进位标志位 (CF) 的行为方式

weixin_49342084的博客 2090

go consul 安装,代码实现微服务注册和发现

1. 什么是服务注册和发现 假如这个产品已经在线上运行,有一天运营想搞一场促销活动,那么我们相对应的【用户服务】可能就要新开启三个微服务实例来支撑这场促销活动。而与此同时,作为苦逼程序员的你就只有手动去 API gateway 中添加新增的这三个微服务实例的 ip 与port ,一个真正在线的微服务系统可能有成百上千微服务,难道也要一个一个去手动添加吗?有没有让系统自动去实现这些操作的方法呢?答案当然是有的。 当我们新添加一个微服务实例的时候,微服务就会将自己的 ip 与 port 发送到注册中心,在注

雪锋的笔记 763

Sigrity System SI Parallel Bus Analysis模式进行DDR3仿真分析操作指导-单个颗粒

Default Strobe Offset:DQS默认偏移时间,自动填充为0.5ns,即DQS默认偏移1/2UI,DQS滞后于DQ 1/2UI,让建立保持时间均分。WLO:写平衡偏移的数值,DataL是0ps,DataU是500ps,是根据WLOSkew自动定义的,可以认为是WLOSkew取整,也可以根据需要手动调整数值。注意AddCmd的UI=T,这里的Data Rate仍然是DQ的速率,并不是地址线的速率,地址线的速率=1/UI=1/2ns=0.5Gbps。

weixin_54787054的博客 367

4.服务注册与发现-go操作consul(grpc服务的注册与发现)

1.grpc服务的健康检查 imporet ( "google.golang.org/grpc/health" "google.golang.org/grpc/health/grpc_health_v1" ) func main(){ server := grpc.NewServer() proto.RegisterUserServer(server, &handler.UserServer{}) lis, _ := net.Listen("tcp", ip ,port)

apple_56973763的博客 856

【Linux命令大全】006.网络通讯之write命令(实操篇)

Linux write命令摘要 write是Linux系统中用于用户间实时通讯的命令工具,允许向其他登录用户的终端发送消息。主要功能包括: 基本使用:通过write username向指定用户发送消息,Ctrl+D结束输入 终端指定:当用户登录多个终端时,可用write username tty指定目标终端 实用技巧: 使用who查看在线用户 通过管道发送单行消息:echo "内容" | write user 支持多行消息发送和简单聊天会话。

yuhuasheng1997的博客 217

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

consul php端,PHP实现consul服务注册与服务发现-Go语言中文社区

本文主要介绍怎么用consul提供的HTTP的API来实现PHP与consul之间的通信,实现服务的注册与发现。上图中文件夹Consul之外的php文件是实现的部分功能内有注释,例如注册方法:/*** Created by 20.* User: 20* 服务注册*/define('BASE_PATH', __DIR__);include BASE_PATH . '/Consul/Agent.php...

weixin_33672838的博客 389

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

consul php sdk,PHP实现consul服务注册与服务发现-Go语言中文社区

本文主要介绍怎么用consul提供的HTTP的API来实现PHP与consul之间的通信,实现服务的注册与发现。上图中文件夹Consul之外的php文件是实现的部分功能内有注释,例如注册方法:/*** Created by 20.* User: 20* 服务注册*/define('BASE_PATH', __DIR__);include BASE_PATH . '/Consul/Agent.php...

weixin_34562922的博客 334

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Golang深入浅出之-Go语言中的服务注册与发现机制

服务注册与发现是微服务架构中的重要组件,它允许服务实例在启动时向注册中心注册自己,同时其他服务能够动态地发现并调用这些已注册的服务。在Go语言生态中,这一机制的实现尤为关键,本文将深入浅出地探讨其原理、常见问题、易错点及解决方案,并提供代码示例。

zevjay的博客 806

一个故事,一段代码告诉你如何使用不同语言(Golang&C#)提供相同的能力基于Consul做服务注册与发现

文章目录引言什么是微服务传统服务微服务什么是服务注册与服务发现为什么要使用不同的语言提供相同的服务能力服务协调器服务注册GolangC#(.NetCore3.1)服务发现通过HttpClient发现服务,并访问注销一个`coffee-service`实例再访问 引言 趁着最近休息写一篇关于微服务架构中特别重要一环服务注册与发现示例来互相探讨学习。 什么是微服务 传统服务 举个栗子: 传统服务就类似于你们家附近的商店,这个商店可以提供你基本日常所需。你可以在里面买牙膏、零食、饮料、袜子、充电器等。 优点:

不诱于誉,不恐于诽,率道而行,端然正己。 646

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

2、定义服务注册和剔除的方法。1、服务实例接口与默认实现。

hongyuyahei的博客 777

python consul_python使用consul进行服务注册和发现

一、安装启动consul1.通过docker快速安装#获取docker镜像docker pull consul2.启动consul然后就可以启动集群了,这里启动4个Consul Agent,3个Server(会选举出一个leader),1个Client#启动第1个Server节点,集群要求要有3个Server,将容器8500端口映射到主机8900端口,同时开启管理界面docker run -d -...

weixin_39550940的博客 532
上一篇: Golang基于etcd实现服务注册和发现功能
下一篇: golang实现CRC8算法
思维的深度
博客等级 码龄11年 2万+粉丝 391原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值