首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Yarn 调度器

YARN是双层调度范式,YARN Scheduler是YARN的主调度器,YARN Scheduler有多种实现,每一种对应了不同的调度策略,如常见的FIFO Scheduler,Fair Scheduler、Capacity Scheduler等,它们都是可插拔的。资源调度器是YARN中最核心的组件之一,并且是可插拔的,用户可以根据它的一整套接口,编写自己的Scheduler,实现自己所需的调度逻辑。这里的调度逻辑指的是第一次调度逻辑,而不关注第二层调度策略,它由计算框架自己控制。

一、YARN的资源管理机制

YARN的资源是以资源池的形式组织的。每个资源池对应一个队列(queue),用户在提交作业的时候以

-queue 参数指定要提交的队列,就可以使用队列背后对应的资源池。在第二代Hadoop中,队列是以树形的方式组织起来的,如图下图所示,YARN中最大的资源池就是整个集群的资源,对应队列为根队列root,如果用户不指定队列,那么默认提交的就是该队列。

层次结构

Yarn中的队列(queue)机制。在yarn中,有层级队列组织方法,它们构成一个树结构,且根队列叫做root。所有的应用都运行在叶子队列中(即树结构中的非叶子节点只是逻辑概念,本身并不能运行应用)。对于任何一个应用,我们都可以显式地指定它属于的队列,也可以不指定从而使用username或者default队列。用户只能将自己的作业提交给子队列,每个队列都可继续向其中添加子队列。子队列的资源使用的都是父队列的资源。

Yarn中有三种调度器可用:FIFO Scheduler(FIFO 调度器) ,Capacity Scheduler(容量调度) 和 Fair Scheduler(公平调度)。

二、FIFO Scheduler

FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。

FIFO Scheduler是最简单也是最容易理解的调度器,也不需要任何配置,但它并不适用于共享集群。大的应用可能会占用所有集群资源,这就导致其它应用被阻塞。在共享集群中,更适合采用Capacity Scheduler或Fair Scheduler,这两个调度器都允许大任务和小任务在提交的同时获得一定的系统资源。从下图可以看出在 FIFO 调度器中,小任务会被大任务阻塞:

三、Capacity Scheduler

Capacity Scheduler是 Yahoo! 开发的调度器,对多用户支持较好。

启用 Capacity Scheduler:

yarn.resourcemanager.scheduler.class

org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler

The class to use as the resource scheduler.

Capacity 调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。除此之外,队列内部又可以垂直划分,这样一个组织内部的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。

如上图所示,对于Capacity调度器,有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用FIFO调度器时的时间。

上图所以,单个作业使用的资源不会超过其队列容量。然而如果这个队列中运行多个job,如果这个队列的资源够用,那么就分配给这些job,如果这个队列的资源不够用了呢?其实 Capacity 调度器仍可能分配额外的资源给这个队列,这就是弹性队列”(queue elasticity)的概念。

在正常的操作中,Capacity调度器不会通过强制终止来抢占Container,因此如果一个队列一开始资源够用,然后随着需求增长,资源开始不够用时,那么这个队列就只能等着其它队列释放容器资源。缓解这种情况的方法是,为队列设置一个最大容量限制,以免这个队列过多的占用空闲资源,导致其它队列无法使用这些空闲资源,当然这样做是牺牲队列弹性为代价的,因此需要在不断尝试和失败中找到一个合理的值。

如果属性 yarn.scheduler.capacity..user-limit-factor 设置为大于 1(默认值),那么一个作业可以使用超过其队列容量的资源。

假设一个队列的层次结构如下:

层次结构

容量调度器配置文件为 capacity-scheduler xml。在root队列下定义两个队列:prod和dev, 分别占40%和60%的 容量。需要注意的是,对特定队列进行配置时,是通过以下形式的配置属性 yarn.scheduler.capacity.. 进行设置的, 其 中, 表示队列的层次路径(用圆点隔开) , 例如 root.prod

yarn.scheduler.capacity.root.queues

prod,dev

yarn.scheduler.capacity.root.dev.queues

eng,science

yarn.scheduler.capacity.root.prod.capacity

40

yarn.scheduler.capacity.root.dev.capacity

60

yarn.scheduler.capacity.root.dev.maximum-capacity

75

yarn.scheduler.capacity.root.dev.eng.capacity

50

yarn.scheduler.capacity.root.dev.science.capacity

50

正如你所见的,prod 和 dev 分别默认分配 root (也就是总资源)中 40% 和 60% 的资源,而 dev 的两个子队列则分配当前 dev 分配到的资源的 50% 和 50% 的资源。

上面说默认分配,是因为 YARN 为了合理利用资源,有一个叫做 queue elasticity 的功能:即在大多时候,一个队列中的 application 是不能使用超过队列容量的资源的。但是如果队列中应用个数超过一个并且其他队列拥有空闲资源时,Capacity Scheduler 会分配给它这些空闲的资源,哪怕使得总资源超过该队列的容量。

同时在 Capacity Scheduler 中,没有抢占资源这一说。因此当某个队列需要更多的资源时(比如本身属于它的资源被其他队列暂时借走),则必须等到其他队列自己还回资源。为了避免某个队列占用了全部资源从而导致其他队列完全无法运行应用的情况出现,我们可以在配置文件中设置 maximum-capacity 的值,例如上面的列子,dev 对应的值是 75,这就意味着 dev 队列最多使用 75% 的 root 资源,从而最少给 prod 留下 25% 的资源,从而避免刚刚所说的情况出现。

队列放置

将应用放置在哪个队列中, 取决于应用本身。例如, 在Map Reduce中,可以通过设置属性map reduce.job.queue name来指定要用的队列。如果队列不存在, 则在提交时会发送错误。如果不指定队列,那么应用将被放在一个名为 “default”的默认队列中。

对于容量调度器,队列名应该是队列层次名的最后一部分(即叶子结点),完整的队列层次名是不会被识别的。例如, 对于上述配置范例, prod 和 eng 是合法的队列名,但 root.dev.eng 和 dev.eng 作为队列名是无效的。

sudo -u hdfs  hadoop jar hadoop-examples.jar pi -Dmapreduce.job.queuename=eng 10 1

四、Fair Scheduler

公平调度器旨在为所有运行的应用公平分配资源 。下图展示了同一个队列中的应用是如何实现资源公平共享的。然而公平共享实际也可以在多个队列间工作,后续会对此进行分析。

接下来解释资源是如何在队列之间公平共享的。想象两个用户 A 和 B,分别拥有自己的队列(参见下图)。启动一个作业,在B没有需求时 A 会分配到全部可用 资源;当 A 的作业仍在运行时 B 启动一个作业,一段时间后,按照我们先前看到的方式,每个作业都用到了一半的集群资源。这时,如果 B 启动第二个作业且其他作业仍在运行,那么第二个作业将和B的其他作业(这里是第一个)共享资源,因此 B 的每个作业将占用四分之一的集群资源,而 A 仍继续占用一半的集群资源。最终的结果就是资源在用户之间实现了公平共享。

1、启用 Fair Scheduler

公平调度器的使用由属性 yarn.resourcemanager.scheduler.class 的设置所决定。默认是使用 Capacity Scheduler (尽管在一些Hadoop分布式项目, 如CDH中是默认使用 Fair Scheduler),如果要使用 Fari Scheduler,需要修改  yarn-site.xml 文件。

yarn.resourcemanager.scheduler.class

org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler

CM中启用

CM中启用 Fair Scheduler2、队列配置

通过一个名为 fair-scheduler.xml 的分配文件对 Fari Scheduler 进行配置, 该文件位于类路径下。(可以通过设置属性yarn.scheduler.fair.allocation.file来修改文件名) 。当没有该分配文件时,Fair Scheduler 的工作策略同先前所描述的一样:每个应用放置在一个以用户名命名的队列中,队列是在用户提交第一个应用时动态创建的。

CM 配置 fair-scheduler.xml 文件:

CM 配置 fair-scheduler.xml 文件

通过分配文件可以为每个队列进行配置。这样可以对 Fair Scheduler 支持的层次队列进行配置。例如,可以像为Capacity Scheduler 所做的那样,使用分配文件定义 prod 和 dev。

fair

40

fifo

60

队列的层次使用嵌套 queue 元素来定义。所有的队列都是 root 队列的孩子, 即使实际上并没有嵌套进 root queue 元素里。这里把 dev 队列又划分成 eng 和 science 两个队列。

队列中有权重元素,用于公平共享计算。在这个例子中,当集群资源按照 40:60 的比例分配给 prod 和 dev 时, 集群分配被认为是公平的。eng 和 science 队列没有指定权重,因此它们会被平均分配。权重并不是百分百,例子中是为了简单起见使用了相加之和为100的两个数。也可以为 prod 和 dev 队列分别指定 2 和 3 的权重,在效果上是一样的。

尽管上述的分配文件中没有展示,每个队列仍可配置最大和最小资源数量,及最大可运行的应用的数量(更多细节可以访问http://bit_l/fair_scheduar)。最小资源数量不是一个硬性的限制,但是调度器常用它对资源分配进行优先排序。如果两个队列的资源都低于它们的公平共享额度,那么远低于最小资源数量的那个队列优先被分配资源。最小资源数量也会用于接下来将介绍的抢占行为。

最小资源配置:

在每个资源池中,允许配置该资源池的最小资源,这是为了防止把空闲资源共享出去还未回收的时候,该资源池有任务需要运行时候的资源保证。

比如,资源池businessA中配置了最小资源为(5vCPU,5GB),那么即使没有任务运行,Yarn也会为资源池businessA预留出最小资源,一旦有任务需要运行,而集群中已经没有其他空闲资源的时候,这个最小资源也可以保证资源池businessA中的任务可以先运行起来,随后再从集群中获取资源。

CM中配置

当设置权重时,记住要考虑默认队列和动态创建的队列(例如以用户名命名的队列)。虽然没有在分配文件中为它们指定权重,但它们仍有值为1的权重。

每个队列可以有不同的调度策略。队列的默认调度策略可以通过顶层元素 `default Queue Scheduling Policy 进行设置, 如果省略, 默认使用公平调度。尽管名称是“公平”, 公平调度器也支持队列级别的FIFO(fifo) 策略, 以及Dominant Resource Fairness(drf) 策略, 本章稍后会对此策略进行解释。

队列的调度策略可以被该队列的 scheduling Policy 元素指定的策略覆盖。在上述例子中,由于我们希望每个生产性作业能够顺序运行且在最短可能的时间内结束, 所以 prod 队列使用了 FIFO 调度策略。值得注意的是, 在prod 和 dev 队列之间、eng 和 science 队列之间及内部划分资源仍然使用了公平调度。

CM中配置:

3、队列放置

公平调度器使用一个基于规则的系统来确定应用应该放到哪个队列。queuePlacementPolicy元素包含了一个规则列表, 每条规则会被依次尝试直到匹配成功。第一条规则, specified, 表示把应用放进所指明的队列中, 如果没有指明,或如果所指明的队列不存在,则规则不匹配,继续尝试下一条规则。primary Group规则会试着把应用放在以用户的主Unix组名命名的队列中,如果没有这样的队列, 则继续尝试下一条规则而不是创建队列。Default规则是 一条兜底规则, 当前述规则都不匹配时, 将启用该条规则, 把应用放进 dev.eng 队列中。

当然, 可以完全省略queue Placement Policy元素, 此时队列放置默认遵从如下规则:

换而言之,除非明确定义队列,否则必要时会以用户名为队列名创建队列。

另一个简单的队列放置策略是, 将所有的应用放进同一个队列(default) 中。这样可以在应用之间公平共享资源,而不是在用户之间共享。策略定义等价于以下规则:

不使用分配文件也可以设置以上策略,通过将属性 yarn.scheduler.fair.user-as-default-queue设为false, 应用就会被放入default队列, 而不是各个用户的队列。另外,将属性 yarn.scheduler.fair allow-undeclared-pools 设置为false, 用户便不能随意创建队列了。

4、抢占

在一个繁忙的集群中,当作业被提交给一个空队列时,作业不会立刻启动,直到集群上已经运行的作业释放了资源。为了使作业从提交到执行所需的时间可预测,公平调度器支持“抢占” (preemption)功能。

所谓抢占,就是允许调度器终止那些占用资源超过了其公平共享份额的队列的容器,这些容器资源释放后可以分配给资源数量低于应得份额的队列。注意,抢占会降低整个集群的效率, 因为被终止的 containers 需要重新执行。

通过将 yarn.scheduler.fair.preemption 设置为true, 可以全面启用抢占功能。有两个相关的抢占超时设置:一个用于最小共享(minimum share preemption timeout) , 另一个用于公平共享(fair share preemption timeout) , 两者设定时间均为秒级。默认情况下,两个超时参数均不设置。所以为了允许抢占容器,需要至少设置其中一个超时参数。

如果队列在 minium share preemption timeout指定的时间内未获得被承诺的最小共享资源,调度器就会抢占其他容器。 可以通过分配文件中的顶层元素 default Min Share Preemption Timeout 为所有队列设置默认的超时时间, 还可以通过设置每个队列的 min Share Preemption Timeout 元素来为单个队列指定超时时间。

类似, 如果队列在fair share preemption timeout指定的时间内获得的资源仍然低于其公平共享份额的一半,那么调度器就会抢占其他容器。可以通过分配文件中的顶层元素default Fair Share Preemption Timeout为所有队列设置默认的超时时间, 还可以通过设置每个队列的fair Share Preemption Timeout元素来为单个队列指定超时时间。通过设置 default Fair Share Preemption Threshold和 fair Share Preemption Threshold(针对每个队列) 可以修改超时阈值, 默认值是 0.5。

CM配置:

5、延迟调度

所有的YARN调度器都试图以本地请求为重。在一个繁忙的集群上, 如果一个应用请求某个节点,那么极有可能此时有其他容器正在该节点上运行。显而易见的处理是,立刻放宽本地性需求,在同一机架中分配一个容器。然而,通过实践发现,此时如果等待一小段时间(不超过几秒),能够戏剧性的增加在所请求的节点上分配到一个容器的机会,从而可以提高集群的效率。这个特性称之为延迟调度 (delay scheduling) 。容量调度器和公平调度器都支持延迟调度。

YARN 中的每个节点管理器周期性的(默认每秒一次)向资源管理器发送心跳请求。心跳中携带了节点管理器中正运行的容器、新容器可用的资源等信息,这样对于一个计划运行一个容器的应用而言,每个心跳就是一个潜在的调度机会 (scheduling opportunity) 。

当使用延迟调度时,调度器不会简单的使用它收到的第一个调度机会,而是等待设定的最大数目的调度机会发生,然后才放松本地性限制并接收下一个调度机会。

对于容量调度器,可以通过设置 yarn.scheduler.capacity.node-locality-delay 来配置延迟调度。设置为正整数,表示调度器在放松节点限制、改为匹配同一机架上的其他节点前,准备错过的调度机会的数量。

公平调度器也使用调度机会的数量来决定延迟时间,尽管是使用集群规模的比例来表示这个值。例如将yarn.scheduler.fair.locality.threshold.node设置为0.5,表示调度器在接受同一机架中的其他节点之间,将一直等待直到集群中的一半节点都已经给过调度机会。还有个相关的属性 yarn.scheduler.fair.locality.threshold.rack, 表示在接受另一个机架替代所申请的机架之前需要等待的时长阈值。

6、主导资源公平性

对于单一类型资源,如内存的调度,容量或公平性的概念很容易确定。例如两个用户正在运行应用,可以通过度量每个应用使用的内存来比较两个应用。然而,当有多种资源类型需要调度时,事情就会变得复杂。例如,如果一个用户的应用对CPU的需求量很大, 但对内存的需求量很少;而另一个用户需要很少的CPU, 但对内存需求量大,那么如何比较这两个应用呢?

YARN中调度器解决这个问题的思路是, 观察每个用户的主导资源, 并将其作为对集群资源使用的一个度量。这个方法称为主导资源公平性”(Dominant Resource Fairness, DRF), 这个思想用一个简单的例子就可以很好的给予解释。

想象一个总共有100个CPU和10TB的集群。应用A请求的每份容器资源为2个CPU和300GB内存, 应用B请求的每份容器资源为6个CPU和100GB内存。A请求的资源在集群资源中占比分别为2%和3%, 由于内存占比(3%) 大于CPU占比(2%),所以内存是A的主导资源。B请求的资源在集群资源中占比分别为6%和1%, 所以CPU是B的主导资源。由于B申请的资源是A的两倍(6%vs 3%) , 所以在公平调度下,B将分到一半的容器数。

默认情况下不用DRF, 因此在资源计算期间, 只需要考虑内存, 不必考虑CPU。对容量调度器进行配置后, 可以使用DRF, 将capacity-scheduler.xml文件中的 org.apache.had oop.yarn.util.resource.Dominant Resource Calculator设为 yarn.scheduler.capacity.resource-calculator即可。

公平调度器若要使用DRF, 通过将分配文件中的顶层元素 defaultQueueSchedulingPolicy 设为drf即可。

7、动态更新资源配置

通过编辑分配文件,可以在运行时修改最小份额,限制,权重,抢占超时和队列调度策略。调度程序将在看到它被修改后10-15秒重新加载此文件。

Fair Scheduler除了需要在yarn-site.xml文件中启用和配置之外,还需要一个XML文件来配置资源池以及配额,而该XML中每个资源池的配额可以动态更新,之后使用命令:yarn rmadmin –refreshQueues 来使得其生效即可,不用重启Yarn集群

每次在ResourceManager上新增用户或者调整资源池配额后,需要执行下面的命令刷新使其生效:

yarn rmadmin -refreshQueues

yarn rmadmin -refreshUserToGroupsMappings

需要注意的是:动态更新只支持修改资源池配额,如果是新增或减少资源池,则需要重启Yarn集群。

CM中操作:

动态刷新资源池8、在队列之间移动应用程序

Fair Scheduler支持将正在运行的应用程序移动到不同的队列。这对于将重要应用程序移动到更高优先级队列或将不重要的应用程序移动到较低优先级队列非常有用。可以通过运行纱线应用程序移动应用程序

movetoqueue appID -queue targetQueueName

当应用程序移动到队列时,其现有分配将使用新队列的分配而不是旧分配来计算,以确定公平性。如果将应用程序的资源添加到该队列将违反其maxRunningApps或maxResources约束,则尝试将应用程序移动到队列将失败。

9、倾倒公平调度程序状态

Fair Scheduler能够定期转储其状态。默认情况下禁用它。管理员可以通过将org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler.statedump日志记录级别设置为DEBUG 来启用它。

默认情况下,Fair Scheduler日志会转到Resource Manager日志文件。Fair Scheduler状态转储可能会生成大量日志数据。取消注释log4j.properties中的“公平调度程序状态转储”部分,以将状态转储到单独的文件中。

五、Capacity 与 Fair Scheduler比较

fair Scheduler 跟 Capacity Scheduler 在以队列为单位划分资源,每个队列可设定一定比例的资源最大最小值及用户资源限定方面是相同的,fair主要在以下方面比Capacity 具有优势:

资源公平共享。在每个队列中,fair可选择按照FIFO、Fair或 DRF策略为应用程序分配资源。

支持资源抢占。当某个队列有剩余资源时,调度器会将这些资源共享给其他队列,而当该队列中有新的应用程序提交时,调度器要为它回收资源。为了尽可能降低不必要的计算浪费,调度器采用了先等待再强制回收的策略,即如果等待一段时间后尚有未归还的资源,则会进行资源抢占

负载均衡。fair 提供了一个基于任务数目的负载均衡机制,该机制尽可能将系统中的任务均匀分配到各个节点上。此外,用户也可以根据自己需求设计负载均衡机制。

调度策略配置灵活。fair允许管理员为每个队列单独设置调度策略(当前支持fifo,fair,DRF三种)。

提高小应用程序响应时间。由于采用了最大最小公平算法,小作业可以快速获取资源并运行完成。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20201030A0FLKA00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券