想象一下,你管理着一个繁忙的“计算资源中央厨房”。各种“菜肴”(大数据作业)源源不断地涌来,有的需要大火快炒(CPU密集型),有的需要文火慢炖(长时间运行),而厨房里的灶台(服务器)、厨师(CPU)、案板(内存)是有限的。如何公平、高效地安排这些任务,让厨房既不闲置,也不拥堵到崩溃?这就是YARN(Yet Another Resource Negotiator)要解决的核心问题。

今天,我们就来聊聊,如何在实际生产环境中,把这个“中央厨房”的调度规则配置得既高效又稳定。

一、先理解YARN的“调度哲学”:三种调度器怎么选?

YARN提供了三位主要的“调度经理”,各有各的脾气。

1. FIFO调度器(先来先服务) 就像排队买票,谁先来谁先被服务。简单粗暴,但问题很大:一个耗时超长的大任务(比如一个要跑10小时的作业)堵在前面,后面所有紧急的小任务都得干等着。生产环境基本不用它,这里只做了解。

2. 容量调度器(Capacity Scheduler) 这是最常用、最经典的“经理”。它的思想是“划地盘”。把整个集群资源划分成多个队列,每个队列被分配一定比例的资源保证。比如,你可以设置:

  • prod队列:占60%资源,给高优先级的线上生产作业用。
  • dev队列:占30%资源,给开发和测试作业用。
  • default队列:占10%资源,兜底用。

每个队列内部,默认还是FIFO,但你可以配置每个队列能使用的资源上限、单个用户能使用的资源上限等。它的优点是资源隔离性好,能保证重要业务总有资源可用,不会互相挤占。缺点是配置相对繁琐,资源在队列间是静态划分的,可能造成浪费(比如prod队列空闲时,dev队列无法借用其资源,除非开启特性)。

3. 公平调度器(Fair Scheduler) 这位“经理”的理念是“动态公平”。它也有队列的概念,但它不预先给队列划死地盘,而是追求在所有运行中的作业之间动态地平均分配资源

  • 当一个超大作业单独运行时,它能获得全部资源。
  • 当一个小作业提交进来时,调度器会迅速从大作业那里“抢”一部分资源(称为“抢占”)分给小作业,最终让每个作业都能获得大致相等的资源份额(或按权重分配)。
  • 如果队列空了,其他队列可以占用其资源。

它的优点是弹性好,资源利用率高,小作业响应快**。缺点是配置复杂,频繁的资源“抢占”行为可能带来额外开销。

生产环境选择建议:对于业务稳定、优先级分明、需要强资源保障的环境(如金融、核心报表),容量调度器是稳妥之选。对于业务多变、作业大小差异大、追求集群整体利用率的环境(如互联网数据分析),公平调度器更具优势。我们接下来的示例将以容量调度器为主,因为它的配置最能体现精细化的控制思想。

二、核心配置实战:给容量调度器“定规矩”

我们假设一个生产场景:公司有一个大数据集群,需要同时服务于A部门的实时推荐作业(要求快速响应)和B部门的夜间批量ETL作业(吞吐量大,但可接受排队)。我们使用Hadoop 3.x技术栈进行配置。

示例1:配置核心调度器类型与根队列

技术栈:Hadoop 3.x 文件:capacity-scheduler.xml

<!-- 指定使用容量调度器 -->
<property>
    <name>yarn.resourcemanager.scheduler.class</name>
    <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
    <description>这是最关键的一步,告诉YARN请容量调度器“经理”上岗。</description>
</property>

<!-- 定义根队列下的子队列 -->
<property>
    <name>yarn.scheduler.capacity.root.queues</name>
    <value>realtime,batch,default</value>
    <description>在根队列(root)下创建三个子队列:实时队列、批量队列和默认兜底队列。</description>
</property>

<!-- 设置各队列的资源容量(百分比) -->
<property>
    <name>yarn.scheduler.capacity.root.realtime.capacity</name>
    <value>40</value>
    <description>实时队列获得集群40%的资源保障。</description>
</property>
<property>
    <name>yarn.scheduler.capacity.root.batch.capacity</name>
    <value>50</value>
    <description>批量队列获得集群50%的资源保障。</description>
</property>
<property>
    <name>yarn.scheduler.capacity.root.default.capacity</name>
    <value>10</value>
    <description>默认队列获得10%的资源保障。</description>
</property>

<!-- 设置各队列可使用的资源上限(可超过容量,用于弹性) -->
<property>
    <name>yarn.scheduler.capacity.root.realtime.maximum-capacity</name>
    <value>60</value>
    <description>实时队列最多可以使用集群60%的资源,在批量队列空闲时可以“借”用。</description>
</property>
<property>
    <name>yarn.scheduler.capacity.root.batch.maximum-capacity</name>
    <value>100</value>
    <description>批量队列最多可以使用全部资源,在夜间可以充分利用集群。</description>
</property>

示例2:配置用户限制与访问控制

不能让人“撑死”,也不能让未授权的人进来。

技术栈:Hadoop 3.x 文件:capacity-scheduler.xml (续)

<!-- 限制单个用户在实时队列中的资源使用上限 -->
<property>
    <name>yarn.scheduler.capacity.root.realtime.user-limit-factor</name>
    <value>1</value>
    <description>设置为1,表示单个用户最多只能使用该队列100%的资源(即整个队列的容量)。防止一个人占满整个实时队列。</description>
</property>

<!-- 设置队列的管理员(或提交用户) -->
<property>
    <name>yarn.scheduler.capacity.root.realtime.acl_submit_applications</name>
    <value>realtime_user, hadoop_admin</value>
    <description>允许用户realtime_user和管理员hadoop_admin向实时队列提交作业。这是重要的权限控制。</description>
</property>
<property>
    <name>yarn.scheduler.capacity.root.realtime.acl_administer_queue</name>
    <value>hadoop_admin</value>
    <description>只有hadoop_admin用户可以管理(如终止作业)实时队列。权限要收窄。</description>
</property>

示例3:配置容器资源与抢占(高级特性)

YARN中资源的基本单位是容器,我们需要定义其最小和最大规格。同时,为了避免低优先级队列长期占用资源,可以开启“抢占”。

技术栈:Hadoop 3.x 文件:yarn-site.xmlcapacity-scheduler.xml

<!-- 在 yarn-site.xml 中设置容器相关参数 -->
<property>
    <name>yarn.scheduler.minimum-allocation-mb</name>
    <value>1024</value>
    <description>单个容器可申请的最小内存,设为1GB。申请量必须是它的整数倍。</description>
</property>
<property>
    <name>yarn.scheduler.maximum-allocation-mb</name>
    <value>16384</value>
    <description>单个容器可申请的最大内存,设为16GB。防止单个任务申请过多内存。</description>
</property>
<property>
    <name>yarn.scheduler.minimum-allocation-vcores</name>
    <value>1</value>
    <description>单个容器可申请的最小虚拟CPU核数。</description>
</property>
<property>
    <name>yarn.scheduler.maximum-allocation-vcores</name>
    <value>8</value>
    <description>单个容器可申请的最大虚拟CPU核数。</description>
</property>

<!-- 在 capacity-scheduler.xml 中开启资源抢占 -->
<property>
  <name>yarn.resourcemanager.scheduler.monitor.enable</name>
  <value>true</value>
  <description>启用调度器监控,这是抢占功能的基础。</description>
</property>
<property>
  <name>yarn.resourcemanager.scheduler.monitor.policies</name>
  <value>org.apache.hadoop.yarn.server.resourcemanager.monitor.capacity.ProportionalCapacityPreemptionPolicy</value>
  <description>使用按比例容量抢占策略。当高优先级队列(如realtime)资源不足时,会从低优先级队列(如batch)中抢占容器。</description>
</property>

三、如何提交作业到指定队列?

配置好了,怎么用呢?我们在提交作业时(比如Spark或MapReduce)需要显式指定队列名。

示例4:提交Spark作业到指定队列

技术栈:Hadoop 3.x + Spark

# 使用 spark-submit 提交作业时,通过 --queue 参数指定队列
spark-submit \
    --master yarn \
    --deploy-mode cluster \
    --queue realtime \  # 关键!指定作业提交到“realtime”队列
    --driver-memory 2g \
    --executor-memory 4g \
    --num-executors 10 \
    /path/to/your-spark-job.jar

# 如果是MapReduce作业,使用 -D 参数设置
hadoop jar your-mapreduce-job.jar \
    -D mapreduce.job.queuename=batch \  # 关键!指定作业提交到“batch”队列
    MainClass input output

四、生产环境配置的“心法”与避坑指南

光有配置示例还不够,理解背后的“心法”和避坑点更重要。

1. 资源规划是前提

  • 不要拍脑袋:配置队列容量前,先用监控工具(如Ambari, Grafana + Prometheus)分析历史作业的资源需求峰值、均值、时间段分布。
  • 留足缓冲:永远不要将capacity之和配成100%,建议留出5-10%给系统进程和冗余。maximum-capacity可以设为100%以实现弹性。

2. 警惕“僵尸容器”与资源碎片

  • 场景:作业申请了资源但启动失败,或者任务结束但资源没有及时释放,导致资源被无效占用。
  • 对策:合理设置yarn.nodemanager.resource.memory-mbyarn.nodemanager.resource.cpu-vcores(在yarn-site.xml中),确保NodeManager汇报的资源准确。并配置yarn.nodemanager.container-monitor.interval-ms等健康检测参数,及时清理失效容器。

3. 队列层级不宜过深

  • 容量调度器支持多级队列(如root.prod.hive, root.prod.spark),但层级过深会增加调度复杂度和管理成本。通常2-3级足够(如root.部门.业务)。

4. 监控与动态调整

  • 必须配置监控:密切关注各队列的资源使用率、待处理作业数、容器等待时间等指标。
  • 配置不是一成不变的:随着业务变化,可能需要动态调整队列容量。YARN支持运行时动态修改部分队列参数(通过yarn rmadmin -refreshQueues命令),这比重启ResourceManager要友好得多。

5. 关联技术:资源管理器(ResourceManager)高可用 YARN调度器运行在ResourceManager(RM)上。单点RM是生产环境的大忌!必须启用RM高可用(HA)。

  • 原理:部署两个或多个RM节点,一个Active,其他Standby。通过ZooKeeper进行主节点选举和状态同步。当Active RM挂掉时,Standby RM能秒级切换,继续提供服务,作业不会中断。
  • 配置要点:在yarn-site.xml中设置yarn.resourcemanager.ha.enabledyarn.resourcemanager.ha.rm-ids以及ZooKeeper相关地址。

五、总结:让调度为业务服务

YARN的配置是一门平衡的艺术,需要在资源保障、利用率、公平性和响应速度之间找到最佳结合点。

  • 应用场景:适用于任何需要统一管理跨多个框架(如MapReduce, Spark, Flink, Tez)计算资源的大数据平台。是Hadoop 2.0及以后生态的“基石”。
  • 技术优缺点
    • 优点:解耦了资源管理与作业逻辑,支持多租户、资源隔离、弹性伸缩,社区成熟稳定。
    • 缺点:原生调度器(容量/公平)对于超大规模集群(万台以上)或极端复杂的调度策略(如严格依赖关系的DAG作业)可能力有不逮,有时需要定制化开发或结合像Kubernetes这样的更底层调度器。
  • 注意事项:再次强调,做好资源评估、启用RM高可用、建立监控告警体系、理解抢占机制的影响,并根据业务反馈进行迭代调整

最好的配置,永远是那个最贴合你当前业务流量和未来发展的配置。开始时可以相对保守,划分清晰的队列并设置保障,随着对系统行为的深入了解,再逐步引入弹性、抢占等高级特性,让这个“中央厨房”日益智能和高效。