首页 > 编程语言 >平滑的加权轮询均衡算法

平滑的加权轮询均衡算法

时间:2022-09-18 18:12:33浏览次数:103  
标签:Node 权重 轮询 节点 Nginx 算法 平滑

前言

在反向代理、路由、分布式应用调度等场景中通常都需要用到负载均衡算法,负载均衡的关键要点是“均衡”,即确保调用请求能均衡的落到多个处理节点上,负载均衡算法一般使用随机或轮询都可以保证均衡性。

现实中由于服务器性能或资源分配的差异,导致我们需要为服务节点设置不同的权重,权重高的节点得到更多流量,同时降低低权重节点的流量比例。也即带权重的均衡算法。

下面我们讨论几种常见的负载均衡算法,并针对其中一种给出完整的算法讲解及实现。

一、随机

这是最简单的负载均衡算法,每次生成一个随机数,然后对服务节点数进行取模,模值即为服务节点序号,很明显这只能做到“均匀”,无法根据各服务节点的权重进行加权分配。不过略加调整即可实现加权分配:
构造一个范围为总权重值的序列,然后用随机数对总权重取模,模值所在区间即为对应的服务节点。譬如:有三个服务节点,其权重分别为:503020,则节点集图像大致如下:

|<-----------A----------->|<-----B----->|<---C--->|
|<0--------------------50>|<51-------80>|<81--100>|

代码简示:

struct Node<TKey> where TKey : IEquatable<TKey>
{
	public Node(TKey key, int boundary) {
		this.Key = key;
		this.Boundary = boundary;
	}

	public TKey Key;
	public int Boundary;
}

class NodeSelector
{
	int _total;
	Node<string> _nodes;

	void Initialize() {
		_total = 50 + 30 + 20;
		_nodes = new[] {
			new Node<string>("Node-A", 50),
			new Node<string>("Node-B", 50 + 30),
			new Node<string>("Node-C", 50 + 30 + 20),
		};
	}

	string Select() {
		var value = Randomizer.GenerateInt32() % _total;

		for(int i = 0; i < _nodes.Length; i++) {
			if(value <= _nodes[i].Boundary)
				return _nodes[i].Key;
		}

		return null;
	}
}

随机算法的表现恰如其名,在一个甚至多个调度周期内也无法确保各节点的权重匹配度,只能在大样本条件下满足权重的概率分布,总之就两字:随缘。

二、一致哈希

关于一致性哈希算法的文章已经汗牛充栋,亦不是本文的重点,所以就不再赘述。在构建哈希环的时候需要依据服务节点的权重比来设置相应数量的虚拟节点,之后确定服务节点的算法与上述随机算法基本差不多。

三、平滑加权轮询

终于来到本文的重点部分,我们假设有三个服务节点,其权重分别为:421,那么在一个调度周期内,最简单调度序列如:{A,A,A,A,B,B,C}{C,B,B,A,A,A,A}{B,B,C,A,A,A,A},但直觉这样的调度顺序不友好,因为它会在某一阵把压力都落到同一个节点上,导致某个节点突然很忙的情况,类似汽车换挡的那种顿挫感。

如果调度序列变成:{A,B,A,C,A,B,A}{A,A,B,A,C,A,B} 这样就显得“平滑”和“均衡”多了,我们主要参考 Nginx 和 LVS 采用的两种算法。

Nginx 算法

算法详解

  • 当前节点集初始值均为零:{0,0,0}
  • 所有节点的当前权重值加上设定的权重值
  • 在当前节点集中选取最大权重值的节点作为命中节点
  • 命中节点的当前权重值减去总权重值作为其新权重值,其他节点保持不变

ABC 三个节点的权重分别为:421,演算步骤如下:

步骤 选择前当前值 选择节点(命中) 选择后当前值
1 { 4, 2, 1} A {-3, 2, 1}
2 { 1, 4, 2} B { 1,-3, 2}
3 { 5,-1, 3} A {-2,-1, 3}
4 { 2, 1, 4} C { 2, 1,-3}
5 { 6, 3,-2} A {-1, 3,-2}
6 { 3, 5,-1} B { 3,-2,-1}
7 { 7, 0, 0} A { 0, 0, 0}

由上发现三个节点的命中次数符合 4:2:1,而且权重大的节点不会霸占选择权。经过一个周期(7轮选择)后,当前权重值又回到了{0, 0, 0},以上过程将按照周期进行循环,完全符合我们先前期望的平滑性。

数学证明

该算法的合理性和平滑性的数学证明:https://tenfy.cn/2018/11/12/smooth-weighted-round-robin

LVS 算法

Linux Virtual Server 采用的是另外一种,算法wiki文档:http://kb.linuxvirtualserver.org/wiki/Weighted_Round-Robin_Scheduling

从算法步骤和计算量上看,相对 Nginx 而言 LVS 算法略微简单一些,性能可能会略好一点点(但都是同一个量级);通过模拟数据发现当节点权重差异较大时,其平滑性没有 Nginx 算法好。

总结

Zongsoft.Data 数据访问框架的读写分离中需要将读写操作路由到不同权重的数据库,于是采用 Nginx 的平滑权重轮询均衡算法实现了数据源路由选择器,下面分别是平滑权重轮询器和数据路由的代码:


参考资料:


注意:本文可能会更新,请阅读原文:https://zongsoft.com/blog/zh-cn/zongsoft/smooth-weighted-round-robin-balancing,以避免因内容陈旧而导致的谬误,同时亦有更好的阅读体验。

标签:Node,权重,轮询,节点,Nginx,算法,平滑
From: https://www.cnblogs.com/Zongsoft/p/smooth-weighted-round-robin-balancing.html

相关文章

  • 算法性能分析
    算法的性能分析概括成时间复杂度和空间复杂度两部分;1.时间复杂度通常指算法运行的时间(大O记法只保留最高次项,忽略低次项和常数项)2.空间复杂度......
  • KMP算法的底层理解
    KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。KMP的精髓所在就是前缀表。(下面用next[]数组来表......
  • 通关基本算法 day_03 -- 二分算法
    整数二分本质如果有单调性的话-->我可以二分,反之不然整个区间可以一分为二,我们定义了一个性质,右半边是满足这个性质的,但是左半边不满足二分可以寻找这个性质的边界......
  • AcWing 算法提高课 强连通分量
    1、Tarjan算法求强连通分量: 强连通分量的点可能会向上联通。  维护两个时间戳。 ......
  • G1GC的算法与实现 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1GO-QAbmrsxH3Qvns1JATyA点击这里获取提取码 ......
  • 算法竞赛进阶指南 0x22 深度优先搜索
    AcWing165.小猫爬山翰翰和达达饲养了N只小猫,这天,小猫们要去爬山。经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。翰翰和达达只好......
  • 算法中的最优化方法01
    算法中的最优化方法0100课程简介优化尽可能用最佳的方式处理一下事项计算机中基于优化的算法多准则控制器的设计模糊建模中的聚类机器人轨迹规划流程工业中的调度......
  • aardio调用百度云人脸识别(api认证机制authorization算法)
    功能:调用百度云识别里的人脸识别api 这里同时分享给需要的人:namespacebaiduimportinet.urlimporttime.zoneimportcrypt.hmacimportcrypt.binstring=........
  • 道长的算法笔记:动态规划经典模型
    (一)背包模型Waiting...(二)数字三角形模型Waiting...(三)线性规划模型Waiting...(四)区间规划模型Waiting...(五)状态压缩动规模型Waiting.........
  • 为 Transformer 实现形式化算法,第 1 部分:注意力
    为Transformer实现形式化算法,第1部分:注意力边做边学的机器学习。使用DeepMind的伪代码从头开始编写多头注意力的教学实现2017年的论文中介绍了transformer架构注......