Algorithm 平衡分布算法

Algorithm 平衡分布算法,algorithm,big-o,load-balancing,cluster-computing,Algorithm,Big O,Load Balancing,Cluster Computing,我正在为松散耦合集群编写一些代码。为了在作业期间获得最佳性能,我让集群在每次子节点进入或退出时重新映射其数据。这最终将成为可选的,但目前它默认执行数据平衡。我的平衡基本上就是确保每个孩子的文件数不超过每台机器的平均数,再加上一个。如果除法不干净,则加1表示剩余部分。由于余数总是小于子项的数量[除了0,但我们可以排除它],平衡后的子项最多有平均值+1 一切似乎都很好,直到我意识到我的算法是O(n!)。沿着孩子们的名单,找出平均数,剩余数,谁的孩子太多,谁的孩子太少。对于“太多”列表中的每个孩子,浏

我正在为松散耦合集群编写一些代码。为了在作业期间获得最佳性能,我让集群在每次子节点进入或退出时重新映射其数据。这最终将成为可选的,但目前它默认执行数据平衡。我的平衡基本上就是确保每个孩子的文件数不超过每台机器的平均数,再加上一个。如果除法不干净,则加1表示剩余部分。由于余数总是小于子项的数量[除了0,但我们可以排除它],平衡后的子项最多有平均值+1

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

有更好的解决办法吗?我觉得一定有

编辑:下面是一些伪代码,显示我是如何导出O(n!):

foreach(子对象中的子对象){
如果(child.dataLoad>avg+1){
foreach(儿童中的儿童2){
if(child!=child2&&child2.dataLoad
编辑:O(n^2)。Foreach n,n=>n*n=>n^2。我想我今天早上喝的咖啡不够


未来,我希望采用更灵活、更具弹性的分配方法[权重和统计量],但目前,数据的统一分配是可行的。

我认为您的分析是错误的:

  • 浏览列表,找出平均值为O(n)
  • 列出数据块过多或过少的子级也是O(n)
  • 移动数据与数据量成正比
你是怎么到达O(n!)的


您可以对列表进行排序[O(n lg n)中的子项数量],这样前面的子项工作太多,最后的子项工作太少。然后同时从两端遍历列表:一个迭代器指向数据过多的子对象,另一个指向数据不足的子对象。传输数据,并向前或向后移动一个迭代器。

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

最后一步看起来像:

在第二步中,在child2中保留一个指向第一项的指针,该项的工作负载低于平均工作负载(以防止需要一个双链接列表)


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


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

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

请参见此处,以获得对该主题的相对简单的介绍:

(还有更深入的论文可供查阅,从Karger等人开始)

我已经在Erlang中创建了一个一致性哈希的工作实现,如果您愿意,可以对其进行检查:


foreach(child中的child)if(child.dataLoad>avg+1)foreach(child2中的child2)if(child!=child2&&child2.dataLoadforeach ( child in children ) { if ( child.dataLoad > avg + 1 ) { foreach ( child2 in children ) { if ( child != child2 && child2.dataLoad < avg ) { sendLoad(child, 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;
  }
}