nginx平滑的基于权重轮询算法分析

栏目: 服务器 · Nginx · 发布时间: 6年前

内容简介:轮询调度非常简单,就是每次选择下一个节点进行调度。比如这样的算法有一个问题,在负载均衡中,每台机器的性能是不一样的,对于16核的机器跟4核的机器, 使用一样的调度次数,这样对于16核的机器的负载就会很低。这时,就引出了基于权重的轮询算法。基于权重的轮询调度是在基本的轮询调度上,给每个节点加上权重,这样对于权重大的节点, 其被调度的次数会更多。比如a, b, c三台机器的负载能力分别是4:2:1,则可以给它们分配的权限为4, 2, 1。 这样轮询完一次后,a被调用4次,b被调用2次,c被调用1次。

轮询调度非常简单,就是每次选择下一个节点进行调度。比如 {a, b, c} 三个节点,第一次选择a, 第二次选择b,第三次选择c,接下来又从头开始。

这样的算法有一个问题,在负载均衡中,每台机器的性能是不一样的,对于16核的机器跟4核的机器, 使用一样的调度次数,这样对于16核的机器的负载就会很低。这时,就引出了基于权重的轮询算法。

基于权重的轮询调度是在基本的轮询调度上,给每个节点加上权重,这样对于权重大的节点, 其被调度的次数会更多。比如a, b, c三台机器的负载能力分别是4:2:1,则可以给它们分配的权限为4, 2, 1。 这样轮询完一次后,a被调用4次,b被调用2次,c被调用1次。

对于普通的基于权重的轮询算法,可能会产生以下的调度顺序 {a, a, a, a, b, b, c}

这样的调度顺序其实并不友好,它会一下子把大压力压到同一台机器上,这样会产生一个机器一下子很忙的情况。 于是乎,就有了平滑的基于权重的轮询算法。

所谓平滑就是调度不会集中压在同一台权重比较高的机器上。这样对所有机器都更加公平。 比如,对于 {a:5, b:1, c:1} ,产生 {a, a, b, a, c, a, a} 的调度序列就比 {c, b, a, a, a, a, a} 更加平滑。

nginx平滑的基于权重轮询算法

nginx平滑的基于权重轮询算法其实很简单。 算法原文 描述为:

Algorithm is as follows: on each peer selection we increase current_weight of each eligible peer by its weight, select peer with greatest current_weight and reduce its current_weight by total number of weight points distributed among peers.

算法执行2步,选择出1个当前节点。

  1. 每个节点,用它们的当前值加上它们自己的权重。
  2. 选择当前值最大的节点为选中节点,并把它的当前值减去所有节点的权重总和。

例如 {a:5, b:1, c:1} 三个节点。一开始我们初始化三个节点的当前值为 {0, 0, 0} 。 选择过程如下表:

轮数 选择前的当前权重 选择节点 选择后的当前权重
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}

我们可以发现,a, b, c选择的次数符合5:1:1,而且权重大的不会被连接选择。7轮选择后, 当前值又回到{0, 0, 0},以上操作可以一直循环,一样符合平滑和基于权重。

一个 go 版本实现

type Node struct {
    Name    string
    Current int
    Weight  int
}

func SmoothWrr(nodes []*Node)(best *Node) {
    if len(nodes) == 0 {
        return
    }
    total := 0
    for _, node := range nodes {
        if node == nil {
            continue
        }
        total += node.Weight
        node.Current += node.Weight
        if best == nil || node.Current > best.Current {
            best = node
        }
    }
    if best == nil {
        return
    }
    best.Current -= total
    return
}

func example() {
    nodes := []*Node{
        &Node{"a", 0, 5},
        &Node{"b", 0, 1},
        &Node{"c", 0, 1},
    }

    for i := 0; i < 7; i++ {
        best := SmoothWrr(nodes)
        if best != nil {
            fmt.Println(best.Name)
        }
    }
}

证明权重合理性

以下证明主要由 安大神 证明得出

假如有n个结点,记第i个结点的权重是x i

设总权重为S=x 1 + x 2 + … + x n

选择分两步

  1. 为每个节点加上它的权重值
  2. 选择最大的节点减去总的权重值

n个节点的初始化值为[0, 0, …, 0],数组长度为n,值都为0。

第一轮选择的第1步执行后,数组的值为[x 1 , x 2 , …, x n ]。

假设第1步后,最大的节点为j,则第j个节点减去S。

所以第2步的数组为[x 1 , x 2 , …, x j -S, …, x n ]。 执行完第2步后,数组的和为

x 1 + x 2 + … + x j -S + … + x n =>

x 1 + x 2 + … + x n - S = S - S = 0。

由此可见,每轮选择,第1步操作都是数组的总和加上S,第2步总和再减去S,所以每轮选择完后的数组总和都为0.

假设总共执行S轮选择,记第i个结点选择m i 次。第i个结点的当前权重为w i 。 假设节点j在第t轮(t < S)之前,已经被选择了x j 次,记此时第j个结点的当前权重为w j =t*x j -x j *S=(t-S)*x j <0, 因为t恒小于S,所以w j <0。

前面假设总共执行S轮选择,则剩下S-t轮,上面的公式w j =(t-S)*x j +(S-t)*x=0。 所以在剩下的选择中,w j 永远小于等于0,由于上面已经证明任何一轮选择后, 数组总和都为0,则必定存在一个节点k使得w k >0,永远不会再选中x j

由此可以得出,第i个结点最多被选中x i 次,即m i <=x i

因为S=m 1 +m 2 +…+m n 且S=x 1 + x 2 + … + x n 。 所以,可以得出m i ==x i

证明平滑性

证明平滑性,只要证明不要一直都是连续选择那一个节点即可。

跟上面一样,假设总权重为S,假如某个节点x i 连续选择了t(t<x i )次,只要存在下一次选择的不是x i ,即可证明是平滑的。

假设t=x i -1,此是第i个结点的当前权重为w i =t*x i -t*S=(x i -1)*x i -(x i -1)*S。

证明下一轮的第1步执行完的值w i +x i 不是最大的即可。

w i +x i =>

(x i -1)*x i -(x i -1)*S+x i =>

x i 2 -x i *S+S=>

(x i -1)*(x i -S)+x i

因为x i 恒小于S,所以x i -S<=-1。 所以上面:

(x i -1)*(x i -S)+x i <= (x i -1)*-1+x i = -x i +1+x i =1。

所以,第t轮后,再执行完第1步的值w i +x i <=1。

如果这t轮刚好是最开始的t轮,则必定存在另一个结点j的值为x j *t,所以有w i +x i <=1<1*t<x j *t。

所以下一轮肯定不会选中x。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

程序员的修炼

程序员的修炼

Jeff Atwood / 陆其明、杨溢 / 人民邮电出版社 / 2014-4 / 45.00元

《程序员的修炼——从优秀到卓越》是《高效能程序员的修炼》的姊妹篇,包含了Coding Horror博客中的精华文章。全书分为8章,涵盖了时间管理、编程方法、Web设计、测试、用户需求、互联网、游戏编程以及技术阅读等方面的话题。作者选取的话题,无一不是程序员职业生涯中的痛点。很多文章在博客和网络上的点击率和回帖率居高不下。 Jeff Atwood于2004年创办Coding Horror博客(......一起来看看 《程序员的修炼》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具