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

中心网关: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命令查看相关注册信息
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IP 层转发分组的过程

目录 IP 层转发分组的过程 1.1 基于终点的转发 1.2 最长前缀匹配 转发表中的 2 种特殊的路由 主机路由 (host route) 默认路由 (default route) 路由器分组转发算法 1.3 使用二叉线索查找转发表 IP 层转发分组的过程 1.1 基于终点的转发 分组在互联网中是逐跳转发的。…

网络异常案例一_RST

本文以及后面几篇会整理输出下以前处理过的一些网络相关的异常 4G定向卡上网问题 问题现象,自研路由器,使用运营商定向的4G卡上网,访问服务器异常,相应的开发同学反馈被服务器拒绝了; 复现问题,同步在cli…

CRF条件随机场学习记录

阅读建议 仔细阅读书[1]对应的序列标注章节,理解该方法面向的问题以及相关背景,然后理解基础的概念。 引言 威胁情报挖掘的相关论文中,均涉及到两部分任务:命名实体识别(Named Entity Recognition,NER&a…

某赛通电子文档安全管理系统 PolicyAjax SQL注入漏洞复现

0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…

Apollo与微服务架构

前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家:https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言引言:1. 什么是微服务架构?2. 微服务架构的组成要素…

python 标准库random生成随机数

当前版本: Python 3.8.4 文章目录如下 1. random的特点 2. random的用法 2.1. 随机整数 2.2. 随机小数 2.3. 随机元素 2.4. 随机字符串 1. random的特点 random 提供了生成伪随机数的功能,可以用于各种随机相关的操作,如生成随机数、…

《HTML 简易速速上手小册》第6章:HTML 语义与结构(2024 最新版)

文章目录 6.1 语义化标签的重要性6.1.1 基础知识6.1.2 案例 1&#xff1a;使用 <article>, <section>, <aside>, <header>, 和 <footer>6.1.3 案例 2&#xff1a;构建带有嵌套语义化标签的新闻网站6.1.4 案例 3&#xff1a;创建一个带有 <mai…

干货 | 大模型在图数据分析、推荐系统和生物科学中的综合应用

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 图机器学习、推荐系统与大语言模型的融合正成为新的前沿热点。图机器学习通过利用图结构数据&#xff0c;能够有效地捕捉和分析复杂关系和模式。同时&#xff0c;推荐系统正逐步成为我们日常生活的一部分&#…

5G_RACH(一)

什么是RACH RACH 代表 Random Access Channel。这是开机时UE发给eNB的第一条消息。 为什么选择RACH &#xff1f;&#xff08;RACH 的功能是什么&#xff1f; 当你第一次听到RACH或RACH Process这个词时&#xff0c;你脑海中浮现的第一个问题是“为什么是RACH&#xff1f;”…

前端Web开发

安装flask框架 pip install flask 导入flask模块 from flask import Flask 【可能遇到的问题】 出现了如下警告&#xff1a; WARNING: You are using pip version 21.2.4; however, version 22.0.4 is available.You should consider upgrading via the D:\Python\python…

EPSON RC 机器人-第一个程序

创建项目 有机械人且用USB线连接好。可以USB。没有真机的选择 C4 Sample 可以运行程序。 否刚会提示【不能连接到控制器&#xff0c;未安装USB驱动器】 代码 按F5打开运行窗口 再点【开始】 点 【是】&#xff0c;查看运行结果

GMS测试BTSfail-CVE-2022-20451

描述&#xff1a; 项目需要过GMS兼容性测试&#xff0c;BTS这块我们环境没有&#xff0c;送检之后出现了一个BTS的Alert&#xff0c;这个是必须要解决的。下面的warning可以不考虑。 这个是patch问题&#xff0c;根据代理提供的pdf文件找到一个id:为A-235098883的补丁&#xf…

C#,德兰诺依数(Dealnnoy Number)的算法与源代码

1 Dealnnoy Number 德兰诺依数&#xff0c;德兰诺伊数 德兰诺依数是以法国军官、业余数学家亨利德兰诺依&#xff08;Henry Dealnnoy&#xff09;的名字命名。 Henry Dealnnoy 在组合数学中&#xff0c;德兰诺依数描述了从(0,0)到(m,n)的格路问题中&#xff0c; 只允许按照(0…

TensorFlow2实战-系列教程14:Resnet实战1

&#x1f9e1;&#x1f49b;&#x1f49a;TensorFlow2实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Jupyter Notebook中进行 本篇文章配套的代码资源已经上传 1、残差连接 深度学习中出现了随着网络的堆叠效果下降的现象&#xff0c;Resnet使用残…

BTC交易数据是什么样子的

如何储存 交易数据是用字节的形式存储在区块链中&#xff0c;但是我们分析和处理的时候一般使用16进制。另外BTC的数据都是通过小端模式存储的。 16进制&#xff1a;计算机的世界只有2进制&#xff0c;但是为了节省空间已经增加可读性&#xff0c;BTC使用了16进制的形式来保存数…

蓝桥杯 第 1 场 小白入门赛

目录 1.蘑菇炸弹 2.构造数字 3.小蓝的金牌梦 4.合并石子加强版 5.简单的LIS问题 6.期望次数 1.蘑菇炸弹 我们直接依照题目 在中间位置的数进行模拟即可 void solve(){cin>>n;vector<int> a(n1);for(int i1;i<n;i) cin>>a[i];int ans0;for(int i2;i…

氢气泄漏检测仪使用方法:守护安全,从细节开始

随着科技的发展&#xff0c;我们的生活和工作环境中充满了各种潜在的危险。其中&#xff0c;氢气作为一种清洁能源&#xff0c;其使用日益广泛&#xff0c;但同时也带来了泄漏的风险。为了确保我们的安全&#xff0c;了解并正确使用氢气泄漏检测仪至关重要。下面将详细介绍氢气…

Optimism的挑战期

1. 引言 前序博客&#xff1a; Optimism的Fault proof 用户将资产从OP主网转移到以太坊主网时需要等待一周的时间。这段时间称为挑战期&#xff0c;有助于保护 OP 主网上存储的资产。 而OP测试网的挑战期仅为60秒&#xff0c;以简化开发过程。 2. OP与L1数据交互 L1&#xf…

STM32学习笔记二——STM32时钟源时钟树

目录 STM32芯片内部系统架构详细讲解&#xff1a; 1.芯片内部混乱电信号解决方案&#xff1a; 2.时钟树&#xff1a; 1.内部RC振荡器与外部晶振的选择 2. STM32 时钟源 3.STM32中几个与时钟相关的概念 4.时钟输出的使能及其流程 5.时钟设置的基本流程 时钟源——单片机…

上海亚商投顾:创业板指失守1600点 全市场超5000只个股下跌

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日低开低走&#xff0c;深成指跌超2%&#xff0c;创业板指失守1600点&#xff0c;续创年内新低。脑机接…