Nginx加权轮询算法

Nginx 加权轮询算法

之前面试被问过如何实现有权重的Map,当时没有做出来。后面听到朋友说Nginx权重分配算法,当时以为是通过权重Map解决的,学习后发现并不是。不能白学,记录一下。

基本概念

nginx可以指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。

例如

upstream backend {
	server a weight = 5;
	server b weight = 3;
	server c weight = 2;
}

按照配置,没有10个请求,5个转发到a,3个转发到b,2个转发到c。

加权轮询与三个变量有关

weight(权重)

约定权重,即在Nginx配置文件中为每个后端服务器指定的权重值。这个值是固定不变的。

effective_weight (有效权重)

初始值等于Weight。在服务器处理请求的过程中,如果Nginx检测到与某个服务器的通信错误,可能会降低其Effective Weight,以减少向该服务器发送请求的频率。当服务器恢复正常后,其Effective Weight会逐渐增加,直到恢复到原始的Weight值

current_weight(当前权重)

初始值为0,用于动态调整服务器的选择过程。Nginx在每次选择服务器时,会根据Current Weight的值来决定哪个服务器应该接收下一个请求

算法逻辑

加权轮询算法如下:

  1. 对于每个请求,遍历集群中的所有可用服务器,对于每个服务器执行 current_weight += effective_weight
  2. 累加所有可用服务的effective_weight,记为total,total += effective_weight
  3. 选中current_weight 最大的服务器,作为本次选定的服务器
  4. 修改本次选中的服务器的current_weight, current_weight -= total

假定服务器没有发生异常,请求10次,过程如下

请求序号请求前current_weight值effective_weighttotal选中节点请求后current_weight值
1{a=0,b=0,c=0}{a=5,b=3,c=2}10a{a=-5,b=3,c=2}
2{a=-5,b=3,c=2}{a=5,b=3,c=2}10b{a=0,b=-4,c=4}
3{a=0,b=-4,c=4}{a=5,b=3,c=2}10c{a=5,b=-1,c=-4}
4{a=5,b=-1,c=-4}{a=5,b=3,c=2}10a{a=0,b=2,c=-2}
5{a=0,b=2,c=-2}{a=5,b=3,c=2}10a{a=-5,b=5,c=0}
6{a=-5,b=5,c=0}{a=5,b=3,c=2}10b{a=0,b=-2,c=2}
7{a=0,b=-2,c=2}{a=5,b=3,c=2}10a{a=-5,b=1,c=4}
8{a=-5,b=1,c=4}{a=5,b=3,c=2}10c{a=0,b=4,c=-4}
9{a=0,b=4,c=-4}{a=5,b=3,c=2}10b{a=5,b=-3,c=-2}
10{a=5,b=-3,c=-2}{a=5,b=3,c=2}10a{a=0,b=0,c=0}

观察到10次调用中,a节点被选中5次,b节点被选中3次,c节点被选中2次,之后current_weight 又恢复到了初始状态0。

算法实现

package main

import "fmt"

type Weighted struct {
	Key             string
	Weight          int
	CurrentWeight   int
	EffectiveWeight int
}

func NewWeighted(key string, weighted int) Weighted {
	return Weighted{
		Key:             key,
		Weight:          weighted,
		CurrentWeight:   0,
		EffectiveWeight: weighted,
	}
}

type WeightedList struct {
	WeightedList []Weighted
}

func NewWeightedList(input map[string]int) WeightedList {
	weightedList := make([]Weighted, 0, len(input))
	for k, v := range input {
		weightedList = append(weightedList, NewWeighted(k, v))
	}
	return WeightedList{
		WeightedList: weightedList,
	}
}

func (w WeightedList) WeightedRoundRobin() string {
	total := 0
	maxWeight := 0
	for i := range w.WeightedList {
		w.WeightedList[i].CurrentWeight += w.WeightedList[i].EffectiveWeight
		total += w.WeightedList[i].EffectiveWeight
		if w.WeightedList[i].CurrentWeight > w.WeightedList[maxWeight].CurrentWeight {
			maxWeight = i
		}
	}
	w.WeightedList[maxWeight].CurrentWeight -= total
	return w.WeightedList[maxWeight].Key
}

func main() {
	w := NewWeightedList(map[string]int{
		"a": 5,
		"b": 3,
		"c": 2,
	})
	for _ = range 10 {
		fmt.Println(w.WeightedRoundRobin())
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值