【Go】微服务架构下实现etcd服务注册与服务发现

news2024/9/21 10:34:27

中心网关:gateway
四个微服务:user、message、note、relationship
在这里插入图片描述

1 中心网关实现服务发现

1.1 设计EtcdDiscovery类

package entity

import (
	"context"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"gonote/gateway/internal/option"
	messageService "gonote/message/service"
	noteService "gonote/note/service"
	relationshipService "gonote/relationship/service"
	userService "gonote/user/service"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"sync"
	"time"
)

type EtcdDiscovery struct {
	etcdClient *clientv3.Client
	serviceMap map[string]interface{}
	mu         sync.RWMutex
}

func NewEtcdDiscovery(ip string, port int) (*EtcdDiscovery, error) {
	etcdCli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{fmt.Sprintf("%v:%v", ip, port)},
		DialTimeout: time.Second * 3,
	})
	if err != nil {
		return nil, err
	}
	
	return &EtcdDiscovery{
		etcdClient: etcdCli,
		serviceMap: make(map[string]interface{}),
	}, nil
}

func (ed *EtcdDiscovery) Start(serviceNames []string) {
	for _, serviceName := range serviceNames {
		resp, err := ed.etcdClient.Get(context.TODO(), serviceName)
		if err != nil {
			panic(err)
		}
		addr := string(resp.Kvs[0].Value)

		conn, err := grpc.Dial(addr,
			grpc.WithTransportCredentials(insecure.NewCredentials()))
		if err != nil {
			panic(err)
		}

		// etcd存储的是各个微服务的监听地址,通过监听地址创建服务实例
		switch serviceName {
		case option.User:
			grpcCli := userService.NewUserServiceClient(conn)
			ed.serviceMap[serviceName] = grpcCli
		case option.Relationship:
			grpcCli := relationshipService.NewRelationshipServiceClient(conn)
			ed.serviceMap[serviceName] = grpcCli
		case option.Note:
			grpcCli := noteService.NewNoteServiceClient(conn)
			ed.serviceMap[serviceName] = grpcCli
		case option.Message:
			grpcCli := messageService.NewMessageServiceClient(conn)
			ed.serviceMap[serviceName] = grpcCli
		}
		
		// 开启协程,监听etcd的变化,动态维护各个grpc服务实例
		go ed.watch(serviceName)
	}
}

func (ed *EtcdDiscovery) watch(serviceName string) {
	watchChan := ed.etcdClient.Watch(context.TODO(), serviceName)
	for event := range watchChan {
		for _, e := range event.Events {
			if e.Type == clientv3.EventTypePut {
				addr := string(e.Kv.Value)
				conn, err := grpc.Dial(addr,
					grpc.WithTransportCredentials(insecure.NewCredentials()))
				if err != nil {
					continue
				}
				ed.mu.Lock()
				switch serviceName {
				case option.User:
					grpcCli := userService.NewUserServiceClient(conn)
					ed.serviceMap[serviceName] = grpcCli
				case option.Relationship:
					grpcCli := relationshipService.NewRelationshipServiceClient(conn)
					ed.serviceMap[serviceName] = grpcCli
				case option.Note:
					grpcCli := noteService.NewNoteServiceClient(conn)
					ed.serviceMap[serviceName] = grpcCli
				case option.Message:
					grpcCli := messageService.NewMessageServiceClient(conn)
					ed.serviceMap[serviceName] = grpcCli
				}
				ed.mu.Unlock()
			} else if e.Type == clientv3.EventTypeDelete {
				ed.mu.Lock()
				delete(ed.serviceMap, serviceName)
				ed.mu.Unlock()
			}
		}
	}
}

func (ed *EtcdDiscovery) GetServiceAddr(serviceName string) interface{} {
	ed.mu.RLock()
	defer ed.mu.RUnlock()

	return ed.serviceMap[serviceName]
}

1.2 在web启动时,初始化EtcdDiscovery

package main

import (
	"gonote/gateway/internal"
	"gonote/gateway/internal/option"
	"gonote/gateway/internal/util"
)

func init() {
	util.InitLogger()

	util.InitWebSocketServer(64)

	err := util.InitRedis()
	if err != nil {
		panic(err)
	}

	util.InitKafka(option.Topic)

	util.InitEtcdDiscovery([]string{
		option.User,
		option.Relationship,
		option.Note,
		option.Message})
}

func main() {
	engine := internal.Router()

	if err := engine.Run("0.0.0.0:9090"); err != nil {
		panic(err)
	}
}

1.3 调用EtcdDiscovery获取服务实例

举个用户注册的例子:

func UserLogin(c *gin.Context) {
	em := c.PostForm("email")
	pwd := c.PostForm("pwd")

    // 获取服务实例
	cli := util.EtcdDiscovery.GetServiceAddr(option.User).(service.UserServiceClient)
   
    // 调用服务
	_, err := cli.UserLogin(context.TODO(), &service.User{
		Email: em,
		Pwd:   pwd,
	})

	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}

	// 生成jwt令牌
	token, err := util.GenToken(em)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}

    // session维护长连接
	session := sessions.Default(c)
	session.Set("email", em)
	err = session.Save()
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}

	c.JSON(200, gin.H{
		"code": 0,
		"data": token,
	})
}

2 微服务端进行服务注册

user业务对应的微服务:

func init() {
	util.InitLogger()

	err := util.InitDB()
	if err != nil {
		panic(err)
	}

	util.InitKafka(option.Topic)

	util.InitEtcdCli()
}

func main() {
	addr := option.IP + ":" + option.Port
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		panic(err)
	}
	defer ln.Close()

	defer util.EtcdCli.Close()
	defer util.KafkaCli.Close()

    // 服务注册
	_, err = util.EtcdCli.Put(context.TODO(), "user", addr)
	if err != nil {
		panic(err)
	}

	server := grpc.NewServer()

	service.RegisterUserServiceServer(server, &service.UserServiceImpl{})

	if err = server.Serve(ln); err != nil {
		panic(err)
	}
}

通过etcd命令查看相关注册信息
在这里插入图片描述

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

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

相关文章

C#,斐波那契数列(Fibonacci Sequence)的八种算法与源代码

一、莱昂纳多斐波那契(Leonardo Fibonacci) 斐波那契公元1170年生于意大利比萨,卒于1250年,被人称作“比萨的莱昂纳多”,是一名闻名于欧洲的数学家,其主要的著作有《算盘书》、《实用几何》和《四艺经》等。…

Github 2024-01-31 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-01-31统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目5非开发语言项目3TypeScript项目1Jupyter Notebook项目1C项目1 基于项目的学习 创建周期&#xf…

SAP下载word

事务代码:STRANS 启动转换器 步骤 1. 将参数填入模板,并另存为word 2003 xml文档 2.使用网页打开xml文档,并将xml拷贝到转换器tt:template中,添加参数 3.替换参数,部分xml可能存在错误或者跑偏根据实际情况检查修改 …

WPF应用程序(.Net Framework 4.8) 国际化

1、新建两个资源字典文件zh-CN.xaml和en-US.xaml&#xff0c;分别存储中文模板和英文模板 (1) zh-CN.xaml <ResourceDictionary xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml&q…

数字孪生智慧能源电力Web3D可视化云平台合集

前言 能源电力的经济发展是中国式现代化的强大动力&#xff0c;是经济社会发展的必要生产要素&#xff0c;电力成本变化直接关系到工业生产、交通运输、农业生产、居民生活等各个方面&#xff0c;合理、经济的能源成本能够促进社会用能服务水平提升、支撑区域产业发展&#xf…

xcode安装visionOS Simulator模拟器报错解决方法手动安装方法

手动安装方法&#xff1a; 手动下载visionOS Simulator模拟器地址&#xff1a; https://developer.apple.com/download/all/ 选择 Xcode 版本 sudo xcode-select -s /Applications/Xcode.app # 用 Xcode-beta 的话是&#xff1a; # xcode-select -s /Applications/Xcode-beta…

Cache Lab:Part A【模拟出使用LRU策略的高速缓存存储器组织结构】

目录 任务描述 知识回顾 实验内容 测试结果 Cache Lab 对应《CS:APP》6.3节至第六章结束的内容。 任务描述 Your job for Part A is to fill in the csim.c file so that it takes the same command line arguments and produces the identical output as the reference …

WAP在线封装APP工具:革新移动体验的技术

一、融合式设计&#xff1a;打破原生与网页应用的界限WAP封装App工具的最新版本已经能够实现无缝融合网页内容与原生应用功能。这些工具不仅仅是简单地将网页“包装”成APP&#xff0c;而是通过创新的融合式设计&#xff0c;让用户在使用过程中几乎感受不到两者之间的差异。例如…

Ruff应用:打破传统,IoT技术赋能工业制造数字化转型之路

近年来&#xff0c;随着物联网、大数据、云计算、5G等数字技术的快速应用&#xff0c;工业制造领域正在经历着前所未有的变革。工业4.0时代&#xff0c;各种数字技术与工业制造的结合&#xff0c;不仅提高了工业生产效率、降低运营成本&#xff0c;更是极大地推动了传统工业数字…

【深度学习每日小知识】Model Accuracy 模型准确率

Model Accuracy 模型准确率 模型准确性是衡量机器学习 (ML) 模型基于数据做出预测或决策的能力的指标。它是用于评估 ML 模型性能的常用指标&#xff0c;可用于比较不同模型的性能或评估特定模型对于给定任务的有效性。 有多种不同的方法来衡量模型的准确性&#xff0c;具体取…

Mac下手动源码编译安装Swig

使用Homebrew安装 这个方式最简单&#xff0c;但是一般都是安装的最新版&#xff1a; brew install swig如果按照特定版本&#xff0c;需要看一个当前支持的列表&#xff1a; brew search swig brew install swig3源码编译安装 swig依赖pcre库&#xff0c;需要先安装pcre …

Inventor 2024下载安装教程,免费使用,附安装包和工具,流程简单,小白也能轻松搞定

前言 Inventor是一款专业的三维可视化实体建模软件&#xff0c;Inventor.主要用于各类二维机械制图、三维制图的设计和开发等操作&#xff0c;可以广泛地应用于零件设计、钣金设计、装配设计等领域。 准备工作 1、Win7及以上系统 2、提前准备好 Inventor 2024 安装包 没有…

C# 多线程(2)——线程同步

目录 1 线程不安全2 线程同步方式2.1 简单的阻塞方法2.2 锁2.2.1 Lock使用2.2.2 互斥体Mutex2.2.3 信号量Semaphore2.2.3 轻量级信号量SemaphoreSlim2.2.4 读写锁ReaderWriterLockSlim 2.3 信号同步2.3.1 AutoResetEvent2.3.1.1 AutoResetEvent实现双向信号 2.3.2 ManualResetE…

H2数据库学习总结

H2数据库-简介 H2 是开源的轻量级Java数据库。它可以嵌入Java应用程序中或以客户端-服务器模式运行。 H2 数据库主要可以配置为作为内存数据库运行&#xff0c;这意味着数据将不会持久存储在磁盘上。 由于具有嵌入式数据库&#xff0c;因此它不用于生产开发&#xff0c;而主要…

【Java程序设计】【C00184】基于SSM的旅游网站管理系统(论文+PPT)

基于SSM的旅游网站管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的旅游网站管理系统 本系统分为前台用户、后台管理员2个功能模块。 前台用户&#xff1a;当游客打开系统的网址后&#xff0c;首先看到的就是首…

Guava EventBus详解

概述 EventBus顾名思义&#xff0c;事件总线&#xff0c;是一个轻量级的发布-订阅模式的应用模式。相比于MQ更加简洁&#xff0c;轻量&#xff0c;它可以在一个小系统模块内部使用。 EventBus允许组件之间通过发布-订阅进行通信&#xff0c;而不需要组件之间显示的注册。它专门…

数据结构与算法教程,数据结构C语言版教程!(第六部分、数据结构树,树存储结构详解)七

第六部分、数据结构树&#xff0c;树存储结构详解 数据结构的树存储结构&#xff0c;常用于存储逻辑关系为 "一对多" 的数据。 树存储结构中&#xff0c;最常用的还是二叉树&#xff0c;本章就二叉树的存储结构、二叉树的前序、中序、后序以及层次遍历、线索二叉树、…

数据库之TiDB基础讲解

文章目录 1 TiDB1.1 引言1.2 TiDB介绍1.3 系统架构1.3.1 TIDB Server1.3.2 PD Server1.3.3 TIKV Server1.3.4 TiKV如何不丢失数据1.3.5 分布式事务支持 1.4 与MySQL的对比1.5 性能测试1.5.1 测试一1.5.2 系统测试报告 2 1 TiDB 1.1 引言 当我们使用 Mysql 数据库到达一定量级…

【python】图形化开发pyqt6基本写法模板与基础控件属性方法整理

pyqt6的简介 首先呢Python有许多可以编写图形化界面的库&#xff0c;我们通常跟着教程的话最初会接触的tkinter&#xff0c;但是学习中会发现编写的图形化跟我们平常接触的软件有很大区别&#xff08;简单来说就是丑&#xff09;。 pyqt则是第三方库&#xff0c;在Python中算…

如何快速记忆小鹤双拼键位图?

记忆方法&#xff1a;韵母表 图形 最常用字 韵母表&#xff1a;双拼的基础 图形&#xff1a;帮助新手快速联想回忆 最常用字&#xff1a;快速打字基础 一、单韵母&#xff08;紫色方块&#xff09; 一一对应如下表&#xff1a; 单韵母aoeiu、AOEIV 二、复韵母—箭矢型&am…