AWS EMR集群Yarn节点标签与实例类型错配问题求助
有没有人有在AWS EMR上使用Yarn node labels的经验?麻烦分享一下相关经验。我们的需求是让所有Spark executors运行在Task(Spot)实例上,所有Spark ApplicationMaster/Driver运行在Core(on-Demand)实例上,此前我们的Spark executors和Driver都运行在CORE按需实例上。
为了实现该需求,我们通过自定义AWS EMR Bootstrap action创建了"TASK" Yarn节点标签,额外通过一个Bootstrap action为所有注册到EMR的Spot实例绑定"TASK"标签,而"CORE"是默认的Yarn节点标签表达式,我们在节点注册时通过Bootstrap action将其与按需实例绑定。
我们配置了Spark参数"spark.yarn.executor.nodeLabelExpression": "TASK",用于指定Spark executors启动在Task节点上。
目前我们遇到Yarn节点标签与对应实例错配的问题:在节点启动后的1-2分钟左右,会出现按需实例被绑定"TASK"标签、Spot实例被绑定"CORE"标签的情况,这段时间内Yarn会将Spark executors调度到按需实例上,将Spark drivers调度到Spot实例上。
该标签错配问题会持续到Bootstrap action执行完成,之后标签映射会自动恢复正常。
我们作为Bootstrap action运行的脚本如下,该脚本会在所有新加入的机器上运行,为节点分配对应标签,由于Yarn需要在所有自定义Bootstrap action完成后才可用,我们将该脚本作为后台进程运行:
#!/usr/bin/env bash set -ex function waitTillYarnComesUp() { IS_YARN_EXIST=$(which yarn | grep -i yarn | wc -l) while [ $IS_YARN_EXIST != '1' ] do echo "Yarn not exist" sleep 15 IS_YARN_EXIST=$(which yarn | grep -i yarn | wc -l) done echo "Yarn exist.." } function waitTillTaskLabelSyncs() { LABEL_EXIST=$(yarn cluster --list-node-labels | grep -i TASK | wc -l) while [ $LABEL_EXIST -eq 0 ] do sleep 15 LABEL_EXIST=$(yarn cluster --list-node-labels | grep -i TASK | wc -l) done } function getHostInstanceTypeAndApplyLabel() { HOST_IP=$(curl http://169.254.169.254/latest/meta-data/local-hostname) echo "host ip is ${HOST_IP}" INSTANCE_TYPE=$(curl http://169.254.169.254/latest/meta-data/instance-life-cycle) echo "instance type is ${INSTANCE_TYPE}" PORT_NUMBER=8041 spot="spot" onDemand="on-demand" if [ $INSTANCE_TYPE == $spot ]; then yarn rmadmin -replaceLabelsOnNode "${HOST_IP}:${PORT_NUMBER}=TASK" elif [ $INSTANCE_TYPE == $onDemand ] then yarn rmadmin -replaceLabelsOnNode "${HOST_IP}:${PORT_NUMBER}=CORE" fi } waitTillYarnComesUp # holding for resource manager sync sleep 100 waitTillTaskLabelSyncs getHostInstanceTypeAndApplyLabel exit 0
以下命令会在集群创建时在Master实例上运行,用于创建新的TASK Yarn节点标签:
yarn rmadmin -addToClusterNodeLabels "TASK(exclusive=false)"
请问大家有没有办法可以避免这种标签错配的问题?
该问题的核心原因是Yarn NodeManager启动后会立刻向ResourceManager注册,未绑定自定义标签的节点默认会继承全局默认的CORE标签,而自定义标签设置脚本是后台延迟执行的,二者的时间差就导致了调度空窗期。可以通过以下任意一种方法解决:
- 配置NodeManager延迟注册
在EMR集群的Yarn配置中增加参数yarn.nodemanager.registration.delay-ms,值设置为120000(即2分钟),让NodeManager等待足够时间后再向RM注册,确保注册时节点已经绑定好正确的标签,从根源上消除空窗期。 - 调整默认标签规则,新增调度校验
将Yarn全局默认节点标签修改为临时无效标签(例如PENDING),同时配置所有Yarn队列的调度规则为仅允许任务调度到带有明确CORE/TASK标签的节点,未绑定有效标签的节点不会接收任何任务,直到脚本执行完成绑定正确标签后才会纳入调度资源池。 - 优化现有脚本逻辑,压缩空窗期
删除现有脚本中固定100秒的sleep逻辑,替换为循环检测NodeManager注册状态的逻辑,一旦检测到节点成功注册到RM,立刻执行标签绑定操作,同时在绑定新标签前先清空节点上的所有旧标签,避免残留标签导致错配,可将空窗期压缩到秒级。 - 使用EMR原生实例组标签绑定能力
EMR 6.x及以上版本已经原生支持Yarn节点标签与实例组绑定,创建集群时直接为Core实例组绑定CORE标签、Task实例组绑定TASK标签即可,EMR会在节点启动流程中自动完成标签绑定,无需自定义Bootstrap脚本,稳定性更高,完全不会出现标签错配问题。
内容的提问来源于stack exchange,提问作者agamjain14

