Nginx轮询算法

以下代码均用go实现

普通轮询算法

func main() {
	r := new(RoundRobinBalance)
	r.Add("127.0.0.1:80")
	r.Add("127.0.0.1:81")
	r.Add("127.0.0.1:82")
	fmt.Println(r.Next())
	fmt.Println(r.Next())
	fmt.Println(r.Next())
	fmt.Println(r.Next())
	fmt.Println(r.Next())
}

type RoundRobinBalance struct {
	curIndex int
	rss []string
}

func (r *RoundRobinBalance) Add(params ...string) error {
	if len(params) == 0 {
		return errors.New("params len 1 at least")
	}
	addr := params[0]
	r.rss = append(r.rss, addr)
	return nil
}

func (r *RoundRobinBalance) Next() string {
	rLen := len(r.rss)
	if rLen == 0 {
		return ""
	}
	if r.curIndex >= rLen {
		r.curIndex = 0
	}
	cur := r.rss[r.curIndex]
	r.curIndex = (r.curIndex + 1) % rLen
	return cur
}

加权轮询算法

在 Nginx加权轮询算法 中,每个节点都有3个权重的变量

Weight : 配置的权重,根据配置文件初始化每个服务器节点的权重
currentWeight : 节点的当前权重,初始化时是配置的权重,随后会一直变更
effectiveWeight : 有效的权重,初始值为 weight ,通讯过程中发现节点异常,则 -1 ,之后再次选择本节点,调用成功一次则 +1 ,直到恢复到 weight。这个参数可以用于做降权。或者说是你的设置的权限修正。

Nginx加权轮询算法 的逻辑实现

轮询所有节点,计算当前状态下所有的节点的 effectiveWeight 之和 作为 totalWeight;
更新每个节点的 currentWeight , currentWeight = currentWeight + effectiveWeight;选出所有节点 currentWeight 中最大的一个节点作为选中节点;
选择中的节点再次更新 currentWeight, currentWeight = currentWeight - totalWeight;

注意:实现中不考虑健康检查,即所有的节点都是100%可用的,所以 effectiveWeight 等于 weight

func main() {
	rb := new(WeightRoundRobinBalance)
	rb.Add("127.0.0.1:80", "4")
	rb.Add("127.0.0.1:81", "2")
	rb.Add("127.0.0.1:82", "1")

	fmt.Println(rb.Next())
	fmt.Println(rb.Next())
	fmt.Println(rb.Next())
	fmt.Println(rb.Next())
	fmt.Println(rb.Next())
	fmt.Println(rb.Next())
	fmt.Println(rb.Next())
}

type WeightRoundRobinBalance struct {
	curIndex int
	rss      []*WeightNode
}

type WeightNode struct {
	weight          int
	currentWeight   int
	effectiveWeight int
	addr            string
}

func (w *WeightRoundRobinBalance) Add(params ...string) error {
	if len(params) != 2 {
		return errors.New("params len need 2")
	}
	addr := params[0]
	parInt, err := strconv.ParseInt(params[1], 10, 64)
	if err != nil {
		return err
	}
	node := &WeightNode{
		weight:          int(parInt),
		currentWeight:   int(parInt),
		effectiveWeight: int(parInt),
		addr:            addr,
	}
	w.rss = append(w.rss, node)
	return nil
}

func (w *WeightRoundRobinBalance) Next() string {
	if len(w.rss) == 0 {
		return ""
	}
	totalWeight := 0
	var maxWeightNode *WeightNode
	for key, node := range w.rss {
		totalWeight += node.effectiveWeight
		node.currentWeight += node.effectiveWeight
		if maxWeightNode == nil ||  maxWeightNode.currentWeight < node.currentWeight {
			maxWeightNode = node
			w.curIndex = key
		}
	}
	maxWeightNode.currentWeight -= totalWeight
	return maxWeightNode.addr
}

数学真的太漂亮了吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值