try ai
科普
编辑
分享
反馈
  • 并行计算中的负载控制

并行计算中的负载控制

SciencePedia玻尔百科
关键要点
  • 并行计算系统的性能受其最慢处理器限制,这一原则被称为完工时间 (makespan)。
  • 负载控制策略分为静态(为可预测的工作负载预先规划)和动态(为气候或星系模拟等变化的工作负载进行自适应调整)两种。
  • 动态再均衡是一种权衡,仅在未来的性能增益超过迁移数据的直接成本时才执行。
  • 实现模型包括可能成为瓶颈的集中式任务队列,以及更具可扩展性和鲁棒性的去中心化工作窃取模型。
  • 算法的选择以及对科学可复现性的需求,都深受负载均衡所带来的约束和机遇的影响。

引言

在追求计算能力的过程中,我们已经从单处理器时代迈向了拥有成千上万甚至数百万个核心协同工作的大规模超级计算机时代。这种并行方法有望带来前所未有的速度,但它也内含一个根本性的弱点:整个系统的速度取决于其最慢的部分。如果工作分配不均,昂贵的处理器就会闲置,等待其不堪重负的同伴赶上进度。这种低效率正是​​负载控制​​(或称负载均衡)旨在解决的核心问题。它是一门让每个处理器都保持高效工作,以最大化整个系统性能的艺术和科学。

本文深入探讨负载控制这一关键学科,阐明其理论基础和实践重要性。第一部分​​原理与机制​​将解析并行性能的核心挑战,即完工时间 (makespan)。我们将探讨分配工作的主要策略,从用于可预测问题的静态均衡,到用于不断变化的科学模拟的自适应动态均衡。我们还将剖析在决定何时以及如何对系统进行再均衡时所涉及的关键权衡。随后,​​应用与跨学科联系​​部分将展示负载控制的实际应用。我们将看到这些原理不仅局限于超级计算机,对于Web服务器、数据存储也至关重要,甚至影响算法的选择,对从计算生物学到天体物理学等领域产生深远影响。我们的探索始于理解支配所有并行工作的基本原则:最慢者暴政。

原理与机制

想象一下,你负责管理一个由许多送货卡车组成的大型车队,所有卡车都从同一仓库出发前往同一目的地。你的目标很简单:尽快将全部货物运达。那么,这项工作何时才算“完成”?不是第一辆卡车到达时,也不是平均到达时间。只有当最后一辆卡车驶入目的地时,工作才算完成。你整个昂贵、并行的操作速度,是由其最慢的那个成员决定的。简而言之,这就是并行计算的根本挑战,这一原则通常被称为​​完工时间 (makespan)​​,也是我们必须服务的主宰。

最慢者暴政

在高性能计算的世界里,我们的“卡车”是处理器,“货物”是计算工作。无论我们是在模拟喷气式飞机机翼上的气流、蛋白质的折叠,还是星系的形成,我们都会将庞大的问题分解成小块,并分配给成千上万个协同工作的处理器。在每个时间步(模拟中的一个微小、离散的瞬间)结束时,处理器必须等待彼此完成工作,然后才能进入下一步。因此,单个时间步的墙上时钟时间 TstepT_{\text{step}}Tstep​ 不是平均时间,而是最大时间:

Tstep≈max⁡p(Wp+Cp)T_{\text{step}} \approx \max_{p} \left( W_p + C_p \right)Tstep​≈pmax​(Wp​+Cp​)

在这里,ppp 代表单个处理器。它花费的时间是两部分之和:WpW_pWp​,即其计算​​工作负载​​(用于“计算”的时间),和 CpC_pCp​,即其​​通信开销​​(用于与其他处理器“交谈”以交换数据的时间)。如果一个处理器被分配的工作远多于其他处理器,或者它陷入了通信拥堵,所有其他处理器都将闲置,无所事事,等待那个落后者赶上。这台价值数百万美元的超级计算机的整体效率便会骤降。

​​负载控制​​,或称​​负载均衡​​,是反抗这种最慢者暴政的艺术和科学。它旨在持续努力确保所有处理器上的总时间 Wp+CpW_p + C_pWp​+Cp​ 尽可能相等。然而,这个简单的目标引出了一系列优美而复杂的策略、权衡和意想不到的后果。

第一道防线:静态均衡

最直接的策略是从一开始就完美地规划一切。这被称为​​静态负载均衡​​。在模拟开始前,我们仔细分析问题并将其划分给各个处理器。想象一下,我们的模拟域是一个代表物理空间的三维网格。我们的目标是将这个网格切成块,每个处理器一块。我们有两个常常相互冲突的目标:

  1. ​​均衡工作​​:每一块应包含大致相同数量的计算工作。如果我们有一个模型可以估算网格中每个单元所需的工作量,我们的目标就是使每个处理器的这些工作量估算值之和相等。

  2. ​​最小化通信​​:通信发生在块与块之间的边界上。一个处理器需要与其拥有相邻块的处理器交换其边界单元的数据(一种“光环交换”)。为了最小化这种通信,我们希望使“切口”尽可能小。理想的分区会给每个处理器一块紧凑、团状的网格,其表面积相对于其体积要小。一个长而细的块会有很长的边界,导致过多的通信。

寻找最优切分是图论中的一个难题,但已有杰出的算法被开发出来解决它。对于许多工作负载均匀且不随时间变化的问题——比如在稳定巡航状态下模拟机翼上的气流——一个良好的初始静态分区便已足够。计划得以维持,车队平稳前行。

当世界变化时:动态均衡的适用场景

但如果世界并非如此可预测呢?如果我们的模拟充满了意外呢?这时静态均衡就会失效,我们需要一种更具适应性的策略:​​动态负载均衡​​。这涉及到在模拟期间改变分区——将工作从一个处理器迁移到另一个处理器。

这种需求出现在无数的科学领域中。在气候模拟中,可能会形成一场飓风,产生一个活动剧烈的区域,这需要更精细的网格(​​自适应网格加密​​),从而需要更多的计算工作。在早期宇宙的模拟中,引力导致粒子聚集在一起,形成密集的星团和星系。一个最初被分配到空旷区域的处理器可能会突然发现自己要负责一个巨大的、新形成的星系,而另一个处理器的区域则变成了空洞。在分子动力学中,分子可能聚集在一起,在盒子的一部分形成稠密的液相,在另一部分形成稀疏的气相,从而急剧改变了局部的工作负载。

即使在你的个人电脑上,操作系统也是一个不懈的动态负载均衡器。你可能同时运行着几十个线程,但许多线程处于“阻塞”状态,等待你输入内容或等待文件从磁盘加载。这会产生暂时的不均衡。如果一个CPU核心上有两个活动线程,而另一个核心因为其线程被阻塞而闲置,操作系统调度器会尝试将其中一个活动线程迁移到闲置的核心,以保持其所有资源都处于忙碌状态。不均衡的来源无处不在,它们是采用动态策略的主要动机。

交易的艺术:何时值得再均衡?

动态再均衡听起来很棒,但它是有代价的。停止模拟、计算新的分区、并将一个单元所需的所有数据从一个处理器的内存物理地移动到另一个处理器都需要时间——这就是​​迁移成本​​。过于频繁地这样做可能比完全不做好更糟糕,就像一个每五分钟就停下来重新整理货物的车队。

因此,决定是否再均衡是一项关键的成本效益分析。我们只应在预期的未来收益超过直接成本时才采取行动。

让我们想象一个来自地球地幔对流模拟的具体场景。我们测量了性能并发现显著的负载不均衡:

  • 目前每步的时间由最慢的处理器决定,耗时 13.513.513.5 秒。
  • 所有处理器的平均时间仅为 101010 秒。这意味着每一步都有一些处理器闲置了 3.53.53.5 秒!
  • 我们的再均衡算法预测,如果我们现在重新分区,可以将最大时间减少到更为均衡的 10.510.510.5 秒。这将为我们未来的每一步节省 13.5−10.5=313.5 - 10.5 = 313.5−10.5=3 秒。
  • 执行这次重新分区的一次性成本估计为 555 秒。
  • 我们预计模拟在此工作负载下还将运行 505050 步。

这值得吗?总节省将是 50 步×3 秒/步=15050 \text{ 步} \times 3 \text{ 秒/步} = 15050 步×3 秒/步=150 秒。而成本仅为 555 秒。这是一笔极好的交易!我们执行再均衡。反之,如果我们只剩一步要运行,花费 555 秒进行再均衡以节省 333 秒将是愚蠢的。这种权衡是所有动态负载均衡系统的基础。在操作系统中,这转化为寻找最佳的均衡频率:均衡得太频繁,调度器的开销和迁移线程带来的缓存惩罚会扼杀性能;均衡得太少,核心会闲置而其他核心则超载。存在一个能够最大化整体系统吞吐量的最佳平衡点。

实现方式:中央计划者与勤劳的窃贼

如果系统决定进行再均衡,实际上是如何协调的呢?主要有两种哲学,我们可以将其视为中央计划者与工人的自由市场。

​​集中式任务队列​​模型就是中央计划者。所有可用任务都放在一个单一的全局队列中。每当一个处理器空闲下来,它就去这个中央队列请求一个新任务。这种设计很简单,但有一个主要弱点:中央队列本身。随着你增加越来越多的处理器,它们都必须排队争夺对这一个队列的访问权。它变成了一个​​串行化点​​,一个限制整个系统可扩展性的瓶颈。此外,如果托管中央队列的机器发生故障,整个模拟就会停顿——这是一个​​单点故障​​。

更现代、更具可扩展性的方法是分布式模型,其中一个著名的例子是​​工作窃取​​。在这个模型中,每个处理器都有自己的私有任务队列。它处理自己的任务,不打扰任何人。然而,如果一个处理器用完了工作,其本地队列变空,它就变成了一个“窃贼”。它会随机选择另一个处理器(一个“受害者”)并尝试从其队列中“窃取”一个任务。这个系统的美妙之处在于所有的负载均衡活动都是去中心化的。没有全局瓶颈。竞争是罕见且短暂的。它也更具容错性;如果一个处理器发生故障,其他处理器可以继续工作并相互窃取任务。这种优雅的分布式算法是许多现代并行运行时和编程语言的核心。

微妙的成本与惊人的联系

负载均衡的原则延伸到令人惊讶的微妙和深刻的领域,揭示了贯穿科学计算的深层联系。

其中一个微妙之处是​​可复现性​​。在计算机的浮点运算世界中,操作的顺序很重要。由于微小的舍入误差,计算 (a+b)+c(a+b)+c(a+b)+c 可能会与 a+(b+c)a+(b+c)a+(b+c) 得出略有不同的答案。当动态负载均衡器将一个单元从处理器A迁移到处理器B时,该单元对全局总和(如系统的总能量)的贡献将以不同的顺序相加。这种微小的变化在某些混沌系统中,可能随着时间的推移导致完全不同的模拟轨迹。因此,要求严格位级可复现性的应用可能被迫使用静态均衡,即使其效率较低。或者,可能需要采用巧妙的数学技巧,比如使用确定性的​​配对函数​​来分配随机数,确保无论工作如何动态调度,每个计算都能接收到完全相同的随机输入序列。

最后,“工作”这个概念本身并不总是仅仅关乎计算。考虑一个使用蒙特卡洛方法的模拟,该方法依赖于统计抽样。为了得到精确的答案,我们需要进行大量抽样。问题空间的某些区域(“分层”)比其他区域变异性更大,需要更多样本才能得到好的估计。一个统计上最优的计划(“Neyman分配”)会为每个分层分配不同数量的样本。但如果我们将分层分配给处理器,这可能会造成严重的负载不均衡!一个被分配到高方差分层的处理器可能需要做比分配到低方差分层的处理器多100倍的工作(采集100倍的样本)。最好的整体策略可能是一种折衷:一种统计上“次优”但计算上远为均衡的分配,从而能更快地完成。

这说明了负载控制的终极教训:不能孤立地优化单个部分。你必须将系统作为一个整体来考虑。从组织卡车车队到在CPU上调度线程,从模拟星系到确保统计公平性,原则始终如一:整体的速度取决于其最慢的部分。负载均衡的目标是让所有人共同进步。

应用与跨学科联系

在我们了解了负载控制的核心原理之后,你可能会觉得这是一个相当技术性,甚至可能有些枯燥的课题,仅限于计算机科学家的深奥世界。事实远非如此。平衡负载的原则就像运动定律一样基础和普适。它是促成大部分现代科学技术的无形之手,其回响可以在经济学、物理学和生物学等不同领域中找到。要真正领会它的力量,我们必须亲见其应用。

保持繁忙的普适逻辑

让我们不从超级计算机开始,而是从一个简单的日常场景开始。想象一下,你是一家小公司的经理,负责完成一个大项目,比如分析12份报告。你有三名员工,他们各自以不同但恒定的速度工作:Alice 每小时完成1份报告,Bob 完成2份,Charles 完成3份。你该如何分配这12份报告,才能在最短的时间内完成整个项目?

你可以给他们每人平均分配4份报告。但这样一来,Alice 需要4小时,Bob 需要2小时,而Charles 只需要1小时20分钟。项目直到最后一个人完成才算结束,所以总时间将是4小时,在此期间 Bob 和 Charles 会有相当长的一段时间无所事事。这显然是低效的。

来自负载均衡的洞见是让每个人在同一时间完成。如果总时间是 TTT,那么 Alice 应该被分配 1×T1 \times T1×T 份报告,Bob 2×T2 \times T2×T 份,Charles 3×T3 \times T3×T 份。由于报告总数是12份,我们有 T+2T+3T=12T + 2T + 3T = 12T+2T+3T=12,得出 6T=126T = 126T=12,即 T=2T = 2T=2 小时。这意味着 Alice 应该分配到2份报告,Bob 4份,Charles 6份。在这种安排下,所有三名员工都在恰好2小时内完成工作。工作负载根据他们的能力得到了完美均衡,项目也在可能的最短时间内完成。

这个简单的想法——为了最小化总时间,你必须根据每个工人的处理速率按比例分配工作——正是负载控制的核心。一台现代超级计算机只不过是一家拥有数百万或数十亿员工(处理器)的公司,挑战依然相同:让每个人都高效地忙碌着。

数字工厂:平衡信息流

当你浏览互联网或访问文件时,你正在与依赖负载均衡才能平稳运行的庞大计算系统进行交互。

考虑一个热门网站。它不是在一台计算机上运行,而是在一个由成百上千台相同机器组成的“服务器农场”上运行。当数百万用户发送请求时,系统如何决定哪台服务器应该处理你的请求?由一个中央管理器轮询每台服务器问“你忙吗?”会是一个糟糕的瓶颈。取而代之的是一种远为优雅的解决方案:一个无状态负载均衡器就像一顶分院帽。它从你的请求中提取一个唯一的信息,比如你的IP地址,然后使用一个称为*哈希函数*的数学函数,立即将其分配给一个特定的服务器。一个设计良好的哈希函数会随机且均匀地分散请求,从而以高概率确保没有单台服务器被雪崩般的流量淹没,而其邻居却闲置。这种方法的美妙之处在于其速度和简单性;它在不需要知道服务器当前状态的情况下平衡了负载。更高级的方案甚至使用巧妙构建的哈希族,为应对恶意请求模式提供更强的数学保障,以防过载。

这个原则延伸到硬件深处。想象一下一个带有RAID存储系统的媒体服务器,数据为了可靠性而镜像在多个物理磁盘上。当你请求一个视频流时,哪个磁盘应该提供数据?一个智能的RAID控制器可以在所有磁盘之间平衡读取请求。如果一个流正在从磁盘1读取,另一个可以从磁盘2读取,依此类推。通过考虑缓存等因素,控制器可以尽可能均匀地分配后端I/O负载,与依赖单个磁盘相比,极大地增加了系统可以支持的并发流数量。

模拟现实:非均匀性的巨大挑战

也许负载均衡最深远的应用是在科学模拟中,这是我们理解宇宙的主要工具。科学家使用超级计算机模拟从星系形成、蛋白质折叠到海洋湍流的一切。所有这些系统的一个共同特征是非均匀性:有趣的物理现象并不会在所有地方平等发生。星系在密集的团块中形成,而不是在星系际空间的空洞中。裂纹沿材料中的特定路径扩展。飓风是广阔大气中的局部风暴。

这带来了一个巨大的挑战。如果我们把模拟域(比如说,一个虚拟空间盒子)分成相等的块,并将每块分配给一个处理器,那么一些处理器将被分配到“有趣”的区域,有大量的工作要做,而另一些处理器将被分配到空无一物的空间,几乎瞬间完成。这就是 Alice 和 Charles 的办公室场景,但规模是宇宙级的。

例如,在一个被真空包围的材料板的分子动力学模拟中,对模拟盒子进行简单的三维分区是灾难性的。被分配到真空区域的处理器没有原子,因此不做任何工作,导致效率极差。一个更聪明的做法是只沿材料存在的维度进行分区,例如,对一个平板进行二维分解。这确保每个处理器都得到材料的一个柱体,并有相当的工作量。更复杂的方法使用令人费解的“空间填充曲线”,将原子的三维位置映射到一维线上,然后可以轻松地切成等工作量的段,既保证了负载均衡,又确保了相互通信的处理器处理空间上相邻的原子。

当非均匀性不是静态而是动态时,问题就更加复杂了。在等离子体的粒子模拟(Particle-in-Cell)中,粒子可能开始时均匀分布,但由于电磁力作用,随时间推移而聚集。一个在模拟开始时均衡的分区,到后来可能会变得极度不均衡。这就需要​​动态负载均衡 (DLB)​​,即模拟周期性地暂停,测量每个处理器上的工作负载,并重新分配数据以恢复平衡。当然,再均衡不是免费的;它有开销成本。性能建模中的一个关键问题是确定不均衡的成本超过再均衡成本的临界点。

在一些现代方法中,不均衡不是偶然,而是刻意为之的特性。在​​自适应网格加密 (AMR)​​中,模拟会自动在解变化迅速的区域使用更高的分辨率(更多的网格单元和更多的计算),比如海洋模拟中沿海涡流周围。这是一种将计算能力集中在最需要地方的绝妙方法。然而,这意味着我们正在有意地创建计算“热点”。负载均衡的挑战就变成了管理这种有目的的不均衡,确保处理加密区域的处理器不会成为压倒性的瓶颈。

算法的灵魂

对负载均衡的需求比仅仅划分数据更深;它影响着我们用来解决问题的算法的选择。在并行计算的世界里,“最好”的算法并不总是那个在单处理器上最快的算法。

考虑在计算物理模拟中寻找一个复杂方程根的任务。人们可能会使用著名的 Newton-Raphson 方法,它能以惊人的速度收敛到答案。然而,它的收敛也可能不稳定;根据初始猜测的不同,它可能需要几步或几千步,甚至可能根本不收敛。现在想象一下,你有成千上万个这样的方程要并行求解。如果你将它们分配给你的处理器,有些会很快完成,而另一些则会卡在困难的情况下。结果就是严重的负载不均衡。

与此形成对比的是不起眼的二分法。它保证收敛,但速度要慢得多、稳定得多。它在并行环境中的关键优点是其可预测性。对于任何给定的问题,我们可以提前精确计算出达到所需精度需要多少步。这使我们能够通过在处理器之间分配问题,使得每个处理器上的二分法总步数几乎相同,从而完美地平衡工作负载。矛盾的是,在大型并行机上,“较慢”但可预测的二分法可能会远远超过“较快”但不可预测的 Newton 方法,纯粹是因为其工作负载可以如此有效地被均衡。

算法的并行结构本身也很重要。用于矩阵乘法的 Strassen 算法是一种经典的“分而治之”方法,它将一个大的矩阵乘法分解为7个较小的乘法。在第一步,它只提供了7的并行度。如果你有一千个处理器,其中993个将处于空闲状态。这造成了初始瓶颈。相比之下,一个更直接的瓦片式算法,可能从一开始就将问题分解成成千上万个微小的、独立任务,为动态调度器提供了大量的并行性以供分配。最高效的并行算法通常是那个给调度器最大灵活性的算法。

复杂性的前沿:多物理场与多尺度

负载均衡的终极挑战出现在最复杂的模拟中,那些在不同尺度上耦合不同物理模型的模拟。

想象一下计算生物学中组织生长的模拟。这涉及一个混合模型:一个偏微分方程 (PDE) 描述化学形态发生素如何在背景网格中扩散,而一个基于代理的模型 (ABM) 将单个细胞视为移动、分裂和消耗形态发生素的代理。为了并行化这个过程,我们必须平衡两种不同的工作:网格元素上的PDE工作和代理的ABM工作。此外,为了效率,一个代理及其所在的网格单元应驻留在同一个处理器上,以避免昂贵的长距离通信。这需要一种复杂的“共置”分区策略,该策略同时平衡两种工作负载的加权和。

现在考虑这种复杂性的顶峰:使用有限元平方 (FE2FE^2FE2) 方法对一种新合金进行的多尺度模拟。为了确定材料在宏观结构(如飞机机翼)上某一点的响应,模拟必须在该点对材料的微观晶体结构进行一个完全独立的、复杂的模拟。这是一个模拟中的模拟。这些微观模拟的成本可能会因材料是弹性变形还是经历复杂的塑性变形而相差几个数量级。静态的工作分配注定会失败。在这个领域,只有最先进的、完全动态的、异步的负载均衡策略——即空闲处理器主动从繁忙处理器“窃取”工作——才有可能成功。

从在办公室分配任务的简单智慧,到模拟中模拟的令人费解的复杂性,负载控制的原则始终如一。它是一个深刻而优美的概念,是计算结构中一条必不可少的线索,将算法、架构以及我们试图理解的物理问题的基本结构联系在一起。它是那门看不见但不可或缺的艺术——让每个人都保持忙碌。