Apollo:云规模计算的可扩展协同调度

摘要

在云规模的计算群集上有效地调度数据并行计算作业对于作业性能、系统吞吐量和资源利用率至关重要。随着集群规模和具有各种特征的更复杂的workload的增长,这变得越来越具有挑战性。本文介绍了Apollo,这是一种高度可扩展协同调度框架,已部署到Microsoft的生产集群上,可每天高效地在数万台计算机上调度数以千计的计算(数百万个任务)。该框架通过松散协调的机制利用全局群集信息以分布式方式执行调度决策。每个调度决策都会考虑未来的资源可用性,并在一个统一的模型中一起优化各种性能和系统因素。Apollo具有强大的功能,可以应对意外的系统动态变化,并且可以在需要时提供有保证的资源的同时优雅地利用空闲的系统资源。

1.介绍

类似于MapReduce的系统让数据并行计算编程变得容易,并允许作业在大型商用硬件群集上处理TB级的数据。每个数据处理作业都包含许多任务,这些任务间具有相关性,描述了任务的执行顺序。任务是计算调度到服务器执行的基本单元。

高效的调度(跟踪任务依赖性并在准备就绪时将任务分配给服务器执行)对整个系统性能和服务质量至关重要。数据并行计算的日益普及和多样性使调度变得越来越困难。例如,用于数据并行计算的生产集群的规模正在不断扩大,每个集群拥有超过20,000台服务器。来自许多不同组织的越来越多的成千上万的用户每天都会向集群提交作业,从而导致每秒成千上万个调度请求的峰值速率。提交的作业本质上是多种多样的,具有数据量、计算逻辑的复杂性、并行度和资源需求方面的多种特征。调度器必须(i)在成千上万台服务器的集群上可扩展以每秒做出数万个调度决策; (ii)保持不同用户和群体之间公平的资源共享; (iii)根据数据局部性、作业特征和服务器负载等因素做出高质量的调度决策,充分利用群集中的资源的同时最小化作业延迟。本文介绍了Apollo调度框架,该框架已完全部署以在Microsoft的云规模生产集群中调度作业,为各种在线服务提供服务。Apollo每天高效地调度数十亿个任务,并通过以下方法来应对大型集群中的调度挑战。

  • 为了在可伸缩性和调度质量之间取得平衡,Apollo采用了分布式(松散)协同的调度框架,通过合并群集利用率信息以乐观和协同的方式做出独立的调度决策。这样的设计达到了适当的平衡:它避免了完全分布式体系结构的独立调度器做出次优(且常常是相互冲突)的决策,同时消除了中心化设计的可伸缩性瓶颈和单点故障。
  • 为了获得高质量的调度决策,Apollo以最小化任务完成时间在服务器上调度每个任务。估计模型包含各种因素,并允许调度器执行加权决策,而不是仅考虑数据位置或服务器负载。计算的数据并行性使Apollo可以根据作业执行过程中类似任务的运行时统计数据,不断完善任务执行时间的估计值。
  • 为了向调度器提供群集信息,Apollo引入了一种轻量级的硬件独立机制来通告服务器上的负载。当与每台服务器上的本地任务队列结合使用时,该机制提供所有服务器上未来资源可用性的视图,调度器可在决策中使用该视图。
  • 为了应对意外的集群动态变化、次优估计以及其他异常运行时行为(这些行为是大型集群的常态),通过一系列校正机制在运行时动态调整和纠正次优决策,这Apollo让变得非常强大。Apollo提供了一种独特的延迟更正机制,该机制仅解决调度器之间产生重大影响冲突,并且这种方法在实践中效果很好。
  • 为了提高群集利用率,同时保持较低的作业延迟,Apollo引入了机会调度,该调度创建了两类任务:常规任务和机会任务。Apollo确保常规任务的低延迟,同时利用机会任务提高利用率,以填补常规任务留下的空隙。Apollo还使用基于token的机制来管理容量(capacity),并通过限制常规任务的总数来避免系统过载。
  • 为了避免Apollo替代生产中已部署先前的调度器时出现服务中断或性能下降的情况,Apollo支持分阶段部署到生产集群并进行大规模验证。这些限制在研究中很少受到关注,但是在实践中却至关重要,本文分享实现这些苛刻目标的经验。

实际观察,Apollo在20,000多台机器的生产集群中每秒调度超过20,000个任务。它还具有很高的调度质量,其中95%的常规任务的排队延迟不到1秒,同时在整个集群中始终保持较高(超过80%)的均衡的CPU利用率。

2.生产规模的调度

Apollo是Microsoft分布式计算平台的基础调度框架,该框架能够满足针对各种业务需求的大规模数据分析。一个典型的群集包含数以万计的服务器,这些服务器通过网络互连。分布式文件系统将数据存储在分布式副本的分区中,类似于GFS和HDFS。所有计算作业均使用SCOPE(一种类似于SQL的高级脚本语言)编写,并带有用户定义的处理逻辑。优化器(optimizer)将作业转换为有向无环图(DAG)的执行计划,其中顶点是任务,边是任务之间的数据流,每个任务代表一个基本计算单元。相同输入的不同分区上执行相同计算的任务逻辑上分阶段组在一起。每个阶段的任务数表示并行度(degree of parallelism-DOP)。

image.png

图1:一个SCOPE执行图示例

图1显示了SCOPE的执行图示例,该图大大简化了一项重要的生产作业,该作业收集了用户点击信息并能够洞察广告效果。从概念上讲,该作业在非结构化用户日志和由连接键(jion key)预先分区的结构化输入之间执行连接。该计划首先使用分区方案从其他输入中对非结构化输入进行分区:阶段S1和S2分别对数据进行分区并汇总每个分区。然后在阶段S4中执行分区连接。根据输入数据量,S1的DOP设置为312,S5的DOP设置为10,S2,S3和S4的DOP设置为150。

2.1容量管理和token

为了确保性能的公平性和可预测性,系统使用基于token的机制为作业分配容量。每个token都被定义为在群集中的计算机上执行常规任务的权利,预定义了该任务最多消耗CPU和内存。例如,一个作业分配了100个token,则意味着它可以运行100个任务,每个任务最多消耗预定义的最大CPU和内存。

出于安全性和资源共享的原因,将为每个用户组创建一个虚拟集群。每个虚拟群集根据token数量分配了一定数量的容量,并维护所有已提交作业的队列。提交的作业包含目标虚拟群集、必要的凭据以及执行所需的token数量。虚拟集群利用各种准入控制策略,并决定如何以及何时将其拥有的token分配给提交的作业。未获得所需token的作业将在虚拟群集中排队。该系统还支持多种功能,例如作业优先级,暂停,升级和取消。

一旦作业获得所需的token开始执行,调度器就要执行计划(优化的执行计划),在遵守token分配的前提下向服务器分配任务,加强任务依赖性,并提供容错能力。

2.2作业调度的本质

调度作业涉及以下功能:

    1. 就绪列表(ready list):维护一个准备好调度的任务列表:最初,该列表包括对原始输入进行操作的那些叶子任务(例如,图1中在步骤S1和S3中的任务);
    2. 任务优先级:适当的对就绪列表排序;
    3. 容量管理:管理分配给作业的容量,并根据容量管理政策决定何时调度任务;
    4. 任务调度:决定在何处调度任务并将其分配给选定的服务器;
    5. 故障恢复:监视调度的任务,在任务失败时启动恢复操作,如果无法恢复则将作业标记为失败;
    6. 任务完成:任务完成后,在执行图中检查依赖它的任务,如果这些任务所依赖的所有任务均已完成,则把它们移至就绪列表;
    7. 作业完成:重复整个过程,直到完成作业中的所有任务。

2.3生产workload特征

生产工作负载的特征极大地影响了Apollo的设计,生产计算集群每天运行超过100,000个作业。在任何时间点,都有数百个作业同时运行。为满足各种各样的业务场景和要求这些作业几乎在很多方面都有很大的不同。例如,大型作业处理TB到PB的数据,包含复杂的业务逻辑和几十个复杂的联接、聚合和用户定义的函数,具有数百个阶段,在执行计划中包含超过一百万个任务,可能需要数小时完成。另一方面,小型作业可处理千兆字节的数据,并且可以在几秒钟内完成。在SCOPE中,还为不同的作业分配了不同数量的资源。支持业务随时间的变化,工作负载也在不断变化。这种工作负载的多样性给基础调度框架带来了巨大的挑战,需要有效地处理。本文描述了几个在生产环境中的作业特征来展示计算工作负载的多样性和动态性。

image.png

图2:异构工作负载

在SCOPE中,根据要处理的数据量和每次计算的复杂性来选择作业阶段的DOP。即使在单个作业中,随着作业期间数据量的变化,DOP也会在不同阶段发生变化。图2(a)显示了阶段DOP在生产环境中的分布。它从一到几万不等。几乎40%的阶段的DOP小于100,占总工作量的不到2%。超过98%的任务属于DOP超过100的阶段。这些阶段的大规模使调度器可以从某些任务中提取统计信息,以推断同一阶段中其他任务的行为,Apollo可以利用这些行为做出明智的决策。作业大小从单个顶点到每个作业图的数百万个顶点,变化很大。如图2(b)所示,每个作业处理的数据量范围从千兆字节到数十PB。任务执行时间从不到100毫秒到几个小时不等,如图2(c)所示。50%的任务运行时间不到10秒,并且对调度延迟很敏感。某些任务需要外部文件(例如可执行文件,配置和查找表)来执行,因此会产生初始化费用。在某些情况下,执行所需的此类外部文件大于要处理的实际输入,这意味着位置应基于这些文件的缓存位置而不是输入位置。总的来说,如此大量的作业创造了很高的调度请求率,峰值每秒超过100,000个请求,如图2(d)所示。

生产的计算工作负载和集群环境的动态性和多样化的特征给调度框架带来了一些挑战,包括可伸缩性、效率、健壮性和资源使用均衡性。Apollo调度框架的设计,旨在解决Microsoft大型生产集群上的这些挑战。

3.Apollo框架

为了支持生产工作负载所需的规模和调度率,Apollo采用了分布式和协同的体系结构,其中每个作业的调度是独立执行的,并且合并汇总的全局群集负载信息。

3.1架构概述

image.png

图3:Apollo架构图

图3是Apollo的架构图。作业管理器(JM)也称为调度器,管理每个作业的生命周期。每个JM使用的全局群集负载信息是通过Apollo框架中两个其他模块的协作提供的:每个群集的ResourceMonitor(RM)和每个服务器上的ProcessNode(PN)。在每台服务器上运行的PN进程负责管理该服务器上的本地资源并执行本地调度,而RM则不断地聚集整个集群中来自PN的负载信息,从而为每个JM提供集群状态的全局视图来做明智的调度决定。

虽然将RM视为单个逻辑模块,但它可以通过不同的机制以不同的配置实现,因为它本质上解决了监视大规模分布式资源集合的动态变化的问题。例如,它可以使用具有最终一致性协议的树层次结构或目录服务。Apollo的架构可以适配任何此类配置。本方案使用Paxos主从配置实现RM。 RM绝不是性能的关键:即使RM暂时不可用,例如由于机器故障而导致的临时主从切换期间,Apollo仍可以继续(降低质量)做出调度决策。此外,一旦将任务调度到PN,JM就会直接从PN频繁的状态更新获得最新的负载信息。

为了更好地预测将来的资源利用率并优化调度质量,每个PN都维护分配给服务器的本地任务队列,根据队列进行推断并以等待时间矩阵的形式通告其未来的资源可用性。因此,Apollo采用基于估计的方法来制定任务调度决策。具体来说,Apollo参考了由RM汇总的等待时间矩阵,以及要调度的任务的各个特征,例如输入的位置。然而,集群的动态性在实践中提出了许多挑战。例如,等待时间矩阵可能是过时的,估计值可能不是最佳的,并且群集环境有时可能是不可预测的。因此,Apollo引入了校正机制来提升鲁棒性,并在运行时动态调整了调度决策。最后,为作业提供有保证的资源(例如,确保SLAs)与实现较高的群集利用率很难同时兼顾,因为群集负载和作业的资源需求都在不断波动。 Apollo通过机会调度解决了这个问题,该调度创建了第二类任务来使用空闲资源。

3.2 PN队列和等待时间矩阵

每个服务器上的PN管理分配给该服务器的任务队列,以提供对未来资源可用性的预测。当JM在服务器上调度任务时,它会发送任务创建请求,其中包含(i)细粒度的资源要求(CPU核数和内存),(ii)估计的运行时间,以及(iii)运行该任务所需的文件列表任务(例如可执行文件和配置文件)。收到任务创建请求后,PN将所需文件缓存到本地目录。 PN监视CPU和内存使用情况,参考队列中任务的资源需求,并在容量可用时执行它们。它可以根据单个任务的CPU和内存需求,通过执行尽可能多的任务来最大程度地利用资源。 PN队列主要是FIFO,但可以重新排序。例如,靠后的需要较少资源的任务可以填补空白,而不会影响其他任务的预期开始时间。

使用任务队列让调度器可以根据未来的资源可用性(而不是基于瞬时可用性)将任务主动调度到PN。Apollo全面参考了任务等待时间(足够的可用资源)和其他任务特性来优化任务调度。使用任务队列还可以在资源可用之前复制文件进而屏蔽任务初始化的成本,避免任务之间的空闲间隙。这种直接派发机制提供了任务(特别是小型任务)所需的效率,因为任何要协商协议都会产生大量开销。

PN还向JM提供反馈,来帮助提高任务运行时估计的准确性。最初,JM使用查询优化器根据任务中的操作和数据量提供的保守估计。不同的数据集的任务在同一阶段执行相同的计算,它们的运行时特性相似,并且较早任务执行的统计信息可帮助改进较晚任务的运行时估计。任务开始运行后,PN将监视其总体资源使用情况,并通过内存使用情况、CPU时间、执行时间和I / O吞吐量等信息向JM更新状态。然后,JM使用此信息以及其他因素(例如操作特性和输入大小)来优化资源使用情况并预测来自同一阶段的任务的预期运行时间。

PN进一步公开了当前服务器上的负载并通过RM进行汇总。理想情况下,其负载信息表示应该传达对未来资源可用性的预测,屏蔽数据中心中服务器的异构性(例如,具有64GB内存和128GB内存的服务器具有不同的容量),并且要足够简洁方便频繁使用更新。 Apollo的解决方案是一个等待时间矩阵,每个单元对应于需要一定数量CPU和内存的任务的预期等待时间。图3包含一个矩阵示例:单元<12GB,4个核>中的值为10,表示需要4个CPU核和12GB内存的任务必须在此PN中等待10秒才能获得其资源配额。PN根据当前正在运行和排队的任务,为各种资源配额的未来任务维护一个预期的等待时间矩阵。该算法模拟本地任务执行,并评估具有给定CPU /内存需求的未来任务将在该PN上等待执行多长时间。PN通过参考实际资源状况以及最新的任务运行时和资源估计来频繁更新此矩阵。最后,PN将这个矩阵以及时间戳发送给在该PN中运行或排队任务的每个JM,它还使用心跳机制将矩阵发送到RM。

3.3基于估计的调度

JM必须使用RM提供等待时间矩阵的汇总视图以及要调度的任务的各个特征,来决定任务调度到哪个服务器上。 Apollo在单个统一模型中使用基于估计的方法必须考虑各种影响调度决策质量的因素(通常是相互冲突的因素)。

image.png

图4:任务调度示例

本文使用一个示例来说明同时考虑各种因素的重要性,以及在每台服务器上都具有本地队列的好处。图4(a)显示了一个简化的服务器图,其中包含两个机架,每个机架通过分层的网络连接,每个机架有四个服务器。假设可以从本地磁盘以160MB / s的速度读取数据,从同一机架内以100MB / s的速度读取数据,从另一个机架以80MB / s的速度读取数据。考虑调度一个任务,该任务有两个输入(一个100MB存储在服务器A中,另一个5GB存储在服务器C中),是I/O密集型任务。图4(b)显示了四个调度选择,其中服务器A和B可立即使用,而服务器C具有最佳数据位置。然而,D是这四个选择中的最佳选择。仅当同时考虑数据位置和等待时间时,才能认识到这一点。此示例还说明了本地队列的价值:每个服务器上都没有本地队列,任何检查即时资源可用性的调度机制都会选择A或B这样的非最佳选择。

因此,Apollo全面考虑了各种因素,并通过估计任务完成时间来执行调度。首先,使用公式估算没有失败(由Esucc表示)的任务完成时间

I表示用于获取任务所需文件的初始化时间,如果这些文件在本地缓存,则可能为0。期望的等待时间(表示为W)是通过查找目标服务器的等待时间矩阵获得。任务运行时(表示为R)由I / O时间和CPU时间组成。将I / O时间计算为输入大小除以预期的I / O吞吐量。 I / O可以来自本地内存,磁盘或各种带宽的网络。总体而言,R的估计最初会包含来自优化器的信息,并使用同一阶段任务的运行时统计信息进行精细化调整。

其次,考虑任务失败的可能性来计算最终完成时间估计,用C表示。在真实的大规模环境中,硬件故障、维护、维修和软件部署是不可避免的。为了减轻其影响,RM还收集了每台服务器上近期和过去的维护计划信息。总而言之,设成功的概率Psucc并将其用于计算C,如下所示。凭经验确定的惩罚常数Kfail用于在任务完成时间上对服务器的故障成本进行建模。

任务优先级.除了完成时间估计之外,任务执行顺序也对整体作业延迟影响很大。例如,对于图1中的作业图,S1中的任务平均运行1分钟,S2中的任务平均运行2分钟,潜在的分区倾斜导致任务运行长达10分钟,而这些任务在S3中平均运行30秒。因此,有效执行S1和S2对于实现最短的运行时间毫无疑问非常关键。因此,调度器应该在考虑S3之前将资源分配给S1和S2。在S2内,调度器应尽早从输入最大的顶点开始,因为它最有可能位于作业的关键路径上。

优化器在每个阶段通过分析作业DAG并计算作业执行的潜在关键路径来标注任务静态优先级。阶段中的任务将根据输入大小确定优先级。Apollo调度任务并按优先级从高到低的顺序分配资源。由于作业包含有限数量的任务,因此不可能饿死低静态优先级的任务,因为最终它们将是剩下的唯一要执行的任务,迟早会被执行。

稳定匹配.为了提高效率,Apollo分批调度具有相似优先级的任务,并将任务调度问题转变为任务与服务器之间的匹配问题。对于每个任务,可以搜索集群中的所有服务器以找到最佳匹配。在大型群集上,该方法变得非常昂贵。相反,Apollo将任务的搜索空间限制为一组候选服务器,包括(i)一组服务器,大量输入位于这些服务器上(ii)与第一组服务器在同一机架中的一组服务器(iii)从一组轻负载服务器中随机选择两个服务器;

image.png

图5:匹配例子

贪婪算法可以依次应用于每个任务,选择每个步骤中估计完成时间最短的服务器。但是,贪婪算法的结果对任务匹配的顺序很敏感,并且常常导致次优决策。图5显示了一个示例,其中调度了三个任务。假定Task1和Task2都从服务器A读取数据,而Task3则从服务器B读取数据,如虚线所示。每台服务器都有能力启动一项任务。贪婪的匹配器首先将Task1与服务器A匹配,然后将Task2与服务器B匹配,因为已经在A上调度了Task1,最后将Task3与服务器C匹配,如实线所示。应该将Task3分配给服务器B以获得更好的位置才是更好的匹配。

因此,Apollo采用稳定匹配算法的一种变体来匹配任务与服务器。对于批处理中的每个任务,Apollo会找到估计完成时间最短的服务器作为该任务的提案。如果服务器只收到了一个任务提案,则该服务器会接受该提议。当多个任务提案同一服务器时,就会发生冲突。在这种情况下,服务器将选择节省完成时间最多的任务。未选择的任务撤回其提案,并进入下一个试图匹配其余任务和服务器的迭代。该算法持续迭代直到分配了所有任务或者达到最大迭代次数为止。如图5所示,稳定匹配器将Task2匹配到C,将Task3匹配到B,这有效地利用了数据局部性,从而提高了作业性能。

然后,调度器根据所有匹配对的质量对它们进行排序,以决定调度顺序。如果匹配的任务具有较短的服务器等待时间,则认为该匹配具有较高的质量。调度器遍历排序的匹配项并按顺序进行调度,直到超出分配的容量为止。如果启用了机会调度,则调度器将继续调度任务,直到机会调度限制为止。

为了简化匹配算法,在效率和质量之间进行权衡,Apollo只能在一个批次中为每个服务器分配一个任务,否则考虑到新分配的任务Apollo必须更新服务器的等待时间矩阵,这增加了算法的复杂性(每次匹配都是假设没有分配新任务为前提)。这种简化可能导致任务的次优匹配,因为这是贪婪算法的另一个变种。Apollo通过两种方式减轻影响:如果次优匹配项的质量较低,则按质量对匹配项进行排序会导致该任务的派发被推迟,然后重新进行评估。即使调度了次优的匹配项,第3.4节中描述的更正机制也旨在捕获这种情况并在需要时重新调度任务。

3.4校正机制

在Apollo中每个JM都可以独立地、无延迟的高频率调度任务。这对于调度拥有大量小任务的workload非常关键。但是,由于调度的分布式特性,几个JM可能同时做出竞争性决策。此外,用于调度决策的信息(例如等待时间矩阵)可能会过时;任务等待时间和运行时间可能不足或高估。 Apollo内部有机制来应对这些挑战并时刻利用最新状态信息动态调整调度决策。

与以往方案(例如在Omega中)不同,在调度时间内立即解决冲突,Apollo乐观地将任务分配到PN队列之后再进行纠正(推迟纠正)。这种设计选择是基于历史的大量观察,即冲突并不总是有害的。如果不同的作业管理器同时调度任务到同一台有足够的资源的服务器并可以并行运行两个任务;先前在服务器上调度的任务可能很快就会完成,尽早释放资源从而无需解决任何冲突。在这些情况下,本地队列使延迟校正机制成为可能,从而避免了急于检测和解决冲突造成的不必要开销。校正机制会不断使用最新信息重新评估调度决策,并在必要时进行适当的调整。

副本调度.当JM在任务创建、升级或监视其任务队列期间从PN获取新的信息时,它会将来自该PN的信息(以及到目前为止经过的等待时间)与已经做出调度决策的信息进行比较。如果出现如下几种情况调度程序会重新评估该决策:

(i)更新后的预期等待时间显着高于原始预期等待时间;

(ii)预期的等待时间大于同一阶段任务的平均时间;

(iii)经过的等待时间已经大于平均值;

第一种情况表示服务器上的任务完成时间被低估,而第二/第三种情况表示任务与服务器匹配质量低。修改调度决策都会触发副本任务调度到新的预期的服务器。当一个任务开始时,其他副本任务将被丢弃。

随机.多个JM可能将任务调度到相同的轻负载PN,彼此之间却不知道,从而导致调度冲突。Apollo在每个完成时间估算值上加一个小的随机数。此随机因素有助于减少不同的JM选择相同服务器冲突的机会。该数字通常与JM和PN之间的通信间隔成比例,对调度决策的质量没有明显影响。

置信度.从RM获得的集群聚合信息包含不同年龄的等待时间矩阵,其中一些可能会过时。调度器将较旧的等待时间矩阵设置较低的置信度,因为从计算出矩阵到现在,等待时间很可能发生了变化。当等待时间矩阵的置信度较低时,调度器将通过查找消耗更多CPU和内存的任务的等待时间来产生悲观的估计。

落后者检测.落后者是比其他任务进展缓慢的任务,对作业性能产生严重影响。Apollo的落后者检测机制通过监控数据处理的速率和CPU的消耗率来预测每个任务剩余的时间量。同一阶段中的其他任务将用作比较的基准。当重新运行任务所需的时间明显少于完成任务所需的时间时,将启动副本任务。它们将并行执行,直到第一个完成,或者直到副本任务赶上了原始任务。调度器还监视I/O速率,并检测由缓慢的中间输入引起的落后者。当任务由于异常的I/O延迟而变慢时,它可以重新运行上游副本任务以提供备用的I/O路径。

3.5机会调度

除了实现大规模的高质量调度外,Apollo还设计提高集群的利用率方法。群集利用率会随时间波动,原因有几个。首先,所有用户都并不是同时提交作业并完全消耗其分配的容量。一个典型的示例是,工作日的群集负载始终高于周末。其次,作业对资源的要求不同。即使具有相同计算逻辑的日常作业也会因其输入数据大小的变化而消耗不同数量的资源。最后,一个完整的作业通常会经历多个阶段,具有不同级别的并行性和变化的资源要求。系统上的这种负载波动为调度器提供了机会,即通过提高利用率来提高作业性能,但以降低可预测性为代价。如何在不影响SLA的情况下明智地利用偶尔的空闲计算资源仍然具有挑战性。

Apollo引入机会调度,以在空闲资源可用时适当地利用它们。任务在常规模式下可以使用足够的token来覆盖其资源消耗,也可以在机会模式下执行,而无需分配资源。每个调度器首先应用乐观调度具有token的常规任务。如果使用了所有token并且仍然有待调度的任务要调度,则可以应用机会调度来调度机会任务。通过在每台服务器上以较低优先级运行机会性任务可以防止常规任务造成的性能下降,并且如果服务器处于高负载,任何机会性任务都可以被抢占或终止。

一个迫在眉睫的挑战是防止一个作业不公平地消耗所有空闲资源。对于机会任务Apollo使用随机分配来实现的资源概率性公平。当token可用并被分配给机会任务,Apollo会将机会性任务升级为常规任务。

随机分配机制:理想情况下,机会资源应在作业之间公平地分配,并与作业的token分配成比例。这尤其具有挑战性,因为整个群集负载和单个服务器负载都会随时间波动,这使得很难(甚至是不可能)保证绝对的瞬时公平性。相反,Apollo着重避免一些作业占用了群集的所有可用容量的最坏情况,并且以平均公平性为目标。

Apollo按作业已分配token比例设置最大机会配额来实现这一目标。例如,具有n个token的作业最多可以分配cn个机会任务(c为常数)。当PN具有可用容量并且常规队列为空时,PN都会从机会任务队列中选择一个随机任务来执行,无论这个作业是什么时候派发的。如果所选任务需要的资源超出可用资源,则继续随机选择,直到没有任务可以执行为止。与FIFO队列相比,该算法的优势在于允许稍后开始的作业快速共享容量。

由于作业的并行程度在其生命周期中会有所不同,因此准备调度的任务数量也会有所不同。结果,作业可能并不总是能够派发足够的机会性任务来充分利用其机会性福利。通过允许每个调度器在随机选择过程中增加机会任务的权重来补偿任务数量的减少,这样可以进一步增强系统。例如,权重为2表示任务被选中的机率是两倍。该作业发出的所有机会性任务的总权重不得超过其机会性福利。

理想的作业负载下,任务运行相同的时间消耗相同数量的资源,并且在一个完美平衡的群集中,该策略是的作业平均共享分配资源成比例的机会资源。但是,实际上任务在运行时与资源需求有很大的差异。随着任务完成和新任务准备就绪,每个作业分派的任务数量会不断变化。此外,作业可能始终没有足够的并行性来充分利用其机会福利。设计一个在动态环境中保证强公平性的完全去中心化的机制仍然是未来一个挑战性课题。

任务升级.如果服务器遇到资源压力,则机会性任务很可能会挨饿。此外,机会性任务可以在队列中无限等待。为了避免作业饿死,在分配了token后,可以将机会调度的任务升级为常规任务。因为作业需要至少一个token才能运行,并且作业中的任务数量有限,所以调度器能够在某一点将饥饿的机会性任务转换为常规任务,从而防止了作业饿死。

机会性任务派发后,调度器在其就绪列表中跟踪任务,直到任务完成为止。在调度常规任务时,调度器会同时考虑未调度的任务和仍在等待执行的先前调度的机会性任务。每个调度器按优先级从高到低的顺序将其token分配给任务。在同一个机器上升级机会任务虽然不是必然选择,但因为没有初始化时间可能是优先选择。调度器通过计算整体的消耗倾向于在常规任务较少的计算机上升级机会性任务,同时等待临时负载较重的计算机释放资源。此策略可更好地利用token并实现更好的负载平衡。

猜你喜欢

转载自blog.csdn.net/weixin_42663840/article/details/108306505
今日推荐