提交了一个Spark作业等了10分钟才跑——YARN资源调度原理
本文目录
先说结论
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就挂了 |
| cluster | YARN集群的某个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年大数据老兵,聊技术、聊职场、聊成长