原文地址:https://program-park.github.io/2022/02/11/hadoop_41/
部分内容摘自尚硅谷、黑马等等培训资料
在 YARN 中,资源管理由 ResourceManager 和 NodeManager 共同完成,其中,ResourceManager 中的调度器负责资源的分配,而 NodeManager 则负责资源的供给和隔离。
资源分配给任务
;提供相应的资源
,甚至保证这些资源应具有独占性
,为任务运行提供基础的保证;Hadoop YARN 同时支持内存和 CPU 两种资源的调度,先品味一下内存和 CPU 这两种资源的特点,这是两种性质不同的资源。内存资源的多少会会决定任务的生死,如果内存不够,任务可能会运行失败; 相比之下,CPU资源则不同,它只会决定任务运行的快慢,不会对生死产生影响。
YARN 允许用户配置每个节点上可用的物理内存资源,注意,这里是 “可用的”,因为一个节点上的内存会被若干个服务共享,比如一部分给 YARN,一部分给 HDFS,一部分给 HBase 等,YARN 配置的只是自己可以使用的,配置参数如下:
yarn.nodemanager.resource.memory-mb
yarn.nodemanager.resource.detect-hardware-capabilities
为true时,将会自动计算操作系统内存进行设置。yarn.nodemanager.vmem-pmem-ratio
yarn.nodemanager.pmem-check-enabled
yarn.nodemanager.vmem-check-enabled
yarn.scheduler.minimum-allocation-mb
yarn.scheduler.maximum-allocation-mb
默认情况下,YARN 采用了线程监控的方法判断任务是否超量使用内存,一旦发现超量,则直接将其杀死
。由于 Cgroups 对内存的控制缺乏灵活性(即任务任何时刻不能超过内存上限,如果超过,则直接将其杀死或者报 OOM),而 Java 进程在创建瞬间内存将翻倍,之后骤降到正常值,这种情况下,采用线程监控的方式更加灵活(当发现进程树内存瞬间翻倍超过设定值时,可认为是正常现象,不会将任务杀死),因此 YARN 未提供 Cgroups 内存隔离机制。
在 YARN 中,CPU 资源的组织方式仍在探索中,当前只是非常粗粒度的实现方式。CPU被划分成虚拟CPU(CPU virtual Core)
,此处的虚拟 CPU 是 YARN 自己引入的概念,初衷是,考虑到不同节点的 CPU 性能可能不同,每个 CPU 具有的计算能力也是不一样的,比如某个物理 CPU 的计算能力可能是另外一个物理 CPU 的 2 倍,此时可以通过为第一个物理 CPU 多配置几个虚拟 CPU 弥补这种差异。用户提交作业时,可以指定每个任务需要的虚拟 CPU 个数。
在 YARN 中,CPU 相关配置参数如下:
yarn.nodemanager.resource.cpu-vcores
yarn.nodemanager.resource.detect-hardware-capabilities
为 true 时,将会自动计算操作系统 CPU 核数进行设置。yarn.scheduler.minimum-allocation-vcores
yarn.scheduler.maximum-allocation-vcores
由于 CPU 资源的独特性,目前这种 CPU 分配方式仍然是粗粒度的。
在 YARN 中,负责给应用分配资源的就是 Scheduler。其实调度本身就是一个难题,很难找到一个完美的策略可以解决所有的应用场景。为此,YARN 提供了多种调度器和可配置的策略供选择。
在 YARN 中有三种调度器可以选择:FIFO Scheduler(先进先出调度器)
,Capacity Scheduler(容量调度器)
,Fair Scheduler(公平调度器)
。
默认情况下,Apache 版本 YARN 使用的是Capacity调度器
。如果需要使用其他的调度器,可以在yarn-site.xml中
的yarn.resourcemanager.scheduler.class
进行配置,具体的配置方式如下:
在 YARN WebUI 界面:http://hadoop123:8088/cluster
在 YARN 中,有层级队列组织方法,它们构成一个树结构,且根队列叫做root
。所有的应用都运行在叶子队列中
(即树结构中的非叶子节点只是逻辑概念,本身并不能运行应用)。对于任何一个应用,都可以显式地指定它属于的队列,也可以不指定从而使用username或者default队列。下图就是一个队列的结构:
FifoScheduler 是 MRv1 中 JobTracker 原有的调度器实现,此调度器在 YARN 中保留了下来。FifoScheduler是一个先进先出的思想,即先来的Application先运行。调度工作不考虑优先级和范围,适用于负载较低的小规模集群。当使用大型共享集群时,它的效率较低且会导致一些问题。
FifoScheduler 拥有一个控制全局的队列 queue,默认queue名称为default
,该调度器会获取当前集群上所有的资源信息作用于这个全局的 queue。
FifoScheduler 将所有的Application按照提交时候的顺序来执行,只有当上一个 Job 执行完成之后后面的 Job 才会按照队列的顺序依次被执行。虽然单一的 FIFO 调度实现简单,但是对于很多实际的场景并不能满足要求,催发了 Capacity 调度器和 Fair 调度器的出现。
Capacity 调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列
,然后再为每个队列分配一定的集群资源
,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。
Capacity调度器可以理解成一个个的资源队列,这个资源队列是用户自己去分配的。队列内部又可以垂直划分,这样一个组织内部的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。
Capacity Scheduler 调度器以队列为单位划分资源。简单通俗点来说,就是一个个队列有独立的资源,队列的结构和资源是可以进行配置的
,如下图:
default 队列占30%资源,analyst 和 dev 分别占 40% 和 30% 资源;类似的,analyst 和 dev 各有两个子队列,子队列在父队列的基础上再分配资源。
CapacityScheduler 是一个可插拔调度程序,它被设计为以队列为单位划分资源、易于操作的方式在多租户模式下安全的共享大型集群,同时能保证每个组所需资源的保证,当容量不够用时还可以使用其他组多余的容量。这种方式最大程度地提高集群的吞吐量和利用率,以便在分配的容量约束下及时为其应用程序分配资源。CapacityScheduler 的特性如下:
CapacityScheduler 的配置项包括两部分,其中一部分在yarn-site.xml
中,主要用于配置 YARN 集群使用的调度器;另一部分在capacity-scheduler.xml
配置文件中,主要用于配置各个队列的资源量、权重等信息。
在 ResourceManager 中配置使用的调度器,修改HADOOP_CONF/yarn-site.xml
,设置属性:
<property>
<name>yarn.resourcemanager.scheduler.classname>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulervalue>
property>
调度器的核心就是队列的分配和使用,修改HADOOP_CONF/capacity-scheduler.xml
可以配置队列。Capacity 调度器默认有一个预定义的队列:root,所有的队列都是它的子队列。队列的分配支持层次化的配置,使用.
来进行分割,比如:
“user1, user2 group1,group2”
。[u or g]:[name]:[queue_name][,next_mapping]*
,列表可以多个,之间以逗号分隔。%user 放在 [name] 部分,表示已经提交应用的用户。如果队列名称和用户一样,那可以使用 %user 表示队列。如果队列名称和用户主组一样,可以使用 %primary_group 表示队列。 u:%user:%user
表示已经提交应用的用户,映射到和用户名称一样的队列上。 u:user2:%primary_group
表示 user2 提交的应用映射到 user2 主组名称一样的队列上。如果用户组并不多,队列也不多,建议还是使用简单的语法,而不要使用带 % 的。org.apache.hadoop.yarn.util.resource.DefaultResourseCalculator
,它只会计算内存。DominantResourceCalculator
则会计算内存和 CPU。 如果想要修改队列或者调度器的配置,可以修改HADOOP_CONF_DIR/capacity-scheduler.xml
,修改完成后,需要执行下面的命令:
HADOOP_YARN_HOME/bin/yarn rmadmin -refreshQueues
注意事项:
mapreduce.job.queuename
属性指定要用的队列。如果队列不存在,在提交任务时就会收到错误。如果没有定义任何队列,所有的应用将会放在一个default
队列中。假设有如下层次的队列:
上图中队列的一个调度器配置文件HADOOP_CONF/capacity-scheduler.xml
:
<configuration>
<property>
<name>yarn.scheduler.capacity.root.queuesname>
<value>prod,devvalue>
property>
<property>
<name>yarn.scheduler.capacity.root.dev.queuesname>
<value>eng,sciencevalue>
property>
<property>
<name>yarn.scheduler.capacity.root.prod.capacityname>
<value>40value>
property>
<property>
<name>yarn.scheduler.capacity.root.dev.capacityname>
<value>60value>
property>
<property>
<name>yarn.scheduler.capacity.root.dev.maximum-capacityname>
<value>75value>
property>
<property>
<name>yarn.scheduler.capacity.root.dev.eng.capacityname>
<value>50value>
property>
<property>
<name>yarn.scheduler.capacity.root.dev.science.capacityname>
<value>50value>
property>
configuration>
相关属性说明如下所示:
dev
队列又被分成了eng
和science
两个相同容量的子队列;dev
的maximum-capacity
属性被设置成了 75%,所以即使prod
队列完全空闲dev
也不会占用全部集群资源,也就是说,prod
队列仍有 25% 的可用资源用来应急;eng
和science
两个队列没有设置maximum-capacity
属性,也就是说eng
或science
队列中的 job 可能会用到整个dev
队列的所有资源(最多为集群的 75%);prod
由于没有设置maximum-capacity
属性,它有可能会占用集群全部资源;对于Capacity调度器,队列名必须是队列树中的最后一部分
,如果使用队列树则不会被识别。比如,在上面配置中,使用prod
和eng
作为队列名是可以的,但是如果用root.dev.eng
或者dev.eng
是无效的。上述配置队列形式如下所示:
运行 MapReduce 中 WordCount 程序,指定运行队列 prod
HADOOP_HOME=/export/server/hadoop
${HADOOP_HOME}/bin/yarn jar \
${HADOOP_HOME}/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.4.jar \
wordcount \
-Dmapreduce.job.queuename=prod \
datas/input.data /datas/output
查看 8088 界面如下所示:
不指定运行队列,默认运行在default
队列,如果找不到default队列将会报如下错误
。
HADOOP_HOME=/export/server/hadoop
${HADOOP_HOME}/bin/yarn jar \
${HADOOP_HOME}/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.4.jar \
wordcount \
datas/input.data /datas/output2
还有一个 Fair Scheduler 公平调度器下一篇博客再详细说,因为这个要说的东西比较多。(这篇博客太长了,csdn编辑面板总是崩)