一文讲清 Spark 集群队列:YARN 多租户、容量隔离与资源共享

Spark 集群中的队列到底管什么?容量配置是否意味着资源被预留?本文从 Spark on YARN 架构出发,讲清队列层级、容量保障、弹性共享、ACL 租户隔离。

Spark on YARN 整体架构

Spark 负责应用内部的计算,YARN 负责跨应用的资源管理。下图以 cluster 模式为例展示核心组件及其关系:

  • ResourceManager 管理整个集群,并由内部 Scheduler 按队列规则分配 Container
  • NodeManager 运行在各工作节点上,负责启动和监控 ApplicationMaster、Executor 等 Container
  • ApplicationMaster 代表单个 Spark 应用申请 Executor 资源,cluster 模式下同时承载 Driver
  • Driver 拆分并调度 Task,Executor 负责实际计算

队列处在架构的什么位置

队列位于 ResourceManager 的 Scheduler 中,控制的是不同应用对 YARN Container 的竞争关系:

text 复制代码
ResourceManager / Scheduler
          │
          ├── 分配首个 Container → NodeManager 启动 ApplicationMaster
          │
          └── 响应 ApplicationMaster 的资源请求
                        ↓
               分配 Executor Container
                        ↓
               NodeManager 启动 Executor

资源申请与任务执行的顺序如下:

  1. ApplicationMaster 自身先运行在 YARN 分配的 AM Container 中
  2. ApplicationMaster 根据应用需求,向 ResourceManager 申请 Executor Container
  3. Scheduler 按队列规则检查资源上限,并决定是否为应用分配这些 Container
  4. 获得分配后,ApplicationMaster 通知相应的 NodeManager 启动 Executor
  5. Driver 再把 Spark Task 分发给 Executor 执行

因此,队列约束的是整个应用占用的 YARN 资源,包括 ApplicationMaster 和 Executor 使用的 Container;队列不直接调度 Spark Task

需要特别区分 Spark 内部调度与集群资源调度:

概念 作用范围 常见配置
YARN 队列 多个应用之间的集群资源分配 spark.yarn.queue、CapacityScheduler 队列配置
Spark 作业调度 同一个 SparkContext 内多个 Job 之间的调度 spark.scheduler.mode=FIFO/FAIR

两者都可能出现 FIFO 或 Fair 等词语,但不是同一层的调度

YARN 如何通过队列实现多租户

YARN 多租户通常把团队、业务或环境映射到一棵层级队列树中,例如:

text 复制代码
root
├── prod       生产任务
│   ├── etl    离线加工
│   └── report 报表任务
└── dev        开发与临时查询

只有叶子队列接收应用,父队列主要负责聚合和约束其子队列的资源

YARN 调度器对比

调度器 核心方式 适用场景
FIFO Scheduler 主要按应用提交顺序调度,治理能力较弱 单用户、测试或非常简单的集群
CapacityScheduler 使用层级队列、容量保障、最大容量、ACL 和弹性共享 多团队共享的生产集群
Fair Scheduler 通过权重和最小份额,让活跃应用或队列趋向公平共享资源 已采用 Fair Scheduler 的存量集群

生产环境通常重点关注 CapacityScheduler。具体默认值和可用能力受 Hadoop 版本及发行版影响,应以当前集群配置为准

CapacityScheduler 的关键参数

以下参数位于 capacity-scheduler.xml

参数 含义
yarn.scheduler.capacity.<queue-path>.capacity 队列相对于父队列的保证容量
yarn.scheduler.capacity.<queue-path>.maximum-capacity 队列弹性扩张后的最大容量
yarn.scheduler.capacity.<queue-path>.acl_submit_applications 允许提交应用的用户和用户组
yarn.scheduler.capacity.<queue-path>.acl_administer_queue 允许管理队列及其中应用的用户和用户组
yarn.scheduler.capacity.<queue-path>.minimum-user-limit-percent 根据活跃用户数计算单用户资源限制时使用的下限
yarn.scheduler.capacity.<queue-path>.user-limit-factor 单用户最多可使用队列保证容量的倍数 user-limit-factor=2 的含义不是"每个用户固定获得两倍资源",而是单个用户在资源空闲且其他约束允许时,最多可以使用队列保证容量的 2 倍
yarn.scheduler.capacity.<queue-path>.state 队列状态,可设为 RUNNINGSTOPPED

容量配置模式

CapacityScheduler 的四种基础容量配置方式都使用参数:capacity 表示队列的保证容量,或者计算保证容量的依据。

text 复制代码
yarn.scheduler.capacity.<queue-path>.capacity

限制队列弹性扩张后的资源上限,则统一使用 maximum-capacity

text 复制代码
yarn.scheduler.capacity.<queue-path>.maximum-capacity

调度器根据参数值的格式判断容量模式:

模式 capacity 示例 含义 maximum-capacity 写法
百分比模式 30 队列获得父队列 30% 的保证容量,同一父队列下的子队列容量之和必须为 100% 使用百分比,例如 90
权重模式 2w 根据该队列权重占所有兄弟队列权重之和的比例计算容量,新增队列时不需要重新计算所有百分比 仍使用百分比,不支持"最大权重"
绝对资源模式 [memory=10240,vcores=12] 为队列配置固定的内存和 vCore 保证量,集群扩容后不会按比例自动增加 使用绝对资源值,例如 [memory=20480,vcores=24]
Universal Capacity Vector [memory=50%,vcores=2w,gpu=1] 不同资源维度可以分别使用百分比、权重或绝对资源值 同样使用混合向量,按资源维度分别设置上限

较新的 Hadoop 版本支持 Universal Capacity Vector。它不是新的基础模式,而是允许不同资源维度在同一个 capacitymaximum-capacity 参数中混合使用上述三种方式:

  • 启用传统的 legacy queue mode 时,同一父队列下的子队列需要使用一致的容量模式

  • 关闭后可以更灵活地混合配置。具体能力受 Hadoop 版本及发行版影响,修改前应先确认当前集群版本

xml 复制代码
<property>
  <name>yarn.scheduler.capacity.legacy-queue-mode.enabled</name>
  <value>false</value>
</property>

<property>
  <name>yarn.scheduler.capacity.root.prod.capacity</name>
  <value>[memory=50%,vcores=2w,gpu=1]</value>
</property>

该配置表示内存使用父队列的 50%,vCore 按权重 2 分配,并为队列配置 1 个 GPU

一个最小配置示例

示例使用传统的百分比容量模式

下面定义 proddev 两个队列,保证容量之和为 100%,同时允许 prod 在资源空闲时扩张到整个集群的 90%

xml 复制代码
<configuration>
  <property>
    <name>yarn.scheduler.capacity.root.queues</name>
    <value>prod,dev</value>
  </property>

  <property>
    <name>yarn.scheduler.capacity.root.prod.capacity</name>
    <value>70</value>
  </property>
  <property>
    <name>yarn.scheduler.capacity.root.prod.maximum-capacity</name>
    <value>90</value>
  </property>
  <property>
    <name>yarn.scheduler.capacity.root.prod.acl_submit_applications</name>
    <value>alice,bob data-prod</value>
  </property>

  <property>
    <name>yarn.scheduler.capacity.root.dev.capacity</name>
    <value>30</value>
  </property>
  <property>
    <name>yarn.scheduler.capacity.root.dev.maximum-capacity</name>
    <value>100</value>
  </property>
</configuration>

下图展示了该配置中的队列层级、租户准入与资源边界:

YARN ACL 的格式是"逗号分隔的用户列表 + 一个空格 + 逗号分隔的用户组列表"。因此,示例中的 alice,bob data-prod 表示允许用户 alicebob 以及用户组 data-prod

修改基于文件的队列配置后,可执行:

bash 复制代码
yarn rmadmin -refreshQueues

该命令会重新加载队列 ACL、状态和调度器属性。部分厂商发行版可能通过管理平台或配置中心接管这些配置

如何把任务提交到指定队列

Spark on YARN

推荐在 spark-submit 时显式指定队列:

bash 复制代码
spark-submit \
  --master yarn \
  --deploy-mode cluster \
  --queue prod \
  --class com.example.Main \
  app.jar

等价的 Spark 配置项是:

text 复制代码
spark.yarn.queue=prod

如果没有指定,Spark 默认提交到名为 default 的 YARN 队列

MapReduce on YARN

MapReduce 使用下面的配置项指定队列:

text 复制代码
mapreduce.job.queuename=prod

可以通过 Hadoop 通用参数、作业配置或代码设置。命令行中 -D 参数的具体位置取决于作业入口是否正确使用了 Hadoop ToolRunner

Hive、Flink、Spark 和 MapReduce 只要运行在 YARN 上,最终都受 YARN 队列约束,但提交参数由各引擎决定

  • Hive 使用 MapReduce 引擎时通常设置 mapreduce.job.queuename
  • Hive 使用 Tez 引擎时通常设置 tez.queue.name
  • Spark on YARN 使用 spark.yarn.queue
  • Flink on YARN 使用对应版本的 YARN 队列提交参数

空闲队列是否占用 CPU 或内存

不占用。队列的容量是调度规则,不是提前创建出来的一块物理 CPU 或内存

状态 实际资源行为
队列无应用 没有因为该队列启动的 Container,CPU 和内存占用为零
队列有应用且未超过保证容量 调度器按规则为应用分配 Container
其他队列空闲 活跃队列可以在 maximum-capacity 等约束内借用空闲资源
原队列重新产生需求 是否主动收回已借出的资源取决于是否启用了抢占策略

这里最容易混淆的是"容量保障"和"资源预留":

  • capacity 表示资源紧张时调度器希望保障的份额,不代表空闲时永久占住这些资源
  • maximum-capacity 表示队列能扩张到的上限,不代表队列一定会获得这么多资源
  • 未启用抢占时,借出的资源通常要等已有 Container 释放后才能重新分配
  • 启用 CapacityScheduler 抢占策略后,调度器才可能通过回收 Container 逐步恢复容量保障

因此,"集群满载后各队列一定立刻回归保证容量"是不准确的,资源回归速度受抢占配置、自然释放、应用资源请求和调度周期共同影响

Spark on Kubernetes 有没有队列

原生 Kubernetes

Spark on Kubernetes 默认把 Driver 和 Executor 作为 Pod 交给 Kubernetes 调度器。原生 Kubernetes 提供以下治理手段:

  • Namespace 用于组织和权限隔离
  • ResourceQuota 和 LimitRange 用于限制资源创建与使用
  • PriorityClass 和抢占用于表达 Pod 优先级
  • Node Selector、Affinity、Taint 和 Toleration 用于控制 Pod 放置位置

这些能力并不直接等价于 YARN 的层级队列。特别是 ResourceQuota 主要负责限制和拒绝超额资源请求,本身不提供完整的作业级排队、公平共享和队列容量借用语义

引入批处理调度组件

如果需要接近 YARN 队列的体验,可以使用额外组件:

组件 作用
Volcano 为批处理负载提供队列、优先级、资源预留和 Gang Scheduling 等能力
Apache YuniKorn 提供层级队列、公平性、最小或最大容量和灵活排序策略
Kueue 在作业创建 Pod 前执行准入与排队,使用 ClusterQueueLocalQueueResourceFlavor 管理配额

Apache Spark 从 3.3.0 开始支持把 Volcano 作为自定义 Kubernetes 调度器,也支持对接 Apache YuniKorn。它们都需要单独安装和显式配置,并不是 Spark on Kubernetes 的默认调度器

YARN 队列与 Kubernetes 方案对照

YARN Kubernetes 侧近似概念 说明
层级队列 YuniKorn Queue、Kueue ClusterQueue 与 LocalQueue、Volcano Queue 由额外调度或准入组件提供
队列容量 ResourceQuota 或批处理调度器配额 ResourceQuota 只有硬限制,不等于弹性队列
YARN Container Pod 实际承载 CPU、内存等资源的运行单元
Node Label Node Label、Affinity、Taint 控制工作负载可使用的节点或资源类型
应用抢占 Pod Priority、Preemption 或批处理调度器抢占 行为和粒度因调度器而异

核心结论

集群中的"队列"不是 MapReduce 或 Spark 执行引擎自身提供的计算能力,而是资源管理器或批处理调度器提供的资源治理能力

  • Spark on YARN 和 MapReduce on YARN 的队列由 YARN ResourceManager 中的调度器管理
  • 队列是逻辑资源容器,用于定义容量、上限、权限、优先级和应用排序规则
  • 空闲队列不启动 Container,因此不会因为"配置了容量"就占用 CPU 或内存
  • 空闲队列的容量通常可以被其他队列弹性使用,但是否以及何时收回借出的资源,取决于上限和抢占配置
  • Spark on Kubernetes 默认由 Kubernetes 调度 Pod,原生调度机制不等同于 YARN 队列
  • Spark on Kubernetes 如需作业排队、公平共享和队列配额,可引入 Volcano、Apache YuniKorn、Kueue 等批处理调度或准入组件

参考资料


✨ 微信公众号【凉凉的知识库】同步更新,欢迎关注获取最新最有用的知识 ✨

相关推荐
极新1 小时前
有怡科技携全球首款可变形本质人形机器人亮相2026世界机器人大会
大数据·科技·机器人
BYSJMG1 小时前
大数据毕业设计选题方向|【基于大数据的燃油消耗数据可视化与分析】Hadoop+PySpark+FP-Growth
大数据·hadoop·分布式·信息可视化·数据分析·课程设计
cspttty1 小时前
会计专业大学期间考什么证
大数据·数据库·人工智能·数据挖掘
markvivv2 小时前
【译】适合在RTX 5090、DGX Spark或类似机器上可运行的最佳新模型是什么?
大数据·人工智能·spark
阿童木写作2 小时前
2026年8月跨境电商批量翻译工具推荐实战指南
大数据·跨境电商批量跨境翻译工具推荐
找方案2 小时前
Seedance 2.5突破30秒视频生成,AI视频赛道进入工业化时代
大数据·人工智能·字节跳动·可灵·ai视频生成·seedance2.5·工业化时代
FYKJ_20102 小时前
django学习成绩预警系统10905
java·javascript·spring boot·python·spark·django·php
数据智研3 小时前
【数据分享】中国农产品价格调查年鉴(2004-2025)
大数据·人工智能·数据分析·可视化·数据可视化
逸Y 仙X3 小时前
Spark SQL
java·大数据·sql·spark