并行处理应用程序中的负载平衡

时间:2011-08-26 15:17:34

标签: c# network-programming parallel-processing load-balancing opencl

我正在构建一个网络分布式并行处理应用程序,它在许多机器上使用CPU和GPU资源的组合。

应用程序必须在数千次迭代中对非常大的数据集执行一些计算成本非常高的操作:

for step = 0 to requested_iterations
  for i = 0 to width
    for j = 0 to height
      for k = 0 to depth
        matrix[i,j,k] = G*f(matrix[i,j,k])

此外,矩阵运算必须同步执行:也就是说,每次迭代都取决于紧接在它之前的帧的结果。

此ad-hoc网格中可用的硬件(包括专用服务器和空闲桌面计算机)在不同机器之间的性能差异很大。我想知道在整个系统中平衡工作量的最佳方法是什么。

一些特质:

  1. 网格应尽可能健壮。有些模拟需要数周才能运行,如果100台机器中有一台机器脱机,最好不要取消运行。

  2. 某些低端计算机(闲置但必须在有人登录时唤醒的桌面)可以随时加入和离开网格。

  3. 专用服务器也可以加入和离开网格,但这是可以预测的。

  4. 到目前为止,我能够提出的最好的想法是:

    1. 让每个节点跟踪处理矩阵中的一组 n 单元格所需的时间(每单位时间处理的单元格)并将其报告给中央存储库。
    2. 此时间对模拟的一个帧(整个网格)的总时间和问题域的总大小进行加权。因此,每个节点将获得以每个工作单位(矩阵单元格)表示的分数,以及表示其与网格其余部分的性能的标量等级。
    3. 在每个框架上,根据这些分数分配工作负荷,以便每台机器尽可能接近同一时间完成。如果机器A比机器B快100倍,它将在给定帧中接收100倍的矩阵单元(假设矩阵大小足以保证包括额外的机器)。
    4. 离开网格的节点(登录的桌面等)将在其余节点之间重新分配工作负载。
    5. 以树结构排列节点,其中每个节点都分配了“权重”。树中较高的节点具有基于其能力与其子女的能力相结合的权重。每帧调整此重量。当节点失去与其子节点的通信时,它使用缓存的树图来联系孤立的子节点并重新平衡其分支。

      如果它有所不同,该应用程序是C#和OpenCL的组合。

      欢迎链接到论文,示例应用程序,尤其是教程。

      修改

      这不是作业。我正在把我作为论文一部分写的模拟器变成一个更有用的产品。现在,工作统一分配,不考虑每台机器的性能,也没有设备从加入或离开电网的机器中恢复。

      感谢提供优质,详尽的回复。

3 个答案:

答案 0 :(得分:2)

对于异构集群,我喜欢让每个处理器在处理器可用时请求新作业。实现涉及一个轻量级服务器,可以一次处理多个请求(但通常只返回一个作业号)。实施可能会是这样的:

  • 将工作分解为最小的组件(我们知道现在有1000个任务)
  • 启动一个网络服务器(最好是带有超时的UDP以避免网络拥塞)向上计数
  • 启动群集流程。
  • 每个流程都会问:“我应该执行哪个工作号码?”并且服务器回复数字
  • 当流程结束时,它会询问下一个工作号码。当所有任务完成后,服务器会向进程返回-1,因此它们会关闭。

这是一种比上面建议的更轻的替代品。您的快速处理器仍然比较慢的处理器做更多的工作,但您不必计算任务所需的时间。如果处理器因任何原因退出,它将停止要求任务。您的服务器可以选择在一段时间后回收任务编号。

这几乎就是集群调度程序自己做的事情,除了处理器没有启动和关闭成本,因此您的个人任务可以更小而不会受到惩罚。

答案 1 :(得分:1)

我会选择分散的解决方案。

每个节点从中心选择(未给定)相同数量的工作。在一些运行之后,每个节点都能够计算itself平均计算能力并与其他人进行通信。

毕竟每个节点都有一个表,其中包含每个节点的平均计算能力。 拥有这些信息(可能是持久的,为什么不呢?)每个节点都可以通过签订合同来“请求”其他节点更有权力将一些东西委托给它。

在每个进程开始之前,每个节点都必须发出关于“我开始做X”的广播信号。有一次总是播出:“我完成了X”。

嗯,这不是那么容易,因为当你开始工作时会出现这种情况,在你的硬盘发生故障后你永远无法完成它。其他人,特别是那些等待你的结果的人应该弄清楚这一点并从篮子中挑选你的工作并从头开始。这里有“ping”技术与计时器。

糟糕:第一次调整时间可能会花费非无关紧要的时间。

好:您将拥有几乎容错解决方案。将它们保留一个星期,即使某些节点发生故障,您的网格仍然存活并完成其工作。

很多年前,我做过类似的事情并取得了不错的成绩。但它并没有像您所描述的那样大规模。实际上,规模也有所不同。

所以选择取决于你。

希望这有帮助。

答案 2 :(得分:1)

我不打算在服务器级别过多地跟踪这些统计信息。你将引入相当多的开销。

相反,控制服务器应该只维护一个工作单元列表。当客户端变得可用时,让它抓住下一个单元并进行处理。冲洗,重复。

一旦给定矩阵的工作单位列表用完,就允许重新分配当前不完整的工作单位。

基于包含10个工作单元和5个服务器的矩阵的示例。

同样快,全部可用:

服务器1检入并抓取单元1.接下来的4台机器(即:服务器2获取单元2 ...) 当单元1完成后,服务器1然后抓住单元6.其他人抓住其余部分。一旦最后一台服务器签入,矩阵就完成了。

低差异表现,全部可用:
您再次启动循环,服务器将获取前5个单元。但是,服务器1比其他服务器长30%。这意味着服务器2将抓住单元6.等等。在某些时刻,服务器1将检查单元1,同时单元2到5将完成,并且将分配6到10。服务器1被分配了单元6,因为它还没有完成。但是,服务器2将在服务器1完成之前检入它已完成的工作。没什么大不了的,只是扔掉最后的结果。

巨大的不同表现,全部可用
您再次启动循环,服务器将获取前5个单元。假设服务器1比其他服务器节省400%的时间。这意味着服务器2将获取单元6等。在服务器2检查单元6之后,它将看到单元#1仍在进行中。继续并将其分配给服务器2;这将在服务器1返回之前完成。

在这种情况下,您应该监控那些一直报告工作的机器并将其从进一步的考虑中删除。当然,由于关机或个人使用,您必须为那些离线的人做一些补贴。可能是某种类型的加权评级,一旦它低于某个阈值,你就会拒绝进一步的工作;或许,评级会经常重置,以便从它将会遇到的稳定状态重新平衡。

机器消失
这与上面列出的“巨大的不同表现”具有完全相同的计划。唯一的区别是机器将永远不会报告,或者会在一段未知的时间后报告。

如果由于某种原因你有更多的机器而不是单位,那么会发生一件有趣的事情:多个服务器将被立即分配到同一个工作单元。您可以通过设置某种类型的延迟来停止此操作(例如,在允许重新分配之前,单元必须处于x分钟的过程中)或者只是允许它发生。应该考虑这一点。


我们做了什么?首先,我们减轻了追踪个人表现的需要。其次,我们已经允许机器消失,同时确保工作仍然完成。第三,我们确保尽可能在最短的时间内完成工作。

比根据性能简单地将多个单元块分配给机器更加繁琐;但是,这使得即使是快速的机器也可以从网络中拔出,同时确保完全可恢复性。哎呀你可以杀掉所有的机器,然后打开其中的一些机器来接你离开的地方。