平衡分配算法

时间:2008-09-26 13:44:38

标签: algorithm big-o load-balancing cluster-computing

我正在为一个松散耦合的集群开发一些代码。为了在作业期间实现最佳性能,每次孩子进入或退出时,我都会重新映射其数据。这最终将成为可选的,但是现在它默认执行数据平衡。我的平衡基本上只是确保每个孩子的每台机器的平均文件数量不超过一个。如果除法不干净,则加上余数。并且由于余下的总是小于子女的数量[除了0个案例,但我们可以排除],平衡后的孩子最多只有平均值+ 1。

一切似乎都很好,直到我意识到我的算法是O(n!)。沿着孩子的名单,找出平均值,余数,谁太多,谁太少。对于列表太多的每个孩子,请查看列表,发送给每个孩子太少。

有更好的解决方案吗?我觉得必须有。

编辑:这是一些伪造的代码来展示我如何派生O(n!):

foreach ( child in children ) {
    if ( child.dataLoad > avg + 1 ) {
        foreach ( child2 in children ) {
            if ( child != child2 && child2.dataLoad < avg ) {
                sendLoad(child, child2)
            }
        }
    }
}

编辑:O(n ^ 2)。 Foreach n,n =&gt; n * n =&gt; N ^ 2。我想我今天早上没有足够的咖啡! ;)

将来我想转向一种更灵活,更有弹性的分配方法[权重和数据],但是现在,统一的数据分布工作。

4 个答案:

答案 0 :(得分:4)

@zvrba:你甚至不必对列表进行排序。第二次遍历列表时,只需将平均工作量较少的所有项目移动到列表末尾(您可以在第一次遍历时保留指向最后一项的指针)。顺序不一定是完美的,它只是在最后一步必须增加或减少迭代器时才会改变。

See previous answer

最后一步看起来像是:

在第二步中,保留指向child2中工作负荷低于第一项的指针(以防止必须有双链接列表)。

for each child in list {
  if child2 == nil then assert("Error in logic");
  while child.workload > avg + 1 {
    sendwork(child, child2, min(avg + 1 - child2.workload, child.workload - (avg + 1)))
    if child2.workload == avg + 1 then child2 = child2.next;
  }
}

答案 1 :(得分:2)

我认为您的分析不正确:

  • 浏览列表以找出平均值为O(n)
  • 制作包含太多或太少数据块的子列表也是O(n)
  • 移动数据与数据量成正比

你是怎么到达O(n!)的?

你可以对儿童数量中的[O(n lg n)]进行排序,这样你就可以在前面让孩子做太多工作,最后孩子的工作量太少。然后同时遍历两端的列表:一个迭代器指向具有过多数据的子节点,另一个迭代器指向缺少数据的子节点。传输数据,向前移动一个迭代器,或向后移动另一个。

答案 2 :(得分:2)

您可能希望尝试完全不同的方法,例如一致性哈希。

请参阅此处以获得相对简单的主题介绍: http://www8.org/w8-papers/2a-webserver/caching/paper2.html

(还有更深入的论文,从Karger等开始)

我在Erlang中创建了一致的哈希工作实现,您可以根据需要进行检查:

http://distributerl.googlecode.com/svn/trunk/chash.erl

答案 3 :(得分:1)

您发布的代码具有复杂度O(n ^ 2)。尽管如此,有可能在malach观察到的线性时间内完成,其中n是子列表中的项目数。

考虑:内部循环有n次迭代,并且最多执行 n次。 n * n = n ^ 2.