订阅更新

提交了一个Spark作业等了10分钟才跑——YARN资源调度原理

Hadoop手册 第 6 题 约 9 分钟读完

本文目录
  1. 先说结论
  2. YARN的四个核心角色
  3. 一个Spark作业在YARN上的完整生命周期
  4. deploy-mode:client vs cluster
  5. Container资源分配的细节
  6. 为什么作业一直在ACCEPTED状态排队?
  7. 实战经验:EMR集群的资源规划
  8. 面试高频追问
  9. 实战踩坑:Executor被YARN kill的OOM
  10. 总结

先说结论

YARN是Hadoop的资源管理和作业调度系统。核心由四个角色组成:ResourceManager(全局资源管理者)、NodeManager(单节点资源管理者)、ApplicationMaster(作业协调者)、Container(资源容器)。一个Spark作业提交后,YARN先为它启动一个ApplicationMaster,再由AM向RM申请Container来运行Executor。

作业排队的原因通常是:① 集群总资源不够(CPU/内存打满);② 队列资源用完了(受队列配额限制);③ 资源碎片化(剩余资源太零散无法分配)。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

在某知名出海硬件品牌用EMR时,经常被同事问:'我的Spark作业提交了10分钟了还是ACCEPTED状态,怎么回事?'答案几乎都一样——YARN的资源不够了,你的作业在排队。YARN是Hadoop的资源调度核心,Spark/Hive/Flink的作业都要通过它获取CPU和内存。理解YARN的调度机制,才能回答'为什么排队'、'怎么让我的作业跑得更快'这类问题。

YARN的四个核心角色

角色数量职责类比
ResourceManager (RM)1个(HA可以2个)全局资源管理、作业调度公司的HR总监
NodeManager (NM)每个节点1个管理本节点的资源、启动Container各部门的HR
ApplicationMaster (AM)每个作业1个协调作业的生命周期、申请资源项目经理
Container若干实际运行Task的资源单元(CPU+内存)工位

一个Spark作业在YARN上的完整生命周期

# Spark on YARN的作业提交和执行流程
#
# 1. 客户端提交作业到ResourceManager
#    spark-submit --master yarn --deploy-mode cluster my_job.py
#
# 2. RM在某个NodeManager上启动ApplicationMaster(Spark Driver)
#    AM是一个特殊的Container,负责协调整个作业
#
# 3. AM向RM申请资源(Container)来运行Executor
#    '我需要10个Container,每个4核8GB'
#
# 4. RM根据调度策略分配Container
#    如果资源够:立即分配,Executor启动
#    如果资源不够:排队等待(ACCEPTED状态)
#
# 5. NM在本地启动Container,运行Executor
#    Executor开始执行Task(Map/Reduce/Spark Stage)
#
# 6. 作业完成后AM通知RM,释放所有Container
#    资源归还给集群,下一个排队的作业可以使用

deploy-mode:client vs cluster

模式Driver运行位置适用场景注意事项
client提交作业的机器上开发调试、交互式关闭客户端Driver就挂了
clusterYARN集群的某个NM上生产环境日志在集群上,需要yarn logs查看

实战踩坑:在某元宇宙社交公司,有人用client模式提交了一个生产作业,然后合上笔记本去吃饭了——Driver跑在他的笔记本上,笔记本休眠后Driver挂了,整个作业失败。还有一次更严重的:多个同事都用client模式在跳板机上提交作业,Driver进程把跳板机的内存吃满了,其他人连SSH都登不上去。从那以后我们团队强制规定:生产环境一律用cluster模式。

Container资源分配的细节

# YARN的资源单位:vcore(虚拟CPU核)+ 内存(MB)
#
# 集群总资源 = 所有NM的资源之和
# 例:10台NM,每台32核128GB
# 集群总资源 = 320 vcores + 1280 GB内存
#
# 每个Container的资源范围
yarn.scheduler.minimum-allocation-mb = 1024    # 最小1GB
yarn.scheduler.maximum-allocation-mb = 65536   # 最大64GB
yarn.scheduler.minimum-allocation-vcores = 1   # 最小1核
yarn.scheduler.maximum-allocation-vcores = 16  # 最大16核
 
# Spark作业的资源配置
spark-submit \
  --num-executors 10 \
  --executor-cores 4 \
  --executor-memory 8g \
  --driver-memory 4g \
  my_job.py
# 这个作业需要:10个Executor × (4核+8GB) + 1个Driver(4GB)
# 总计 = 40核 + 84GB(含AM的额外开销)

为什么作业一直在ACCEPTED状态排队?

作业卡在ACCEPTED的三个常见原因:

原因现象排查方法解决方案
集群资源不够所有队列都满了YARN Web UI看总资源使用率等待其他作业完成或扩容
队列配额用完本队列满但其他队列有空余看队列的Used/Max资源调整队列配额或换队列
资源碎片化总资源够但分配不出去看Pending Containers数调小Container粒度或重启NM
AM资源不够AM Container分配不了看AM资源使用量调大AM资源配额
# 排查作业排队的命令
 
# 查看作业状态
yarn application -status application_1234567890_0001
 
# 查看集群资源使用情况
yarn top
# 显示各队列的资源使用率和排队作业数
 
# 查看具体队列的资源详情
yarn queue -status default
 
# YARN Web UI(最直观)
# http://rm-host:8088/cluster
# Cluster Metrics: 总资源、已用资源、可用资源
# Scheduler: 各队列的配额和使用情况

实战经验:EMR集群的资源规划

在某知名出海硬件品牌,EMR集群有20个节点(每台16核64GB),总资源320核1280GB。我们的资源规划:

ETL作业(80%资源):100+个Spark作业每天凌晨1-6点跑,高峰期需要256核+1000GB。我们把ETL队列的容量设为80%。

临时查询(20%资源):白天分析师和开发的Hive/Spark临时查询。队列容量20%,但允许在ETL低峰期弹性使用空闲资源。

核心矛盾:凌晨ETL高峰时所有资源都被占满,如果有紧急的临时查询提交上去只能排队。解决方案是给ETL队列设置了抢占(Preemption)——临时查询队列的资源被ETL占用时,有新的临时查询提交会触发资源回收,ETL作业释放一部分Container给临时查询。延迟约30秒,但比干等好得多。

面试高频追问

追问一:ResourceManager挂了怎么办?

YARN支持RM的高可用(HA)——Active/Standby双RM,通过ZooKeeper选举。Active挂了Standby自动接管。但切换期间(约30秒)新的作业无法提交,已经在运行的作业不受影响(AM和Container继续执行)。这和HDFS的NameNode HA原理类似。

追问二:YARN和Kubernetes有什么区别?

YARN是专为大数据设计的资源调度器,和Hadoop生态深度绑定。K8s是通用的容器编排系统,可以运行任何工作负载。趋势是Spark/Flink越来越多地跑在K8s上而不是YARN上——K8s的弹性伸缩、容器化部署、多租户隔离都比YARN更好。但存量的Hadoop集群大多还在用YARN。

追问三:Spark的Dynamic Allocation是什么?

动态资源分配——Spark作业运行时根据实际需求自动增减Executor数量。空闲的Executor会被回收归还给YARN,忙的时候再申请新的。好处是提高集群利用率(不需要预先申请固定数量的Executor)。在EMR上我们默认开启了Dynamic Allocation,集群利用率从60%提升到85%。

实战踩坑:Executor被YARN kill的OOM

在某知名出海硬件品牌,经常遇到Spark作业跑到一半Executor被YARN kill掉。日志里看到:'Container killed by YARN for exceeding memory limits. 8.5GB of 8GB physical memory used.'

原因:Spark Executor的JVM堆内存设了8GB(--executor-memory 8g),但JVM还有堆外内存(Off-Heap、线程栈等),总物理内存超过了YARN分配的Container限制。YARN默认允许的物理内存 = executor-memory × yarn.nodemanager.vmem-pmem-ratio(默认2.1)。

解决方案:① 调大executor-memory-overhead(从默认的10%调到20%);② 或者调大yarn.nodemanager.vmem-pmem-ratio;③ 根本方案是优化作业减少内存使用(比如Broadcast Join改为Sort Merge Join)。

总结

YARN资源调度面试讲清楚四个角色(RM/NM/AM/Container)和一个完整的作业生命周期(提交→AM启动→申请Container→执行→释放)。排队问题三个原因:集群资源不够、队列配额用完、资源碎片化。能讲出client vs cluster模式的踩坑经历和动态资源分配的效果,面试官会觉得你有实际的YARN运维经验。

下一篇聊YARN的队列管理:两个团队抢资源天天吵架——队列怎么配才合理?

你们YARN集群的资源够用吗?作业经常排队吗?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器