背景介绍
在腾讯云EMR的用户场景使用当中,有部分用户要求希望他们能在任务高峰期,对集群进行扩容,利用云端的弹性计算资源,为集群扩展计算能力,并且在集群相对空闲的情况下,对集群进行缩容,能够最大化的平衡费用成本,达到对资源的按需利用,从而满足自身对计算的需求。
如何在腾讯云的EMR上,如何实现这个目标呢?
从实现上来说,我们需要考虑两部分
集群扩缩容:
我们需要在某个时刻对集群进行扩容,我们EMR已经提供了REST API对集群进行Task节点扩缩容操作,用户可以自行通过自己的扩容策略按需扩容,缩容, demo为emrdemo。
核心的应用不受影响:
保持核心的应用不受集群扩缩容的影响,例如实时计算程序只希望跑在常规节点,其余计算量大的程序允许一定程度的延迟,因为在缩容的时候,会涉及到一些任务Container的重跑,所以要允许某些不重要的业务在缩容的时间段延迟的情况,这就涉及到YARN上对节点进行分区的操作。
目前在EMR上,支持使用容量调度器进行对节点进行分区,也就是Node Label功能,这个功能的主要作用是可以对计算节点打上标签,然后对队列标记上标签,等操作将application分配到要求的节点上,从而达到将计算节点分区的目的(原理文章后面会介绍)。
操作步骤:
在EMR控制台上面增加配置:
1.点击参数配置 2.选择yarn 3.点击自定义参数配置
登陆EMR机器,执行命令:
代码语言:javascript复制echo `hdfs getconf -confKey fs.defaultFS`/hadoop/label-store
hdfs://HDFSXXXX/hadoop/label-store
增加参数
配置文件 | 参数名 | 运行值 |
---|---|---|
yarn-site.xml | yarn.node-labels.enabled | true |
yarn-site.xml | yarn.node-labels.fs-store.root-dir | hdfs://HDFSXXXX/hadoop/label-store |
同步配置之后,重启RM
终端执行命令,为集群添加标签
代码语言:javascript复制yarn rmadmin -addToClusterNodeLabels label_online
为节点打上标签:
代码语言:javascript复制yarn rmadmin -replaceLabelsOnNode ip:5006=label_online
调整队列配置修改capacity-scheduler.xml
代码语言:javascript复制<configuration>
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>online,offline</value>
</property>
<!-- 默认标签的队列配置 -->
<property>
<name>yarn.scheduler.capacity.root.online.capacity</name>
<value>20</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.offline.capacity</name>
<value>80</value>
</property>
<!--队列访问标签设置-->
<property>
<name>yarn.scheduler.capacity.root.online.accessible-node-labels</name>
<value>label_online</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.online.default-node-label-expression</name>
<value>label_online</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.offline.default-node-label-expression</name>
<value>*</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.default-node-label-expression</name>
<value>*</value>
</property>
<!--标签资源设置-->
<property>
<name>yarn.scheduler.capacity.root.accessible-node-labels.label_online.capacity</name>
<value>100</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.online.accessible-node-labels.label_online.capacity</name>
<value>99</value>
</property>
<property>
<name>yarn.scheduler.capacity.root.offline.accessible-node-labels.label_online.capacity</name>
<value>1</value>
</property>
<property>
<name>yarn.scheduler.capacity.resource-calculator</name>
<value>org.apache.hadoop.yarn.util.resource.DominantResourceCalculator</value>
</property>
</configuration>
进行测试验证
指定标签
代码语言:javascript复制hadoop jar /usr/local/service/hadoop/share/hadoop/yarn/hadoop-yarn-applications-distributedshell-2.7.3.jar org.apache.hadoop.yarn.applications.distributedshell.Client -shell_command "sleep 200s" -container_memory 2048 -num_containers 100 -node_label_expression "label_online" -jar /usr/local/service/hadoop/share/hadoop/yarn/hadoop-yarn-applications-distributedshell-2.7.3.jar -appname wallytest -queue online
运行结果:
只运行到了label_online节点
不指定标签
应用会跑到所有的节点上
代码语言:javascript复制hadoop jar /usr/local/service/hadoop/share/hadoop/yarn/hadoop-yarn-applications-distributedshell-2.7.3.jar org.apache.hadoop.yarn.applications.distributedshell.Client -shell_command "sleep 200s" -container_memory 2048 -num_containers 100 -jar /usr/local/service/hadoop/share/hadoop/yarn/hadoop-yarn-applications-distributedshell-2.7.3.jar -appname wallytest -queue offline
原理介绍
接下来,如果有兴趣的同学可以往下了解CS调度器标签实现的一些大致的原理:
不管是CS还是FS调度器,默认配置的情况下,节点每一次心跳都会触发资源的分配,在容量调度器分配的流程,会受节点资源的预留情况影响,如果该节点已经有application预留过,则优先分配该节点的资源给预留的application,如果没有预留,则从root节点进行资源的分配,这两个过程都涉及到了调度器如何把资源分配给对应的application的一个过程。
在正常的分配过程中,对于Parent Queue队列来说(非叶子结点为ParentQueue,叶子结点为LeafQueue),它的分配过程其实就是找到最合适的childQueue队列并把资源分配下去,而LeafQueue则是将对应资源分配给它下面的applications的一个过程。
分配的过程其实可以分成两个阶段:一个是标签的满足性检查,一个是资源的满足性检查(队列的资源限制和用户的资源限制等等),总的来说,分配的过程就是一个满足性检查的过程,同时会涉及很多机制类似本地性和预留机制去优化调度器资源的分配。
标签的满足性检查
对于具有标签功能的CS调度器,Queue和Node之间分配的条件,需要检查自身的queue label(ParentQueue 和 LeafQueue)和node label是否拥有共同的标签,如果有则继续分配资源,否则则跳过该队列和该队列的子队列的资源分配,直到找到合适的队列分配或不参与任务的调度。
资源满足性检查
资源分配涉及的细节比较多,具体不详细描述(详细的可以一起交流),接下来只从大体的分配流程,给大家展示,一般的分配流程:
步骤简单的描述为(ParentQueue):
- 首先节点会和队列的标签进行满足性检查
- 节点的可用内存是否满足最小分配资源要求,是则继续,否则结束分配
- 检查分配后的资源或分配后的非预留资源是否小于currentLimitResource,是则允许分配到这个队列,否则结束分配
- 选择childQueue进行分配,根据不同childQueue的配置,计算出不同的childLimit,然后进行分配
- 如果分配成功,则对这个childQueue进行resort,跳出继续找childQueue的过程,回到步骤6,否则则遍历childQueue返回
- 检查分配的情况,如果上一次分配成功,回到步骤2,否则结束对该节点的分配流程
步骤简单的描述为(LeafQueue):
- 首先节点会和队列的标签进行满足性检查
- 对于每一个applicaiton,检查该节点是否在application的黑名单节点
- 检查分配后的资源或分配后的非预留资源是否小于currentLimitResource,是则允许分配到这个队列,否则结束分配
- 计算和检查用户资源是否小于该队列的用户资源的限制
- 本地性参数检查
- application的request label和节点的node labe检查
- 应用请求的container容量和节点可用容量检查
- 最后调用application进行Allocate进行资源的分配
这就是资源分配的大体流程
总结
这篇文章描述了如何在EMR和YARN的基础上对集群进行弹性扩容,同时不影响重要任务的运行,从而达到按需而用,降低用户的成本,充分利用云的资源弹性的特性,接下来的文章将会带来YARN的抢占机制和YARN预留系统的代码分析,有兴趣可以关注。