Golang基于etcd实现服务注册和发现功能

Kitex 提供的服务注册与发现 etcd 拓展 etcd 是一个高度可用的、分布式、一致性的键值存储系统,主要用于服务发现、配置共享、协调分布式系统状态等场景。它是使用 Go 语言编写的,并采用 Raft 算法保证数据的强一致性。etcd 在云原生生态系统中扮演着至关重要的角色,特别是在 Kubernetes(K8s)中作为其元数据存储和集群协调的核心组件。 阅读详情

windows安装etcd:https://skaygo.blog.youkuaiyun.com/article/details/80712214

linux安装etcd:https://skaygo.blog.youkuaiyun.com/article/details/80714661

 

etcd是一个分布式的,一致的 key-value 存储,主要用途是共享配置和服务发现。Etcd 已经在很多分布式系统中得到广泛的使用。

etcd实现服务注册与发现功能,主要使用key-value存储,租约(lease)以及watch功能。

服务注册

1.租约模式,lease用于检测客户生存状态的机制。etcd集群支持具有生命周期的租约。如果etcd集群在给定的TTL周期内未收到客户端的keepAlive,则租约到期。存储在etcd集群中的key-value允许附加一个租约。当租约到期或被撤销时,绑定到该租约的所有key-value键值对将会被删除。

2.相同服务存储的key的前缀需要设置成一样

3.注册服务就是向服务端使用租约模式写入一个key和对应的value

 

代码实现(etcd_ register.go)

package main

import (
	"os"
	"log"
	"time"
	"syscall"
	"context"
	"os/signal"

	"go.etcd.io/etcd/clientv3"
)

//ServiceRegister 创建租约注册服务
type ServiceRegister struct {
	cli     *clientv3.Client //etcd v3 client
	leaseID clientv3.LeaseID //租约ID
	//租约keepalieve相应chan
	keepAliveChan <-chan *clientv3.LeaseKeepAliveResponse
	key           string //key
	val           string //value
}

//NewServiceRegister 新建注册服务
func NewServiceRegister(endpoints []string, key, val string, lease int64,dailTimeout  int) (*ServiceRegister, error) {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   endpoints,
		DialTimeout: time.Duration(dailTimeout) * time.Second,
	})
	if err != nil {
		return nil,err
	}

	ser := &ServiceRegister{
		cli: cli,
		key: key,
		val: val,
	}

	//申请租约设置时间keepalive
	if err := ser.putKeyWithLease(lease); err != nil {
		return nil, err
	}

	return ser, nil
}

//设置租约
func (s *ServiceRegister) putKeyWithLease(lease int64) error {
	//创建一个新的租约,并设置ttl时间
	resp, err := s.cli.Grant(context.Background(), lease)
	if err != nil {
		return err
	}

	//注册服务并绑定租约
	_, err = s.cli.Put(context.Background(), s.key, s.val, clientv3.WithLease(resp.ID))
	if err != nil {
		return err
	}
	//设置续租 定期发送需求请求
	//KeepAlive使给定的租约永远有效。 如果发布到通道的keepalive响应没有立即被使用,
	// 则租约客户端将至少每秒钟继续向etcd服务器发送保持活动请求,直到获取最新的响应为止。
	//etcd client会自动发送ttl到etcd server,从而保证该租约一直有效
	leaseRespChan, err := s.cli.KeepAlive(context.Background(), resp.ID)
	if err != nil {
		return err
	}

	s.leaseID = resp.ID
	log.Println(s.leaseID)
	s.keepAliveChan = leaseRespChan
	log.Printf("Put key:%s  val:%s  success!", s.key, s.val)
	return nil
}

//ListenLeaseRespChan 监听 续租情况
func (s *ServiceRegister) ListenLeaseRespChan() {
	for leaseKeepResp := range s.keepAliveChan {
		log.Println("续约成功", leaseKeepResp)
	}
	log.Println("关闭续租")
}

// Close 注销服务
func (s *ServiceRegister) Close() error {
	//撤销租约
	if _, err := s.cli.Revoke(context.Background(), s.leaseID); err != nil {
		return err
	}
	log.Println("撤销租约")
	return s.cli.Close()
}

func main() {
	var endpoints = []string{"localhost:2379"}

	ser, err := NewServiceRegister(endpoints, "/server/node1", "localhost:8000", 6 , 5)
	if err != nil {
		log.Fatalln(err)
	}
	//监听续租相应chan
	go ser.ListenLeaseRespChan()

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

 

服务发现

1.创建一个etcd client

2.匹配到所有相同前缀的 key. 存储信息到本地

3.watch这个key前缀,当有增加或者删除的时候就修改本地

4.本地维护server的列表

 

代码实现(etcd_discovery.go)

package main

import (
	"os"
	"log"
	"time"
	"sync"
	"syscall"
	"context"
	"os/signal"

	"go.etcd.io/etcd/clientv3"
	"github.com/coreos/etcd/mvcc/mvccpb"
)

//ServiceDiscovery 服务发现
type ServiceDiscovery struct {
	cli        *clientv3.Client  //etcd client
	serverList map[string]string //服务列表
	lock       sync.RWMutex
}

//NewServiceDiscovery  新建发现服务
func NewServiceDiscovery(endpoints []string) *ServiceDiscovery {
	//初始化etcd client v3
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   endpoints,
		DialTimeout: 5 * time.Second,
	})

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

	return &ServiceDiscovery{
		cli:        cli,
		serverList: make(map[string]string),
	}
}

//WatchService 初始化服务列表和监视
func (s *ServiceDiscovery) WatchService(prefix string) error {
	//根据前缀获取现有的key
	resp, err := s.cli.Get(context.Background(), prefix, clientv3.WithPrefix())
	if err != nil {
		return err
	}

	//遍历获取到的key和value
	for _, ev := range resp.Kvs {
		s.SetServiceList(string(ev.Key), string(ev.Value))
	}

	//监视前缀,修改变更的server
	go s.watcher(prefix)
	return nil
}

//watcher 监听key的前缀
func (s *ServiceDiscovery) watcher(prefix string) {
	rch := s.cli.Watch(context.Background(), prefix, clientv3.WithPrefix())
	log.Printf("watching prefix:%s now...", prefix)
	for wresp := range rch {
		for _, ev := range wresp.Events {
			switch ev.Type {
			case mvccpb.PUT: //修改或者新增
				s.SetServiceList(string(ev.Kv.Key), string(ev.Kv.Value))
			case mvccpb.DELETE: //删除
				s.DelServiceList(string(ev.Kv.Key))
			}
		}
	}
}

//SetServiceList 新增服务地址
func (s *ServiceDiscovery) SetServiceList(key, val string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.serverList[key] = string(val)
	log.Println("put key :", key, "val:", val)
}

//DelServiceList 删除服务地址
func (s *ServiceDiscovery) DelServiceList(key string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	delete(s.serverList, key)
	log.Println("del key:", key)
}

//GetServices 获取服务地址
func (s *ServiceDiscovery) GetServices() []string {
	s.lock.RLock()
	defer s.lock.RUnlock()
	addrs := make([]string, 0,len(s.serverList))

	for _, v := range s.serverList {
		addrs = append(addrs, v)
	}
	return addrs
}

//Close 关闭服务
func (s *ServiceDiscovery) Close() error {
	return s.cli.Close()
}

func main() {
	var endpoints = []string{"localhost:2379"}
	ser := NewServiceDiscovery(endpoints)
	defer ser.Close()

	err := ser.WatchService("/server/")
	if err != nil {
		log.Fatal(err)
	}


	// 监控系统信号,等待 ctrl + c 系统信号通知服务关闭
	c := make(chan os.Signal, 1)
	go func() {
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	}()

	for {
		select {
		case <-time.Tick(10 * time.Second):
			log.Println(ser.GetServices())
		case <-c:
			log.Println("server discovery exit")
			return
		}
	}
}

 

go run etcd_regiser.go

etcd_register实例1启动

 

go run etcd_discovery.go

 

一会儿之后我们将etcd_register中的key改为/server/node2,value改为localhost:8001

go run etcd_register.go(etcd_register实例2)启动成功之后观察etcd_discovery.go日志信息

我们发现etcd_discovery已经watch到新增实例的操作了,也更新了本地实例(服务)列表

 

然后我们关闭etcd_register实例1,观察etcd_discovery.go日志信息

发现etcd_discoveryo已经watch到删除实例的操作了,也更新了本地实例(服务)列表

 

 

感谢:https://www.cnblogs.com/FireworksEasyCool/p/12890649.html

go-zero 微服务集成 consul 注册发现和配置中心 最近在开发学习go-zero时发现基于ETCD做服务发现, 做配置中心相关资料较少, 需要做二次开发. 也调研尝试了一些注册发现组件 consul 和 nacos 等, 从资源使用上 consul 相对占用资源小太多了. 比较 nacos 是阿里基于 java 开源的. 阅读详情

相关推荐

[zz][用etcd实现服务注册和发现]

用etcd实现服务注册和发现 Kevin 发布于 2019-11-08 系统中实现服务注册与发现所需的基本功能有 服务注册:同一service的所有节点注册到相同目录下,节点启动后将自己的信息注册到所属服务的目录中。 健康检查:服务节点定时发送心跳,注册到服务目录中的信息设置一个较短的TTL,运行正常的服务节点每隔一段时间会去更新信息的TTL。 服务发现:通过名称能查询到服务提供外部访问的 IP 和端口号。比如网关代理服务时能够及时的发现服务中新增节点、丢弃不可用的服务节点,同时各个服务间也能感知对方..

突围 489

Golang+etcd的分布式锁

etcd是新一代的服务发现与配置中心,官网 https://etcd.io/ ,同时兼顾有Redis的部分功能,可以以K-V模式存储数据。基于它(类似于Zookeeper)实现一套稳定、可靠、强一致的分布式锁,在以后的应用开发中大有用处。...

风之翼的专栏 1339

etcd-discovery:在etcd上分层以在Go中进行简单的服务发现

Etcd发现v7.0.3 这是一个golang软件包,用于管理分散式键值存储etcd上的服务 要安装它: go get github.com/Scalingo/etcd-discovery/service/v7 原料药 注册服务 /* * First argument is the name of the service * Then a struct containing the service informations * The registeration will stop when the context will be canceled. * It will return the service uuid and a channel which will send back any modifications made to the service by th

Go语言etcd实现服务注册发现

Go语言实现服务注册发现

m0_62729235的博客 1690

手把手教你用STM32+LAN8720搭建以太网通信模块(含原理图)

本文详细介绍了如何使用STM32微控制器与LAN8720物理层芯片搭建以太网通信模块,涵盖硬件设计、软件配置及常见问题排查。重点讲解了LAN8720的低功耗设计、RMII接口简化布线等特性,以及STM32CubeMX配置和LwIP协议栈移植技巧,助力开发者快速实现稳定可靠的嵌入式网络通信。

CAT789的专栏 416

保姆级教程:在LKD3588开发板上为RK3588添加SC2210摄像头驱动(含完整DTS配置)

本文提供了一份详细的教程,指导如何在LKD3588开发板上为RK3588处理器添加SC2210摄像头驱动,包括完整的DTS配置和内核编译步骤。教程涵盖了环境准备、驱动文件添加、DTS配置详解、内核编译与烧录、驱动测试以及常见问题排查,帮助开发者快速实现SC2210传感器在RK3588平台上的集成与优化。

weixin_42641741的博客 480

golang云原生项目之:etcd服务注册与发现

EtcdResolver: etcd resolver是一种DNS解析器,用于将域名转换为etcd集群中的具体地址,以便应用程序可以与etcd集群进行通信。通过使用etcd resolver,应用程序可以更方便地与etcd集群交互。endpoints 用于指定集群的地址列表.例如:etcd1.example.com:2379, etcd2.example.com:2379。应用程序将通过这些地址与etcd集群的各个节点进行通信,以读取和更新数据。上面有实现的案例,直接cv。直接看例子就能大致明白。

YiGeiGiaoGiao的博客 1851

【Qt】Qt5.15在线安装避坑指南:从代理配置到组件选择的完整实践

本文详细介绍了Qt5.15在线安装的全流程避坑指南,包括代理配置、组件选择和常见问题解决方案。通过使用Fiddler工具和国内镜像源,可显著提升下载速度。文章还提供了组件选择的黄金法则和安装后的验证步骤,帮助开发者高效完成Qt5.15的安装与配置。

weixin_42550052的博客 271

golang+etcd实现的服务注册和服务发现

etcd是一个功能强大、可靠性高、易用性好的分布式键值存储系统,可以帮助用户在分布式环境中存储和同步关键数据,并实现高可用性和数据一致性。强大的观察和通知功能,使其成为一个非常适合用于作为配置管理中心或者服务注册/发现模块的选择

多年后端开发经验,专注于Golang和PHP语言的开发 1616

FPGA 学习系列(2):Verilog 语法基础

Verilog 由门级建模数据流建模行为建模门级建模(Gate Level Modeling):使用基本逻辑门描述电路,接近硬件物理结构。数据流建模(Data Flow Modeling):使用assign语句进行组合逻辑建模,类似数学方程式。行为建模(Behavioral Modeling):使用always代码块和if-elsecase等控制语句建模,抽象程度较高。Verilog 代码一般由模块(module)组成,每个模块描述一个独立的硬件功能。

Azperk的博客 989

AI大模型驱动Web UI自动化测试:Playwright与RobotFramework智能整合实践

Web自动化测试是软件质量保障的关键环节,其核心原理是通过脚本模拟用户操作,对Web应用界面进行功能验证。传统方法依赖固定的元素定位和脚本逻辑,在应对频繁的UI变更时面临维护成本高、脚本脆弱的挑战。随着AI大模型技术的发展,其强大的自然语言理解和代码生成能力为自动化测试带来了新的技术价值。通过将大模型的意图理解与代码生成能力,与Playwright强大的浏览器自动化执行引擎以及RobotFramework灵活的关键字驱动框架相结合,可以构建出能够理解自然语言指令、动态生成稳定操作脚本的智能测试系统。这种融合

weixin_28718769的博客 415

golang etcd 服务注册与发现

一条龙了解etcd

JIE2580_2580的博客 1290

Open3D (C++) 计算点云坐标最值及其索引

使用C++版本的Open3D计算点云最值点及其对应的下标索引

点云侠的博客 731

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

在构建微服务时,使用服务发现可以减少配置的复杂性,本文以go-micro为微服务框架,使用etcd作为服务发现服务,使用gin开发golang服务。使用gin 的原因是gin能够很好的和go-micro进行集成。本文主要介绍服务注册和发现的实现关于如何搭建etcd服务可以看历史文章本文默认以搭建好了etcd服务,服务的地址是:192.168.109.131:12379如果你搭建好了自己的etcd服...

weixin_34298263的博客 809

【项目实战】使用Python - Mediapipe、OpenCV进行手部面部检测(Python源码)

本文介绍了使用MediaPipe和OpenCV库进行实时面部和手部关键点检测的方法。通过MediaPipe的Holistic模型,可以获取468个面部特征点及每只手21个特征点。文章详细说明了环境配置、模型初始化参数设置,并提供了完整的代码实现,包括视频流处理、关键点绘制和FPS计算等功能。这套方案可应用于手语识别、疲劳检测等计算机视觉场景,为开发者提供了一套高效的开箱即用解决方案。

梦想起飞的地方 483

python全栈入门到实战【基础篇 01】Python初识:定位、优势与发展历程

本文介绍了热门编程语言Python。它是解释型高级语言,具通用、入门友好、胶水型特点,以简洁易读为设计哲学。优势包括语法简洁高效、生态庞大、跨平台、社区活跃、应用广泛、门槛低。发展历经诞生(1989-1994,吉多创建,1994年1.0发布)、成长(版本迭代,3.0发布)、崛起(Web与大数据推动)、爆发(AI浪潮助推)及持续迭代阶段。

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 1万+

用etcd实现服务注册和发现

系统中实现服务注册与发现所需的基本功能有 服务注册:同一service的所有节点注册到相同目录下,节点启动后将自己的信息注册到所属服务的目录中。 健康检查:服务节点定时发送心跳,注册到服务目录中的信息设置一个较短的TTL,运行正常的服务节点每隔一段时间会去更新信息的TTL。 服务发现:通过名称能查询到服务提供外部访问的 IP 和...

kevin_tech的博客,微信搜「网管叨bi叨」 1958

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

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

Go gRPC etcd实现服务注册发现与负载均衡

使用Go +grpc + etcd实现服务注册发现和负载均衡方案,可以监控服务上下线,客户端实现负载均衡

small_to_large的博客 2305

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

golang用etcd实现服务注册和发现

系统中实现服务注册与发现所需的基本功能有 服务注册:同一service的所有节点注册到相同目录下,节点启动后将自己的信息注册到所属服务的目录中。 健康检查:服务节点定时发送心跳,注册到服务目录中的信息设置一个较短的TTL,运行正常的服务节点每隔一段时间会去更新信息的TTL。 服务发现:通过名称能查询到服务提供外部访问的 IP 和端口号。比如网关代理服务时能够及时的发现服务中新增节点、丢弃不可用的服务节点,同时各个服务间也能感知对方的存在。 在分布式系统中,如何管理节点间的状态一直是一个难题,

猛犸象 3216

Go Kratos V2 gRpc + ETCD 使用实例

1. 服务端

u014647332的专栏 1392

go grpc测试_go-micro V2 从零开始(五)集成etcd注册中心

本文相关代码:gitee 前言接下来几章,重点介绍go-micro几个常用功能的集成。首先集成的是服务的注册与发现,go-micro框架为服务注册发现提供了标准的接口Registry。只要实现这个接口就可以定制自己的服务注册和发现。不过官方已经为主流注册中心提供了官方的接口实现,大多数时候我们不需要从头写起。在老版本的go-micro中默认使用consul作为注册中心,网上你能搜到的教程大多也是如...

weixin_39581739的博客 403

ETCD组件在grpc中的实践

一、前言 grpc中没有像go-micro那样集成可插拔式的etcd库使用,如何使得grpc能够使用服务注册发现及命名解析的功能,因此本文基于etcd实现了Name Resolver。 二、所需的grpc版本及高版本grpc、protobuf与etcd兼容问题 grpc相关库: google.golang.org/grpc v1.26.0 google.golang.org/grpc/b...

HarvardFly的博客 1706

微服务注册中心 ETCD Go/Python/Node调用

微服务注册中心ETCD简介 Go/python/node调用

qq_38269333的博客 1204

Docker自发现注册服务regd研发

Docker的发展已经超出我们的想象, 随着在项目中大量的应用, 联动服务也越来越需要自动化, 因此我们需要做到自发现, 自配置, 自侦错, 自报告, 此文就是自发现的基础"注册服务"

paintss的博客 879

云计算与云原生 — ETCD 数据库完全解析

目录 文章目录目录目录etcdetcd vs ZooKeeper vs Consuletcd 的应用场景服务注册与发现消息发布与订阅分布式通知与协调分布式锁分布式队列集群监控Leader 竞选负载均衡etcd 的安装与部署服务进程单点部署编译部署容器部署集群部署静态配置集群集群健康检测etcd 的架构原理etcd 的核心术语etcd 的 K/V 存储etcd 的软件架构RaftRaft 中一个 Term(任期)是什么意思?Raft 状态机是怎样切换的?如何保证最短时间内竞选出 Leader,防止竞选冲突?如

烟云的计算 4169

「推荐系统从0到1」服务发现

前沿 首先谈谈我对推荐系统的引擎和算法的理解。 现在市面上讲起推荐系统,大多都是讲各种算法,讲的天花乱坠,高深莫测,其实很多算法都是大同小异,核心思想是差不多的,只不过实现手段略有差异。而在工业上,各种复杂算法能够落地的,我认为不多,大部分的厂商,运用的算法都是很集中的那一部分算法。 一套好的推荐系统,对于引擎是非常依赖的,实验显示,响应时长与各项指标之间都是有直接关联的,响应时长越长,指标越低。 作为一个朴实的推荐码农,我还是想从基础做起,朴朴实实,脚踏实地,先把引擎部分做好。当然,算法后面也会有,毕竟.

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

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值