写点什么

CapacityScheduler 原理

作者:冰心的小屋
  • 2023-09-12
    北京
  • 本文字数:7260 字

    阅读完需:约 24 分钟

CapacityScheduler 原理

CapacityScheduler 使用了树的结构来管理资源的使用,树的节点类型为 Queue,Queue 你可以理解为就是一个可伸缩的资源池,任务提交申请资源和任务销毁时释放资源都由 Queue 统一管理。

1. 队列类型:

  • ParentQueue:非叶子结点包含子节点,管理子队列的状态信息,子队列之间资源的共享等;

  • LeafQueue:叶子结点,任务只能提交到叶子节点,校验当前队列状态,运行的任务是否达到最大,用户提交任务数量的校验。

2. 通用队列属性,适用于所有队列

  • yarn.scheduler.capacity.maximum-applications:处于 running 和 pending 状态任务的最大数量,默认 10000;

  • yarn.scheduler.capacity.max-parallel-apps:任务运行的并发度,默认 int 最大值;

  • yarn.scheduler.capacity.resource-calculator:可以限定的资源类型,默认值 org.apache.hadoop.yarn.util.resource.DefaultResourceCalculator 只能用来限定内存,无法限定 CPU,如需同时限定 CPU 和内存需使用 org.apache.hadoop.yarn.util.resource.DominantResourceCalculator;

  • yarn.scheduler.maximum-allocation-vcores:每个 container 可申请的最大 vcore,默认 4;

  • yarn.scheduler.maximum-allocation-mb:每个 container 可申请的最大内存,默认 8192。

3. 队列私有属性

  • yarn.scheduler.capacity..state:队列状态,RUNNING = 上线的队列,可用来分配任务资源,STOPPED = 下线状态的队列,之前可能上过线现在下线了;

  • yarn.scheduler.capacity..maximum-applications:必须小于等于对应的通用队列属性;

  • yarn.scheduler.capacity..max-parallel-apps:必须小于等于对应的通用队列属性;

  • yarn.scheduler.capacity..capacity:当前队列容量在父队列中的容量占比,这里比较特殊的是 root 根节点,容量始终等于 100 表示 Yarn 可分配的总资源,对某个父队列其所有子队列占比之和为 100,例如 root 子队列事业部 1 占 20%、事业部 2 占 50% 和事业部 3 占 20%。

  • yarn.scheduler.capacity..maximum-capacity:当前队列的容量超过默认容量时,还可以用多少其他队列的容量,如果不配置默认 100 即可使用父队列容量的全部;

3.1 限定 Container

  • yarn.scheduler.capacity..maximum-allocation-vcores:当前队列中每个 container 可申请的最 大 vcore,这个值必须 <= yarn.scheduler.maximum-allocation-vcores;

  • yarn.scheduler.capacity..maximum-allocation-mb:当前队列中每个 container 可申请的最大内存,这个值必须 <= yarn.scheduler.maximum-allocation-mb。

3.2 限定用户资源

  • yarn.scheduler.capacity..minimum-user-limit-percent:限制用户使用的最小资源占比;

  • yarn.scheduler.capacity..user-limit-factor:用户可扩容的倍数,例如原有占比 10%,如果 该值为 2 那么用户可用的最大资源为 20%。

3.3 限定用户权限

  • yarn.scheduler.capacity.root..acl_submit_applications:可提交任务的用户或用户组;

  • yarn.scheduler.capacity.root..acl_administer_queue:队列的管理权限。

ACL 控制语法:用户之间逗号分隔 + 空格 + 用户组之间逗号分隔。

3.4 用户、用户组和队列的映射

  • yarn.scheduler.capacity.queue-mappings:用户提交任务的时候,可以根据用户名称和用户所在用户组限定用户提交的队列,支持多个规则,规则之间以逗号分隔,排在前面的规则优先执行;

  • 用户和队列的匹配:u:username:queue;

  • 用户组和队列的匹配:g:userGroup:queue;


例如用户 user1 和 user2,user1 所在的用户组 userGroup1,和队列的映射规则:

  • user1 -> q1,匹配优先级高

  • user2 -> q2

  • userGroup1 -> q3


那么配置如下:

<property>  <name>yarn.scheduler.capacity.queue-mappings</name>  <value>u:user1:q1,u:user2:q2,g:userGroup1:q3</value></property>
复制代码

4. 环境部署

配置 CapacityScheduler 队列,要求如下:

  • 事业部 1 队列 q1 资源:20% ~ 30%;

  • 子队列 user:40% ~ 50%;

  • 子队列 spark:60% ~ 80%;

  • 事业部 2 队列 q2 资源:50% ~ 80%;

  • 子队列 query:30% ~ 50%;

  • 子队列 export:50% ~ 80%;

  • 子队列 merge:20% ~ 30%;

  • 事业部 3 队列 q3 资源:30% ~ 50%;

  • 子队列 import:20% ~ 30%;

  • 子队列 ai:80% ~ 100%。

4.1 环境搭建

wget https://downloads.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gztar -xvf hadoop-3.3.6.tar.gzcd /home/ice/hadoop-3.3.6/etc/hadoop # 1. 配置 core-site.xmlcat << EoF > core-site.xml<configuration>    <property>        <name>fs.defaultFS</name>        <value>hdfs://localhost:9000</value>    </property></configuration>EoF # 2. 配置 hdfs-site.xmlcat << EoF > hdfs-site.xml<configuration>    <property>        <name>dfs.replication</name>        <value>1</value>    </property></configuration>EoF # 3. 配置 mapred-site.xmlcat << EoF > hdfs-site.xml<configuration>    <property>        <name>mapreduce.framework.name</name>        <value>yarn</value>    </property>    <property>        <name>mapreduce.application.classpath</name>      <value>$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*:$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*</value>    </property></configuration>EoF # 4. 配置 yarn-site.xml,这里需要用到 CapacityScheduler,同时限制下 Yarn 整体资源为 10GB,主要是好测试cat << EoF > yarn-site.xml<configuration>    <property>        <name>yarn.nodemanager.aux-services</name>        <value>mapreduce_shuffle</value>    </property>    <property>        <name>yarn.nodemanager.resource.memory-mb</name>        <value>10240</value>    </property>    <property>        <name>yarn.nodemanager.env-whitelist</name>        <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_HOME,PATH,LANG,TZ,HADOOP_MAPRED_HOME</value>    </property>    <property>        <name>yarn.resourcemanager.scheduler.class</name>        <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>    </property></configuration>EoF
echo "export JAVA_HOME=/home/ice/jdk1.8.0_191" >> hadoop-env.shecho 'export HDFS_NAMENODE_OPTS="-XX:+UseParallelGC -Xmx2g"' >> hadoop-env.shecho 'export HDFS_DATANODE_OPTS="-XX:+UseParallelGC -Xmx4g"' >> hadoop-env.sh # 这里为了可以远程 debugecho 'export YARN_RESOURCEMANAGER_OPTS="-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9999"' >> yarn-env.sh # 生成密钥一路回车ssh-keygen# 设置免密登录ssh-copy-id localhost # 加入到环境变量里面vim ~/.bash_profileexport HADOOP_HOME=/home/ice/hadoop-3.3.6export PATH=$HADOOP_HOME/bin:$PATH:$HOME/.local/bin:$HOME/bin source ~/.bash_profile
复制代码

4.3 配置队列:capacity-scheduler.xml

<!--  Licensed under the Apache License, Version 2.0 (the "License");  you may not use this file except in compliance with the License.  You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See accompanying LICENSE file.--><configuration> <property> <name>yarn.scheduler.capacity.root.queues</name> <value>q1,q2,q3</value> </property> <!-- q1 及其子队列--> <property> <name>yarn.scheduler.capacity.root.q1.queues</name> <value>user,spark</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.capacity</name> <value>20</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.maximum-capacity</name> <value>30</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.user.capacity</name> <value>40</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.user.maximum-capacity</name> <value>50</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.user.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.spark.capacity</name> <value>60</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.spark.maximum-capacity</name> <value>80</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.spark.state</name> <value>RUNNING</value> </property>
<!--q2 及其子队列--> <property> <name>yarn.scheduler.capacity.root.q2.queues</name> <value>query,export,merge</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.capacity</name> <value>50</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.maximum-capacity</name> <value>80</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.query.capacity</name> <value>30</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.query.maximum-capacity</name> <value>50</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.query.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.export.capacity</name> <value>50</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.export.maximum-capacity</name> <value>80</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.export.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.merge.capacity</name> <value>20</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.merge.maximum-capacity</name> <value>30</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.merge.state</name> <value>RUNNING</value> </property>
<!--q3 及其子队列--> <property> <name>yarn.scheduler.capacity.root.q3.queues</name> <value>import,ai</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.capacity</name> <value>30</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.maximum-capacity</name> <value>50</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.import.capacity</name> <value>20</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.import.maximum-capacity</name> <value>30</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.import.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.ai.capacity</name> <value>80</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.ai.maximum-capacity</name> <value>100</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.ai.state</name> <value>RUNNING</value> </property></configuration>
复制代码

4.4 启动

bin/hdfs namenode -formatsbin/start-dfs.shsbin/start-yarn.sh
复制代码


查看具体配置:hadoop queue -list

5. 场景测试

编写用于测试的脚本:

# 1. 先创建 HDFS 目录hdfs dfs -mkdir /input # 2. 放点测试文件hdfs dfs -put etc/hadoop/*.xml /input # 3. 运行个原有的样例hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar grep /input /output 'dfs[a-z.]+' # 4. 编写脚本 start_test.sh# 可以设定提交用户和提交队列queue=${1:-root.q2}export HADOOP_USER_NAME=${2:-ice}
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar pi \-Dyarn.app.mapreduce.am.resource.mb=2048 \-Dmapreduce.job.queuename=$queue \100 100
复制代码


将测试的队列变得简单一些,复现问题也会容易些:

<!--       Licensed under the Apache License, Version 2.0 (the "License");  you may not use this file except in compliance with the License.  You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See accompanying LICENSE file.--><configuration> <property> <name>yarn.scheduler.capacity.user.max-parallel-apps</name> <value>100</value> </property> <property> <name>yarn.scheduler.capacity.root.queues</name> <value>q1,q2,q3</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.capacity</name> <value>20</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q1.user-limit-factor</name> <value>5</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.capacity</name> <value>50</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.user-limit-factor</name> <value>2</value> </property> <property> <name>yarn.scheduler.capacity.root.q2.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.capacity</name> <value>30</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.state</name> <value>RUNNING</value> </property> <property> <name>yarn.scheduler.capacity.root.q3.user-limit-factor</name> <value>4</value> </property></configuration>
复制代码


通过设置 user-limit-factor,用户提交的任务可使用集群所有资源:

  • root.q1:0.2 * 5 = 100%;

  • root.q2:0.5 * 2 = 100%;

  • root.q3:0.3 * 4 = 120% 只能使用 100%。

5.1 单队列单任务

直接启动任务即可:./start_test.sh,默认提交到 root.q1 队列

5.2 单独列多任务

改为后台任务多次执行:


for i in `seq 1 3`; do sh start_test.sh; done;
复制代码



执行过程中发现同一时刻只能有一个任务执行,主要原因是最开始提交的任务 application_1694433897361_0002 占用了所有资源,导致后续的 application_1694433897361_0003application_1694433897361_0004 只能阻塞。

通过上面的测试可以发现,设定用户使用容量的上线很有必要。

5.3 多队列多任务同时执行

for queue in root.q1 root.q2;do sh start_test.sh $queue;done
复制代码

运行中发现,不同队列的任务没有发生阻塞:

两个任务执行的状态:

5.4 多队列多任务先后执行

我们让 root.q1 队列任务先执行一会,等其占用到整体资源 100% 时,这时候再提交 root.q2 队列任务:


测试过程中发现,root.q2 等待一段时间后获取到资源,并没有强制的对 root.q1 队列任务 kill,CapacityScheduler 其实不同队列发生资源竞争时,会减少正在运行任务的资源需要等到再次申请资源时,还是很友好的:

所有设置队列的最大上限也是很有必要的,起码不会影响其他队列的执行。


发布于: 刚刚阅读数: 3
用户头像

分享技术上的点滴收获! 2013-08-06 加入

一杯咖啡,一首老歌,一段代码,欢迎做客冰屋,享受编码和技术带来的快乐! 欢迎关注公众号:冰心的小屋

评论

发布
暂无评论
CapacityScheduler 原理_YARN_冰心的小屋_InfoQ写作社区