学习负载均衡的算法

什么负载均衡

负载均衡是一种计算机技术,用于在多个系统、网络链接、硬盘驱动器、CPU等之间分配工作负载,以优化资源使用、最大化吞吐量、最小化响应时间、并避免任何单一资源的过载。在网络负载均衡的情况下,它可以帮助将网络流量有效地分配到多个服务器。
负载均衡可以在硬件、软件或两者的组合中实现。它通常使用一种算法,如轮询、最少连接、IP哈希或其他自定义方法,来决定将请求发送到哪个服务器。
在微服务架构和大规模并行处理的环境中,负载均衡尤其重要,因为它可以帮助分散大量的请求,并确保系统的稳定性和可靠性。

负载均衡的算法有那些

  1. round-robin (轮询)
  2. random(随机)
  3. ip-hash
  4. power of 2 random choice (两次随机策略)
  5. consistent hash (一致性hash)
  6. consistent hash with bounded (有界一致性hash)
  7. least-load(最小连接)
  8. Weighted Round Robin(权重轮询)

round-robin(轮询)

在这里插入图片描述
i的类型是线程安全的,每次请求i就 +1
hosts 是目标服务器中host的slice,可以存储多个host
每次请求我们的i就会+1然后和host是的长度进行取余来轮询我们的目标服务器的ip。

random(随机)

在这里插入图片描述
rnd 是个随机来源
我们在调用该函数的时候需要先下一个随机种子

	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))

每次我们使用的时候,会根据hosts长度的大小随机一个该长度内的数据来获取一个目标服务器的ip。

ip-hash (ip哈希)

在这里插入图片描述
我们通过代码可以看到,传入进来的client的ip是通过crc32进行了hash计算,算出来一个值以后和hosts的长度进行了取余。
该负责均衡的算法有个好处就是同一个ip的用户访问我们的服务会被分配到同一个目标服务器上。

power of 2 random choice (两次随机策略)

type host struct {name stringload uint64
}// P2C refer to the power of 2 random choice
type P2C struct {sync.RWMutexhosts   []*hostrnd     *rand.RandloadMap map[string]*host
}// NewP2C create new P2C balancer
func NewP2C(hosts []string) Balancer {p := &P2C{hosts:   []*host{},loadMap: make(map[string]*host),rnd:     rand.New(rand.NewSource(time.Now().UnixNano())),}for _, h := range hosts {p.Add(h)}return p
}// Add new host to the balancer
func (p *P2C) Add(hostName string) {p.Lock()defer p.Unlock()if _, ok := p.loadMap[hostName]; ok {return}h := &host{name: hostName, load: 0}p.hosts = append(p.hosts, h)p.loadMap[hostName] = h
}// Remove new host from the balancer
func (p *P2C) Remove(host string) {p.Lock()defer p.Unlock()if _, ok := p.loadMap[host]; !ok {return}delete(p.loadMap, host)for i, h := range p.hosts {if h.name == host {p.hosts = append(p.hosts[:i], p.hosts[i+1:]...)return}}
}// Balance selects a suitable host according to the key value
func (p *P2C) Balance(key string) (string, error) {p.RLock()defer p.RUnlock()if len(p.hosts) == 0 {return "", NoHostError}n1, n2 := p.hash(key)host := n2if p.loadMap[n1].load <= p.loadMap[n2].load {host = n1}return host, nil
}func (p *P2C) hash(key string) (string, string) {var n1, n2 stringif len(key) > 0 {saltKey := key + Saltn1 = p.hosts[crc32.ChecksumIEEE([]byte(key))%uint32(len(p.hosts))].namen2 = p.hosts[crc32.ChecksumIEEE([]byte(saltKey))%uint32(len(p.hosts))].namereturn n1, n2}n1 = p.hosts[p.rnd.Intn(len(p.hosts))].namen2 = p.hosts[p.rnd.Intn(len(p.hosts))].namereturn n1, n2
}// Inc refers to the number of connections to the server `+1`
func (p *P2C) Inc(host string) {p.Lock()defer p.Unlock()h, ok := p.loadMap[host]if !ok {return}h.load++
}// Done refers to the number of connections to the server `-1`
func (p *P2C) Done(host string) {p.Lock()defer p.Unlock()h, ok := p.loadMap[host]if !ok {return}if h.load > 0 {h.load--}
}

我们看到(两次随机策略)的算法和ip-hash一样都是使用crc32的hash算法,只不过ip-hash是对key 进行一次hash然后于hosts的长度进行取余,但是(两次随机策略)是对同一个key进行两次hash,一次是用key直接进行hash,另外一次是对key加盐之后进行hash,这时候就求出来两个值,然后在hosts里面获取两个ip,然后对比他们的连接数,取最小连接数。

我们还发现当我们传入的key是个空值的时候,(两次随机策略)使用的随机策略。

Inc 方法和Done方法是在我们进行访问的时候会对连接的ip进行连接数的加减。

consistent hash (一致性hash)

在学习算法之前我们需要先学习下一致性hash

什么是一致性hash

一致性哈希(Consistent Hashing)是一种特殊的哈希技术,广泛应用于分布式系统中,用于解决数据的分布式存储问题。

在传统的哈希表中,如果哈希空间的大小发生变化(例如,增加或减少服务器),几乎所有的键值对都需要重新映射,这会导致大量的数据迁移,对系统的性能和稳定性产生影响。

一致性哈希通过引入虚拟节点和环形哈希空间的概念,使得哈希空间的大小变化时,只有一小部分的键值对需要重新映射。这大大减少了数据迁移的数量,提高了系统的稳定性。

一致性hash解决什么问题

一致性哈希(Consistent Hashing)主要解决分布式系统中的数据分布和负载均衡问题。

一致性哈希通过创建一个环形的哈希空间,并将节点和数据都映射到这个空间上,使得节点数量的变化只会影响哈希空间中的一小部分数据,大大减少了数据重新分配的数量。这使得一致性哈希非常适合动态变化的系统。

一致性哈希还可以通过引入虚拟节点来解决数据分布不均的问题。通过为每个节点创建多个虚拟节点,可以使得数据更均匀地分布在各个节点上,从而实现更好的负载均衡。

原理

在传统的哈希表中,如果哈希空间的大小发生变化,几乎所有的键值对都需要重新映射,这会导致大量的数据迁移,对系统的性能和稳定性产生影响。

但是一致性哈希通过引入虚拟节点和环形哈希空间的概念,使得哈希空间的大小变化时,只有一小部分的键值对需要重新映射。这大大减少了数据迁移的数量,提高了系统的稳定性。

一致性hash算法是对232 进行取模运算,是一个固定的值。通过和232 次进行取模运算的结果值组织成一个圆环。所以,一致性哈希是指将「存储节点」和「数据」都映射到一个首尾相连的哈希环上。
在这里插入图片描述
在hash 环上的结果的映射是顺时针方向第一个节点。
在这里插入图片描述
如果hash环上增加了节点,并不会想传统hash一样发生大量数据迁移的情况从而造成(hash洪水),而是只有部分数据会发生迁移。
在这里插入图片描述
但是一般的hash环会有个节点分布不均匀的问题,这样会导致如会有大量的数据或请求指向同一个节点上去。
在这里插入图片描述
为了解决这个问题我们在hash环上引入虚拟节点来均衡实体节点在hash环上分布不均匀的问题。
在这里插入图片描述
这时候节点数量多了以后,节点在hash环上的分布就均匀了。
在这里插入图片描述
我们看一致性hash负载均衡的类,里面有hash一致性的函数。
在这里插入图片描述
在这里插入图片描述

我们在调用一致性hash的add的时候我们看源码发现,针对每个host我们会创建10个虚拟的因子来加入到hash环上。
在这里插入图片描述
在这里插入图片描述
当我们在发送请求的时候通过我们client ip去获取对应的server ip
在这里插入图片描述
这里我们需要看下c.hash这个方法

  1. blake2b.Sum512:这一行代码将key转换为一个字节切片,然后使用BLAKE2b哈希算法计算其512位(64字节)的哈希值。BLAKE2b是一种密码学哈希函数,可以生成不同长度的哈希值,这里生成的是512位的哈希值。计算结果被存储在out中。、
  2. binary.LittleEndian.Uint64(out[:]):这一行代码将out的前8个字节(64位)解释为一个小端格式的无符号整数。

在这里插入图片描述
我们在看下search函数,该函数使用key计算出来的hash的值和hash环中的值进行比较,并返回index。
在这里插入图片描述
我们通过上面函数返回的index获取到hash环中的对应的hash值,在冲hosts中获取到对应的服务器ip。

consistent hash with bounded (有界一致性hash)

在这里插入图片描述

什么是有界一致性hash

有界一致性哈希(Bounded Load Consistent Hashing)是一致性哈希的一个改进版本,它在一致性哈希的基础上增加了负载均衡的考虑。

在传统的一致性哈希中,虽然理论上数据会均匀地分布在各个节点上,但在实际应用中,由于哈希函数的随机性,可能会出现某些节点上数据过多,而某些节点上数据过少的情况,这被称为"哈希倾斜"。

有界一致性哈希通过引入一个负载因子的概念来解决这个问题。每个节点都有一个负载因子,表示该节点当前承载的数据量。当一个新的数据项需要被插入时,它不仅会考虑哈希环上的位置,还会考虑各个节点的负载因子,优先选择负载因子较小的节点。

这样,有界一致性哈希不仅保持了一致性哈希的优点(如高可用性和可扩展性),还提高了系统的负载均衡性,使得数据在各个节点之间的分布更加均匀。

在这里插入图片描述
有界一致性hash 其实和一致性的hash的添加方式是一样的,不一样是不一样在获取和请求的时候,有界一致性hash多了一个对ip负载的统计,不废话上代码。
在这里插入图片描述

在这里插入图片描述

  1. Inc是对我们请求的servic ip进行负载的原子操作+1
  2. Done是在我们对service ip 请求结束后的进行负载的原子操作-1

在这里插入图片描述
通过ip获取到服务器的service ip ,接下来我们看看GetLeast
在这里插入图片描述
在这里插入图片描述
hash和search这两个函数我们在一致性hash的时候解读过了,这里我们看看loadOk 这个函数,这个函数是来比较每个节点的平均负载,获取最小负载的host

通过代码我们可以看出我们要获取到负载小于平均负载的host

我们看到代码中*1.25 为什么这样作呢,是为了引入一个负载因子,使得每个节点可以接受稍微超过平均负载的请求。

乘以1.25就是为了给每个节点提供一些额外的容量,允许其负载稍微超过平均负载,以应对这种情况。这样可以提高系统的灵活性和鲁棒性,使得在节点的负载稍微超过平均负载时,系统仍能正常工作,而不是立即拒绝新的请求。

least-load(最小连接)

“Least Load” 是一种负载均衡策略,其目标是将新的请求分配给当前负载最小的服务器。这种策略可以帮助确保所有的服务器都能得到充分利用,同时避免某些服务器过载。

该策略使用了斐波那契堆来实现

斐波那契堆(Fibonacci Heap)是一种优先队列数据结构,它支持一系列操作,如插入、获取最小值、合并等,具有很好的理论性能。斐波那契堆在图算法(如 Dijkstra 和 Prim)中特别有用,因为它可以更有效地处理减少关键字的操作。

斐波那契堆的特点是:

  • 它是一组最小堆有序树的集合,这些树都满足斐波那契堆的性质(即,每个节点的孩子数大于或等于其父节点的秩)。
  • 它有一个指针指向最小元素。
  • 它的所有操作(插入、删除最小元素、减少关键字、合并两个堆)都有很好的平摊时间复杂度。

在这里插入图片描述
我们在使用该策略的时候发现host让存入了斐波那契堆里面。该堆里面还记录了每个host的负载。
在这里插入图片描述
我们在每次请求的时候通过client ip 获取对应的host,但是在请求的时候会堆该host进行负载+1,请求结束以后会进行负载 -1
在这里插入图片描述
所以我们在获取service ip的时候就非常方便的从该堆里面获取到负载最小的ip,防止我们某个服务器过载。
在这里插入图片描述
我们在初始化该策略的时候会将host 通过斐波那契堆的insert存入到该堆的节点里面。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们在请求的时候需要堆host进行负载的加减,这两个函数是通过递归的形式对堆里面的元素进行操作的。

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

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

相关文章

300分钟吃透分布式缓存-11讲:MC如何淘汰冷key和失效key?

淘汰策略 Mc 作为缓存组件&#xff0c;意味着 Mc 中只能存储访问最频繁的热数据&#xff0c;一旦存入数据超过内存限制&#xff0c;就需要对 Mc 中的冷 key 进行淘汰工作。Mc 中的 key 基本都会有过期时间&#xff0c;在 key 过期后&#xff0c;出于性能考虑&#xff0c;Mc 并…

SpringBoot中Redis缓存的使用

目录 1 前言 2 实现方法 2.1 查询数据时 2.2 修改数据 1 前言 对于一些不常改变&#xff0c;但又经常查询的数据&#xff0c;我们可以使用Redis缓存&#xff0c;来缓解数据库的压力&#xff0c;其中的逻辑如下&#xff1a; 2 实现方法 2.1 查询数据时 一般在控制类查询方…

SMIC思洣客矩阵:重塑数字经济的未来

经济的发展 经济是供需满足的过程&#xff0c;它涵盖了社会物资的生产和再生产过程。在这个过程中&#xff0c;经济活动遵循着生产和再生产的规律&#xff0c;通过生产、分配、交换和消费的过程&#xff0c;不断地形成和再造价值。从传统的市场经济到现代的智能经济&#xff0…

Shell好用的工具: cut

目标 使用cut可以切割提取指定列\字符\字节的数据 介绍 cut 译为“剪切, 切割” , 是一个强大文本处理工具&#xff0c;它可以将文本按列进行划分的文本处理。cut命令逐行读入文本&#xff0c;然后按列划分字段并进行提取、输出等操作。 语法 cut [options] filename opti…

快速学习安全框架 Springsecurity最新版(6.2)--用户授权模块

简介 上一节Springsecurity 用户认证 Springsecurity 拥有强大的认证和授权功能并且非常灵活&#xff0c;,一来说我们都i有以下需求 可以帮助应用程序实现以下两种常见的授权需求&#xff1a; 用户-权限-资源&#xff1a;例如张三的权限是添加用户、查看用户列表&#xff0c;李…

1.1_1 计算机网络的概念、功能、组成和分类

文章目录 1.1_1 计算机网络的概念、功能、组成和分类&#xff08;一&#xff09;计算机网络的概念&#xff08;二&#xff09;计算机网络的功能&#xff08;三&#xff09;计算机网络的组成1.组成部分2.工作方式3.功能组成 &#xff08;四&#xff09;计算机网络的分类 总结 1.…

频段划分学习射频知识的意义

一、射频电路设计与低频电路设计的不同点 随着频率提高&#xff0c;相应电磁波的波长与变得可与分立电路元件的尺寸相比拟时&#xff0c;电阻、电容和电感这些元件的电响应&#xff0c;将偏离他们的理想频率特性。以 WIFI 2.4G 频段为例&#xff0c;当频率为 2437MHz&#xff0…

快速排序、归并排序和堆排序的原理与实现

排序算法是计算机科学中的基本算法之一&#xff0c;用于将一组元素按照一定顺序排列。快速排序、归并排序和堆排序是三种常见的排序算法&#xff0c;各有其特点和适用场景。 快速排序 (Quick Sort) 快速排序是一种经典的分而治之的排序算法。其基本思想是选择一个基准元素&am…

Chat With RTX 安装、使用问题记录

1.安装包运行检测环境失败 安装适合的的CUDA&#xff1a;https://developer.nvidia.com/cuda-downloads?target_osWindows&target_archx86_64&target_version11 2.安装Chat With RTX 和 模型 Mistral 7B 失败 科学上网&#xff0c;可以单独装Chat With RTX 先&…

实习日志30

概要 高拍仪硬件通信原理&#xff0c;WebSocket源码解析&#xff08;JavaScript&#xff09; WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据…

智能科技助力服装业:商品计划管理系统的革命性变革

随着智能科技的飞速发展&#xff0c;服装行业正在经历前所未有的变革。在这股浪潮中&#xff0c;商品计划管理系统的智能化转型成为了行业的核心驱动力。这种变革不仅极大地提高了服装企业的运营效率和市场竞争力&#xff0c;更为整个行业的可持续发展注入了新的活力。 智能商…

【Power Apps】实现一个简单的可编辑列表

简单来说&#xff0c;我们这次是要实现一个可以直接在列表上增加、修改、删除数据的功能。 大概就像这样。 之前我们都是拿列表做一个数据展示的功能&#xff0c;真要增加、修改、删除数据是在另一张表单上做的&#xff0c;我们这回要去掉另一个表单&#xff0c;直接在列表上做…

ProtoBuf认识与Windows下的安装

protobuf简介 Protobuf 是 Protocol Buffers 的简称&#xff0c;它是 Google 公司开发的一种数据描述语言&#xff0c;是一种轻便高效的结 构化数据存储格式&#xff0c;可以用于结构化数据&#xff0c;或者说序列化。它很适合做数据存储 或 RPC 数据交换格 式 。可用于通讯…

qt 软件发布(Windows)

1. 开发环境 QtCreator MSVC编译器 2. 源码编译 生成release或者debug版本的exe可执行文件(x64或x86) 3. windeployqt 打包 ①左下角开始菜单栏找到QT的命令交互对话框&#xff0c;如下图MSVC 2017 64-bit(根据第二步编译的类型选择64位或者32位)。 ②cd 切换到第二步可…

vue实现拖拽(vuedraggable)

实现效果: 左侧往右侧拖动&#xff0c;右侧列表可以进行拖拽排序。 安装引用&#xff1a; npm install vuedraggable import draggable from vuedraggable 使用&#xff1a; data数据&#xff1a; componentList: [{groupName: 考试题型,children: [{componentType: danxua…

数字信号处理:傅里叶分析

本文主要参考视频如下&#xff1a; 数字信号处理9-1_线性时不变系统对复指数信号的响应_哔哩哔哩_bilibili 傅里叶分析的主要研究内容如下所示&#xff1a; 注意&#xff0c;计算机中使用的离散傅里叶变换并不是离散时间傅里叶变换&#xff1b; 前四种都是理论上的变换方式&…

构建生物医学知识图谱from zero to hero (4):通过Neo4j构建知识图谱

图数据库是一种专门用于存储图形数据的 NoSQL 数据库。与传统的关系型数据库和其他 NoSQL 数据库不同,图数据库利用图形数据模型来存储和管理数据。图形数据模型由节点和边组成,节点代表实体,边代表实体之间的关系。例如,在社交网络中,用户可以表示为节点,朋友关系可以表…

15-36V降压充电光伏MPPT充电方案

1.MPPT原理--简介 MPPT&#xff0c;全称为Maximum Power Point Tracking&#xff0c;即最大功点跟踪&#xff0c;它是一种通过调节电气模块的工作状态&#xff0c;使光伏板能够输出更多电能的电气系统能够将太阳能电池板发出的直流电有效地贮存在蓄电池中&#xff0c;可有效地…

Knife4j

knife4j和原来swagger2冲突 版本springboot和knife4j不对 可以了 http://127.0.0.1:8081/doc.html#/documentManager/OfficelineDocument-default

Draw.io绘制UML图教程

一、draw.io介绍 1、draw.io简介 draw.io 是一款强大的免费在线图表绘制工具&#xff0c;支持创建流程图、组织结构图、时序图等多种图表类型。它提供丰富的形状库、强大的文本编辑和样式设置功能&#xff0c;使用户能够轻松创建专业级图表。draw.io 具有用户友好的界面&…