Go-服务注册和发现,负载均衡,配置中心

news2024/12/26 11:21:11

文章目录

  • 什么是服务注册和发现
    • 技术选型
  • Consul 的安装和配置
    • 1. 安装
    • 2. 访问
    • 3. 访问dns
  • Consul 的api接口
  • go操作consul
  • grpc下的健康检查
    • grpc的健康检查规范
    • 动态获取可用端口号
  • 负载均衡策略
    • 1. 什么是负载均衡
    • 2. 负载均衡策略
      • 1. 集中式load balance
      • 2. 进程内load balance
      • 3. 独立进程load balance
  • 常见的负载均衡算法
    • 1. 轮询(Round Robin)法
    • 2. 随机法
    • 3. 源地址哈希法
    • 4. 加权轮询(Weight Round Robin)法
    • 5. 加权随机(Weight Random)法
    • 6. 最小连接数法
  • grpc负载均衡策略
  • 为什么需要分布式配置中心
    • 分布式配置中心选型
    • nacos的基本使用
    • gin集成nacos
    • 如何将nacos中的配置映射成go的struct

什么是服务注册和发现

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

技术选型

Consul 与其他常见服务发现框架对比

image.png

Consul 的安装和配置

1. 安装

docker run -d -p 8500:8500 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8600:8600/ud
docker container update --restart=always 容器名字

2. 访问

浏览器访问 127.0.0.1:8500

3. 访问dns

consul提供dns功能,可以让我们通过, 可以通过dig命令行来测试,consul默认的dns端口是8600, 命令行:
linux下的dig命令安装:
yum install bind-utils

dig @192.168.1.103 -p 8600 consul.service.consul SRV 

windows下载dig命令 :dig.zip

Consul 的api接口

  1. 添加服务
    https://www.consul.io/api-docs/agent/service#register-service
  2. 删除服务
    https://www.consul.io/api-docs/agent/service#deregister-service
  3. 设置健康检查
    https://www.consul.io/api-docs/agent/check
  4. 同一个服务注册多个实例
  5. 获取服务
    https://www.consul.io/api-docs/agent/service#list-services

go操作consul

package main
	import (
		"fmt"
		"github.com/hashicorp/consul/api"
	)
func Register(address string, port int, name string, tags []string, id string) er
	cfg := api.DefaultConfig()
	cfg.Address = "192.168.1.103:8500"
	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}
	//⽣成对应的检查对象
	check := &api.AgentServiceCheck{
	HTTP: "http://192.168.1.102:8021/health",
	Timeout: "5s",
	Interval: "5s",
	DeregisterCriticalServiceAfter: "10s",
}
	//⽣成注册对象
	registration := new(api.AgentServiceRegistration)
	registration.Name = name
	registration.ID = id
	registration.Port = port
	registration.Tags = tags
	registration.Address = address
	registration.Check = check
	err = client.Agent().ServiceRegister(registration)
	if err != nil {
	panic(err)
	}
		return nil
	}
func AllServices(){
	cfg := api.DefaultConfig()
	cfg.Address = "192.168.1.103:8500"
	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}
	data, err := client.Agent().Services()
	if err != nil {
		panic(err)
	}
	for key, _ := range data{
	fmt.Println(key)
	}
}
func FilterSerivice(){
	cfg := api.DefaultConfig()
	cfg.Address = "192.168.1.103:8500"
	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}
	data, err := client.Agent().ServicesWithFilter(`Service == "user-web"`)
	if err != nil {
		panic(err)
	}
	for key, _ := range data{
		fmt.Println(key)
	}
}
func main(){
	//_ = Register("192.168.1.102", 8021, "user-web", []string{"mxshop", "bobby"}
	//AllServices()
	FilterSerivice()
}

grpc下的健康检查

grpc的健康检查规范

官方文档

grpc健康检查重要点:

1. check = {
“GRPC”: f’{ip}:{port}’,
“GRPCUseTLS”: False,
“Timeout”: “5s”,
“Interval”: “5s”,
“DeregisterCriticalServiceAfter”: “5s”,
}
  1. 一定要确保网络是通的
  2. 一定要确保srv服务监听端口是对外可访问的
  3. GRPC一定要自己填写

动态获取可用端口号

package utils
	import (
		"net"
	)
	func GetFreePort() (int, error) {
		addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
		if err != nil {
		return 0, err
	}
	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	defer l.Close()
	return l.Addr().(*net.TCPAddr).Port, nil
}

负载均衡策略

1. 什么是负载均衡

image.png

2. 负载均衡策略

1. 集中式load balance

集中式LB方案,如下图。首先,服务的消费方和提供方不直接耦合,而是在服务消费者和服务提供者之间有一个独立的LB(LB通常是专门的硬件设备如F5,或者基于软件如LVS,HAproxy等实现)。

image.png

LB上有所有服务的地址映射表,通常由运维配置注册,当服务消费方调用某个目标服务时,它向LB发起请求,由LB以某种策略(比如Round-Robin)做负载均衡后将请求转发到目标服务。

服务消费方如何发现LB呢?通常的做法是通过DNS,运维人员为服务配置一个DNS域名,这个域名指向LB。
这种方案基本可以否决,因为它有致命的缺点:所有服务调用流量都经过load balance服务器,所以load balance服务器成了系统的单点,一旦LB发生故障对整个系统的影响是灾难性的。为了解决这个问题,必然需要对这个load balance部件做分布式处理(部署多个实例,冗余,然后解决一致性问题等全家桶解决方案),但这样做会徒增非常多的复杂度。

2. 进程内load balance

进程内load balance。将load balance的功能和算法以sdk的方式实现在客户端进程内。先看架构图:

image.png

可看到引入了第三方:服务注册中心。它做两件事:

  1. 维护服务提供方的节点列表,并检测这些节点的健康度。检测的方式是:每个节点部署成功,都通知服务注册中心;然后一直和注册中心保持心跳。
  2. 允许服务调用方注册感兴趣的事件,把服务提供方的变化情况推送到服务调用方。这种方案下,整个load balance的过程是这样的:
  3. 服务注册中心维护所有节点的情况。
  4. 任何一个节点想要订阅其他服务提供方的节点列表,向服务注册中心注册。
  5. 服务注册中心将服务提供方的列表(以长连接的方式)推送到消费方。
  6. 消费方接收到消息后,在本地维护一份这个列表,并自己做load balance。

可见,服务注册中心充当什么角色?它是唯一一个知道整个集群内部所有的节点情况的中心。所以对它的可用性要求会非常高,这个组件可以用Zookeeper实现。
这种方案的缺点是:每个语言都要研究一套sdk,如果公司内的服务使用的语言五花八门的话,这方案的成本会很高。第二点是:后续如果要对客户库进行升级,势必要求服务调用方修改代码并重新发布,所以该方案的升级推广有不小的阻力。

3. 独立进程load balance

该方案是针对第二种方案的不足而提出的一种折中方案,原理和第二种方案基本类似,不同之处是,他将LB和服务发现功能从进程内移出来,变成主机上的一个独立进程,主机上的一个或者多个服务要访问目标服务时,他们都通过同一主机上的独立LB进程做服务发现和负载均衡。如图

image.png

这个方案解决了上一种方案的问题,不需要为不同语言开发客户库,LB的升级不需要服务调用方改代码。
但新引入的问题是:这个组件本身的可用性谁来维护?还要再写一个watchdog去监控这个组件?另外,多了一个环节,就多了一个出错的可能,线上出问题了,也多了一个需要排查的环节。

常见的负载均衡算法

在分布式系统中,多台服务器同时提供一个服务,并统一到服务配置中心进行管理,消费者通过查询服务配置中心,获取到服务到地址列表,需要选取其中一台来发起RPC远程调用。如何选择,则取决于具体的负载均衡算法,对应于不同的场景,选择的负载均衡算法也不尽相同。负载均衡算法的种类有很多种,常见的负载均衡算法包括轮询法、随机法、源地址哈希法、加权轮询法、加权随机法、最小连接法等,应根据具体的使用场景选取对应的算法。

1. 轮询(Round Robin)法

轮询很容易实现,将请求按顺序轮流分配到后台服务器上,均衡的对待每一台服务器,而不关心服务器实际的连接数和当前的系统负载。

2. 随机法

通过系统随机函数,根据后台服务器列表的大小值来随机选取其中一台进行访问。由概率概率统计理论可以得知,随着调用量的增大,其实际效果越来越接近于平均分配流量到后台的每一台服务器,也就是轮询法的效果。

3. 源地址哈希法

源地址哈希法的思想是根据服务消费者请求客户端的IP地址,通过哈希函数计算得到一个哈希值,将此哈希值和服务器列表的大小进行取模运算,得到的结果便是要访问的服务器地址的序号。采用源地址哈希法进行负载均衡,相同的IP客户端,如果服务器列表不变,将映射到同一个后台服务器进行访问。

4. 加权轮询(Weight Round Robin)法

不同的后台服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不一样。跟配置高、负载低的机器分配更高的权重,使其能处理更多的请求,而配置低、负载高的机器,则给其分配较低的权重,降低其系统负载,加权轮询很好的处理了这一问题,并将请求按照顺序且根据权重分配给后端。

5. 加权随机(Weight Random)法

加权随机法跟加权轮询法类似,根据后台服务器不同的配置和负载情况,配置不同的权重。不同的是,它是按照权重来随机选取服务器的,而非顺序。

6. 最小连接数法

前面我们费尽心思来实现服务消费者请求次数分配的均衡,我们知道这样做是没错的,可以为后端的多台服务器平均分配工作量,最大程度地提高服务器的利用率,但是,实际上,请求次数的均衡并不代表负载的均衡。因此我们需要介绍最小连接数法,最小连接数法比较灵活和智能,由于后台服务器的配置不尽相同,对请求的处理有快有慢,它正是根据后端服务器当前的连接情况,动态的选取其中当前积压连接数最少的一台服务器来处理当前请求,尽可能的提高后台服务器利用率,将负载合理的分流到每一台服务器。

grpc负载均衡策略

  1. grpc的负载均衡策略
    文档

  2. go使用grpc负载均衡
    文档

  3. 关于serverconfig
    官方文档

  4. go的grpc测试

package main
	import (
		"OldPackageTest/grpclb_test/proto"
		"context"
		"fmt"
		"log"
		_ "github.com/mbobakov/grpc-consul-resolver" // It's important
		"google.golang.org/grpc"
	)
func main() {
	conn, err := grpc.Dial(
	"consul://192.168.1.103:8500/user-srv?wait=14s&tag=srv",
	grpc.WithInsecure(),
	grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	for i := 0; i<10; i++{
		userSrvClient := proto.NewUserClient(conn)
		rsp, err := userSrvClient.GetUserList(context.Background(), &proto.PageIn
		Pn: 1,
		PSize: 2,
	})
	if err != nil {
		panic(err)
	}
	for index, data := range rsp.Data{
		fmt.Println(index, data)
		}
	}
}

为什么需要分布式配置中心

我们现在有一个项目,使用gin进行开发的,配置文件的话我们知道是一个叫做config.yaml的文件。
我们也知道这个配置文件会在项目启动的时候被加载到内存中进行使用的。
考虑两种情况:
a. 添加配置项
ⅰ. 你现在的用户服务有10个部署实例,那么添加配置项你得去十个地方修改配置文件还得重新启动等。
ⅱ. 即使go的viper能完成修改配置文件自动生效,那么你得考虑其他语言是否也能做到这点,其他的服务是否也一定会使用viper?
b. 修改配置项
大量的服务可能会使用同一个配置,比如我要更好jwt的secrect,这么多实例怎么办?
c. 开发、测试、生产环境如何隔离:
前面虽然已经介绍了viper,但是依然一样的问题,这么多服务如何统一这种考虑因素?

分布式配置中心选型

目前最主流的分布式配置中心主要是有spring cloud config、 apollo和nacos,spring cloud属于java的spring体系,我们就考虑apollo和nacos。apollo与nacos 都为目前比较流行且维护活跃的2个配置中心。
apollo是协程开源,nacos是阿里开源

  1. apollo大而全,功能完善。nacos小而全,可以对比成django和flask的区别
  2. 部署nacos更加简单。
  3. nacos不止支持配置中心还支持服务注册和发现。
  4. 都支持各种语言,不过apollo是第三方支持的,nacos是官方支持各种语言

两者都很活跃,不过看得出来nacos想要构建的生态野心更大,不过收费意图明显。

image.png

nacos的基本使用

文档

  1. 命名空间
    可以隔离配置集,将某些配置集放到某一个命名空间之下。
    命名空间我们一般用来区分 微服务

  2. 抛出一个问题: 你现在确实能够隔离微服务,但是不同的微服务的开发、测试、生产环境如何区别,组可以用来区别区别开发、测试、生产环境
  3. dataid - 配置集
    一个配置集就是一个配置文件, 实际上可以更灵活

gin集成nacos

nacos-sdk-go地址

  1. go操作nacos
package main
	import (
		"fmt"
		"time"
		"github.com/nacos-group/nacos-sdk-go/clients"
		"github.com/nacos-group/nacos-sdk-go/common/constant"
		"github.com/nacos-group/nacos-sdk-go/vo"
	)
func main(){
	sc := []constant.ServerConfig{
	{
	IpAddr: "192.168.1.103",
	Port: 8848,
	},
}
	cc := constant.ClientConfig {
	NamespaceId: "c1872978-d51c-4188-a497-4e0cd20b97d5", // 如果需要⽀持
	TimeoutMs: 5000,
	NotLoadCacheAtStart: true,
	LogDir: "tmp/nacos/log",
	CacheDir: "tmp/nacos/cache",
	RotateTime: "1h",
	MaxAge: 3,
	LogLevel: "debug",
}
configClient, err := clients.CreateConfigClient(map[string]interface{}{
	"serverConfigs": sc,
	"clientConfig": cc,
})
if err != nil {
	panic(err)
}
	content, err := configClient.GetConfig(vo.ConfigParam{
	DataId: "user-web.yaml",
	Group: "dev"})
	if err != nil {
		panic(err)
	}
	fmt.Println(content)
	err = configClient.ListenConfig(vo.ConfigParam{
		DataId: "user-web.yaml",
		Group: "dev",
	OnChange: func(namespace, group, dataId, data string) {
		fmt.Println("配置⽂件变化")
		fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + dat
		},
	})
	time.Sleep(3000 * time.Second)
}

如何将nacos中的配置映射成go的struct

转换地址: https://www.json2yaml.com/convert-yaml-to-json

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

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

相关文章

Python+Selenium+Unittest 之selenium12--WebDriver操作方法2-鼠标操作1(ActionChains类简介)

在我们平时的使用过程中&#xff0c;会使用鼠标去进行很多操作&#xff0c;比如鼠标左键点击、双击、鼠标右键点击&#xff0c;鼠标指针悬浮、拖拽等操作。在selenium中&#xff0c;我们也可以去实现常用的这些鼠标操作&#xff0c;这时候就需要用到selenium中的ActionChains类…

采用springboot 2.7.10来操作clickhouse

1、采用springboot与clickhouse结合&#xff0c;其实和操作mysql&#xff0c;oracle区别不大。直接上代码开干 2、所采用的环境 jdk1.8 springboot 2.7.10 clickhouse 22.8.3.13 clickhouse 0.5.0 3、项目的pom.xml文件 <dependency><groupId>com.clickhous…

基于SSM框架的共享单车管理系统小程序系统的设计和实现

基于SSM框架的共享单车管理系统小程序系统的设计和实现 源码传送入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码传送入口 前言 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;…

整理笔记——稳压直流电路知识

一、稳压直流电路的基本构成 稳压直流电路就是把生活中常用的220V交流电转换成稳压直流电。如生活中常见的手机充电器就是一个稳压直流电路。其主要功能是提供持续稳定且满足要求的电压。 直流稳压电路由一下几个模块组成&#xff1a; 下面具体分析下各个模块的功能。…

编译原理——构造预测分析表(判断某字符串是否是文法G(E)的句子)

进入今天的学习前&#xff0c;若不理解LL(1)文法中的首符号集&#xff0c;后跟符号集和选择符号集&#xff0c;可看&#xff1a; http://t.csdnimg.cn/BjSHv 构造预测分析表的步骤&#xff1a; 步骤1&#xff1a;对文法的每个规则U->u,执行步骤2与3 步骤2&#xff1a;对…

Springboot---整合对象储存服务MinIO

OSS 「OSS」的英文全称是Object Storage Service&#xff0c;翻译成中文就是「对象存储服务」&#xff0c;官方一点解释就是对象存储是一种使用HTTP API存储和检索非结构化数据和元数据对象的工具。 白话文解释就是将系统所要用的文件上传到云硬盘上&#xff0c;该云硬盘提供了…

chatGPT使用情况

作为一个语言模型&#xff0c;我&#xff08;ChatGPT&#xff09;被用于各种不同的应用场景。以下是一些常见的情况&#xff1a; 个人助手&#xff1a;人们可以使用我来获取信息、解答问题、获取建议或进行闲聊。我可以提供各种知识和帮助&#xff0c;从学术知识到日常生活的建…

nginx发布vue项目

1、docker拉取nginx镜像 docker pull nginx:latest2、docker安装nginx # 第一个80端口是主机端口&#xff0c;第二个80端口是内部端口&#xff0c;主机的端口 80 映射到容器内部的端口80 docker run -d --name nginx -p 80:80 -p 443:443 nginx:lateste3、输入IP访问 说明我们…

javaEE进阶

Cookie 是可以伪造的,比如说学生证是可以伪造的 Session 是不可以伪造的,这是学校系统记录在册的 如何获取 Cookie 我们先用 Servlet 原生的获取 cookie 的方式 我们在浏览器进行访问 但是实际上目前是没有 cookie 的,我们按 F12 进行添加 然后再重新访问,就能在 idea 看到 …

什么是高敏感型人格,高敏型人格如何改变自己

什么是高敏感型人格&#xff1f; 高敏感型人格&#xff0c;指的是个体情绪敏感度高&#xff0c;有好处也有不好的地方&#xff0c;比如说好处吧&#xff0c;高敏感型人格他们对情绪的感知更加细腻&#xff0c;这种特征在创作和设计方面&#xff0c;往往能到达常人所不能达到的…

NIO讲解

一&#xff1a;什么是NIO? 二&#xff1a;NIO三大组件 1. channel channel 有一点类似于 stream&#xff0c;它就是读写数据的双向通道&#xff0c;可以从 channel 将数据读入 buffer&#xff0c;也可以将 buffer 的数据写入 channel&#xff0c;而之前的 stream 要么是输入…

C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发006:基于redis查找玩家姓名+游戏业务实现总结

文章目录 1 Redis的安装与API的使用1.1 安装目录及环境变量1.2 设置远程客户端连接和守护进程1.3 启动redis1.4 Hiredis API的使用1.5 我的动态库和头文件 2 Redis的使用2.1 初始化时候2.2 结束的时候 3 测试4 Makefile5 游戏业务总结 1 Redis的安装与API的使用 1.1 安装目录及…

Kotlin HashMap entries.filter过滤forEach

Kotlin HashMap entries.filter过滤forEach fun main(args: Array<String>) {val hashMap HashMap<String, Int>()hashMap["a"] 1hashMap["b"] 2hashMap["c"] 3println(hashMap)hashMap.entries.filter {println("filter $…

Python用requests库采集充电桩LBS位置经纬度信息

这是一个使用Python的requests库来爬取网页内容的示例。首先&#xff0c;我们需要导入requests库。然后&#xff0c;我们需要定义一个函数来处理请求。在这个函数中&#xff0c;我们需要设置爬虫IP服务器的URL和端口号&#xff0c;然后使用requests.get来获取网页内容。最后&am…

将 Figma 轻松转换为 Sketch 的免费方法

最近浏览网站的时候&#xff0c;发现很多人不知道Figma是怎么转Sketch的。众所周知&#xff0c;Figma支持Sketch文件的导入&#xff0c;但不支持Sketch的导出&#xff0c;那么Figma是如何转Sketch的呢&#xff1f;不用担心&#xff0c;建议使用神器即时设计。它是一个可以实现在…

【C++】类和对象(一):什么是面向对象,访问限定符有哪些,类定义细节,结构体和类的关系。

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

使用ffmpeg调用电脑自带的摄像头和扬声器录制音视频

1、打开cmd&#xff0c;执行chcp 65001,修改cmd的编码格式为utf8&#xff0c;避免乱码 2、执行指令ffmpeg -list_devices true -f dshow -i dummy,查看当前window的音频和视频名称 3、打开windows系统的"打开声音设置"–“麦克风隐私设置”–"允许应用访问你…

Vue 将响应式数据转为普通对象

toRaw&#xff1a;将一个 reactive 生成的响应式数据转为普通对象。 toRaw 适用于&#xff1a;获取响应式数据对应的普通对象&#xff0c;对这个普通对象所有的操作&#xff0c;都不会引起页面的更新。 markRaw&#xff1a;标记一个对象&#xff0c;使其永远不会再成为响应式…

C++中将数据添加到文件的末尾

参考:https://blog.csdn.net/qq_23880193/article/details/44279283 C中文件的读取需要包含fstream文件&#xff0c;即&#xff1a;#include 文件的读取和写入是是通过流操作来的&#xff0c;这不像输入、输出流那样&#xff0c;库中已经定义了对象cin和cout 文件的读取需要声…

lv11 嵌入式开发 ARM体系结构理论基础2

目录 1 ARM概述 1.1 处理器分类 1.2 SOC概念 2 ARM指令集概述 2.1 ARM指令集 2.2 编译原理 3 ARM存储模型 3.1 ARM数据类型 3.2 字节序 3.3 ARM指令存储 4 ARM工作模式 4.1 ARM工作模式分类 1 ARM概述 ARM的含义 ARM&#xff08;Advanced RISC Machines&#…