首页>>后端>>Golang->Golang实践录:使用gin框架实现转发功能:一些负载均衡算法的实现

Golang实践录:使用gin框架实现转发功能:一些负载均衡算法的实现

时间:2023-12-01 本站 点击:0

近段时间需要实现一个转发 post 请求到指定后端服务的小工具,由于一直想学习 gin 框架,所以就使用这个框架进行尝试,预计会产生几篇文章。本文研究一些负载均衡算法的实现。

概述

本文实现的负载均衡纯粹是为了笔者的一个念想,并不具有实际指导意义。

本文假定有一个后端服务 URL 的数组,因此,在实现上,仅是输出数组的索引值。权重数组每个索引值对应一个后端服务。比如"1 3 3",表示有3台服务器,第1台权重为1,第2、3台权重均为3。

算法实现及测试结果

负载均衡有很多类型,如:随机、加权随机;简单轮询、加权轮询、平滑加权轮询,等。本文仅实现几种轮询算法,并且按请求次序递增,不使用随机数。

简单轮询算法

算法描述:

按请求先后轮询服务器。接收到第一次请求,转发到第1台服务器,第二次请求,转发到第2台服务器,依次类推,如果轮询到最后一台服务器,再转发第一台。

代码:

varlb_indexint=0//简单轮询funcgetOneServerUrlForLB_RR(exTimestring)(urlstring){url=""count:=conf.TotalPort//len(conf.BackInfo)iflb_index>=count{lb_index=0}fmt.Println("indx:",lb_index,count)url=fmt.Sprintf("http://127.0.0.1:%d",conf.BackPorts[lb_index])fmt.Println("goturl:",url)lb_index+=1return}

加权轮询算法

一个权重的示意:

3台机器(分别为A、B、C),权重分别为5,3,2。排列(注:按设置的权重先后列出):

53215810|-----|---|--|ABC

某一区间大,表示该服务器的权重大。 设一数,其值在1~10之间,即范围在权重总和之内,依次与5、3、2对比,如小则在该区间,如大,则减去前一数,再比对。看落到哪个区域。 举例: 设该数为3,与5对比,小,则落到第1区间,即选择服务器 A。 设该数为7,与5对比,大,取下一区间,即减去5,得2,与3对比,小,则落到第2区间,即选择服务器 B。 设该数为9,与5对比,大,减去5得4,与3对比,大,减去3得1,与2对比,小,第3区间,即选择服务器 C。

注意,我们关注的是某个区间出现的次数,并不关注是哪一个索引。以轮询 10 次为例,只要保证A、B、C服务器分别访问了5、3、2次即可。最简单的算法,就是将这次 10 次依次分配到A、B、C服务器。

代码:

/*测试用,假定有3组IP,每组分配好权重,根据请求顺序,按权重分配可以认为,IP总数为权重总值,只是部分重复了,所以请求循环的次数就是权重总值*///因为测试,所以直接赋值,测试的总数不超过conf.TotalPort//conf.Weights示例:[3]int{2,5,3},数组索引0表示第1个后端,1表示第2个后端funcgetIndex_WRR(offsetint,totalWeightint)(indexint){//如果不指定,使用随机ifoffset==-1{rand.Seed(time.Now().UnixNano())offset=rand.Int()%totalWeight}//fmt.Println("total:",totalWeight,offset)//注:这里关注的是某个索引值的次数,与顺序无关forindex,w:=rangeconf.Weights{ifoffset<w{returnindex}offset-=w}return}funcgetOneServerUrlForLB_WRR(exTimestring)(urlstring){url=""count:=conf.TotalPorttotalWeight:=0for_,w:=rangeconf.Weights{totalWeight+=w}count=totalWeight//注:按权重总数轮询iflb_index>=count{lb_index=0}new_lb_index:=getIndex_WRR(lb_index,totalWeight)iflb_index==100{fmt.Println("indx:",lb_index,new_lb_index,count)}fmt.Printf("%d",new_lb_index)url=fmt.Sprintf("http://127.0.0.1:%d",conf.BackPorts[new_lb_index])fmt.Println("goturl:",url)lb_index+=1return}

实验结果:

./httpforward.exe-w"532"00000111220000011122./httpforward.exe-w"133"01112220111222./httpforward.exe-w"531"000001112000001112

为了数据可靠,轮询了2遍,下同。

平滑加权轮询算法

上述算法并不考虑服务器处理在效率,比如前面5次均在A服务器,其它服务器均为空闲状态,由此引出平滑加权轮询算法。笔者暂未参透该算法的证明过程,因此本文不涉及。

设置如下变量: 总权重值:totalWeight,其值固定。 固定权重数组:Weights,其值固定。 当前权重数组 CurrentWeights,其值可变。 当前权重数组最大值 maxWeight,CurrentWeights数组的最大值。

算法步骤: 0、某次请求到来。 1、判断当前权重数组(对应下表当前权重1)值是否全为0,如是,则用固定权重初始化之。 2、查获当前权重数组,获取最大值,对应的索引,即为需要返回的服务器。 3、将第2步的索引对应的值,减去权重总和,其它索引的值保持不变。(对应下表当前权重2) 4、 将第3步得到的当前权重数组的每个值,加上对应的固定权重值。 5、回到第1步,重复。

假定有3台服务器A、B、C,其权重依次为 5、1、1,权重总和为7。演算过程如下:

初始时,当前权重为[0,0,0],则用固定权重[5,1,1]初始化之。 此时,最大值为5,索引为0,返回服务器A。 将[5,1,1]的索引0值减去权重总和7,得到[-2,1,1]。 将[-2,1,1]加上[5,1,1],得到新的当前权重[3,2,2]。 此时,最大值为3,索引为0,返回服务器A。 将[3,2,2]的索引0值减去权重总和7,得到[-4,2,2]。 将[-4,2,2]加上[5,1,1],得到新的当前权重[1,3,3]。 (下略)

总体过程如下表:

请求次数当前权重1返回服务器当前权重20[0, 0,0]--初始化为[5, 1, 1]1[5, 1, 1]A[-2, 1, 1]2[3, 2, 2]A[-4, 2, 2]3[1, 3, 3]B[1, -4, 3]4[6, -3, 4]A[-1, -3, 4]5[4, -2, 5]C[4, -2, -2]6[9, -1, -1]A[2, -1, -1]7[7, 0, 0]A[0, 0, 0]8[5, 1, 1]A[-2, 1, 1]

代码:

//平滑加权funcgetIndex_SWRR(offsetint,totalWeightint)(indexint){initflag:=0//0.判断是否全为0for_,w:=rangeconf.CurrentWeights{ifw==0{initflag++}}//全为0,则需要初始化ifinitflag==len(conf.CurrentWeights){foridx,w:=rangeconf.Weights{conf.CurrentWeights[idx]=w}}//1.查询当前权重表最大者,并取该索引,即为所需结果maxWeight:=0foridx,w:=rangeconf.CurrentWeights{ifw>maxWeight{maxWeight=windex=idx}}//2.最大的那个权重,其值减去总权重conf.CurrentWeights[index]=maxWeight-totalWeight//fmt.Println("current222:",conf.CurrentWeights)//3.新的当前权重,所对应的值加上初始权重//为下次循环计算打下基础foridx,w:=rangeconf.Weights{conf.CurrentWeights[idx]+=w}return}funcgetOneServerUrlForLB_SWRR(exTimestring)(urlstring){url=""totalWeight:=0for_,w:=rangeconf.Weights{totalWeight+=w}//注:按权重总数轮询iflb_index>=totalWeight{lb_index=0}new_lb_index:=getIndex_SWRR(lb_index,totalWeight)iflb_index==100{fmt.Println("indx1:",lb_index,new_lb_index,totalWeight)}fmt.Printf("%d",new_lb_index)url=fmt.Sprintf("http://127.0.0.1:%d",conf.BackPorts[new_lb_index])//fmt.Println("goturl:",url)lb_index+=1return}

实验结果:

./httpforward.exe-w"511"00102000010200./httpforward.exe-w"133"12012121201212./httpforward.exe-w"531"010201010010201010./httpforward.exe-w"253"12011210211201121021

从结果上看,权重保持着比例,但响应的服务器分布较平衡,即不会出现权重大的服务器集中处理请求的情况。某次测试 nginx 的负载均衡,似乎默认便是此种方法,但算法实现不同,测试发现,在保持权重比例情况下,不同的服务器出现的顺序不同,未深究原因。

小结

本文主要根据网络的相关资料整理并用 golang 代码实现负载均衡部分算法。

参考

https://www.cnblogs.com/wsw-seu/p/11336634.html https://juejin.cn/post/6844903793012768781


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