YARN 全称为 Yet Another Resource Negotiator,是 Hadoop 2.x 引入的通用资源管理与任务调度框架。它将集群资源管理与具体计算逻辑解耦,使 MapReduce、Spark、Flink、Tez 等计算框架能够共享同一个集群。

1. YARN 是什么

YARN 是 Apache Hadoop 的资源管理和任务调度系统。

它主要负责两件事情:

  1. 管理集群中的 CPU、内存等计算资源。
  2. 根据应用提交的资源请求,为应用分配运行资源。

YARN 本身并不关心应用具体执行的是 SQL、MapReduce、Spark 任务还是 Flink 作业。它只负责管理资源,以及为应用分配 Container。

从职责上看,可以将 YARN 理解为一个分布式操作系统:

  • ResourceManager 类似操作系统内核中的资源管理器。
  • NodeManager 类似每台服务器上的本地资源代理。
  • ApplicationMaster 类似应用自己的进程管理器。
  • Container 类似受资源限制的进程运行环境。

YARN 支持的计算框架包括:

  • Hadoop MapReduce
  • Apache Spark
  • Apache Flink
  • Apache Tez
  • Apache Hive
  • Apache HBase 辅助任务
  • 自定义分布式应用

YARN 的核心价值是:

将集群资源管理能力与具体计算框架解耦,让多种计算框架共享同一套集群资源。


2. 为什么需要 YARN

在 Hadoop 1.x 中,MapReduce 同时承担资源管理和计算任务调度职责。

Hadoop 1.x 的核心组件包括:

  • JobTracker
  • TaskTracker

JobTracker 既要管理集群资源,又要负责 MapReduce 任务的调度、监控和失败重试。

这会带来几个问题。

2.1 JobTracker 压力过大

所有任务的信息都集中在 JobTracker 中管理。

当集群规模扩大、任务数量增加时,JobTracker 容易成为性能瓶颈和单点故障点。

2.2 资源模型过于固定

Hadoop 1.x 使用固定数量的 Map Slot 和 Reduce Slot 表示资源。

例如,一台服务器可能配置:

  • 8 个 Map Slot
  • 4 个 Reduce Slot

当集群中只有 Map 任务时,空闲的 Reduce Slot 无法直接分配给 Map 任务,容易造成资源浪费。

2.3 只能运行 MapReduce

Hadoop 1.x 的资源管理系统与 MapReduce 强耦合,其他计算框架难以直接复用 Hadoop 集群。

2.4 YARN 的解决方案

YARN 将原来 JobTracker 的职责拆分为:

  • ResourceManager:管理整个集群的资源。
  • ApplicationMaster:管理单个应用的执行过程。

拆分后的架构具有以下优势:

  • 降低中心节点压力。
  • 支持更加灵活的资源模型。
  • 支持多种计算框架。
  • 提高集群资源利用率。
  • 提高系统扩展能力。
  • 支持队列、容量、公平性等多种调度策略。

3. YARN 的整体架构

YARN 的核心架构由以下组件组成:

  1. ResourceManager
  2. NodeManager
  3. ApplicationMaster
  4. Container
  5. Client

整体关系如下:

客户端 Client

ResourceManager

Scheduler

ApplicationsManager

NodeManager 1

NodeManager 2

NodeManager 3

ApplicationMaster

Container

Container

Container

各个组件的职责如下:

组件作用
ResourceManager管理整个集群资源,并进行资源调度
NodeManager管理单个节点上的资源和 Container
ApplicationMaster管理单个应用的生命周期
Container应用实际运行时占用的资源单位
Client提交、查询和停止应用
Scheduler根据调度策略分配集群资源

YARN 采用“一个全局管理器加多个节点管理器”的结构:

  • 集群通常有一个处于 Active 状态的 ResourceManager。
  • 每台工作节点上运行一个 NodeManager。
  • 每个应用一般拥有自己的 ApplicationMaster。
  • 一个应用可以运行多个 Container。

4. YARN 的核心概念

4.1 Application

Application 表示提交给 YARN 的一个完整应用。

例如:

  • 一个 MapReduce 作业
  • 一个 Spark 应用
  • 一个 Flink Session Cluster
  • 一个 Hive on Tez 查询

每个应用都有唯一的 Application ID,例如:

application_1723456789000_0012

Application ID 通常由两部分组成:

application_<ResourceManager启动时间戳>_<应用序号>

4.2 ApplicationAttempt

ApplicationMaster 可能因为节点故障、进程崩溃等原因重新启动。

每启动一次 ApplicationMaster,就会产生一个新的 ApplicationAttempt。

示例:

appattempt_1723456789000_0012_000001

因此,一个 Application 可能对应多个 ApplicationAttempt。

4.3 Container

Container 是 YARN 中最基本的资源分配单位。

一个 Container 通常包含:

  • 一定数量的内存
  • 一定数量的虚拟 CPU 核心
  • 可选的 GPU、FPGA 等扩展资源
  • Container 启动命令
  • 环境变量
  • 本地化文件
  • 安全令牌

需要注意:

YARN Container 是一种资源抽象,不等同于 Docker 容器。

YARN 可以直接启动普通操作系统进程,也可以通过 LinuxContainerExecutor、Docker Runtime 等方式增强资源隔离。

4.4 ResourceRequest

ApplicationMaster 通过 ResourceRequest 向 ResourceManager 申请资源。

资源请求通常包含:

  • 资源数量
  • 内存大小
  • vCore 数量
  • 优先级
  • 节点位置偏好
  • 机架位置偏好
  • 节点标签要求

4.5 Queue

Queue 是 YARN 调度器中的逻辑资源分组。

企业可以按照部门、项目或环境划分队列,例如:

root
├── production
│   ├── realtime
│   └── offline
├── development
└── test

队列可以配置:

  • 保证容量
  • 最大容量
  • 用户权限
  • 应用数量限制
  • ApplicationMaster 资源占比
  • 节点标签访问权限
  • 用户资源限制

5. YARN 应用的完整运行流程

一个应用从提交到完成,通常经历以下过程。

5.1 客户端准备应用

客户端首先准备应用运行所需的信息,例如:

  • 应用名称
  • 提交队列
  • ApplicationMaster 启动命令
  • ApplicationMaster 所需资源
  • 依赖文件
  • 配置文件
  • 安全令牌
  • 环境变量

5.2 客户端申请 Application ID

客户端向 ResourceManager 申请一个新的 Application ID。

ResourceManager 返回应用相关信息,包括允许申请的最大资源能力。

5.3 上传应用资源

客户端将应用依赖上传到共享文件系统,通常是 HDFS。

上传内容可能包括:

  • JAR 文件
  • 配置文件
  • Python 文件
  • 归档文件
  • ApplicationMaster 所需依赖

5.4 提交应用

客户端调用 ResourceManager 的应用提交接口,提交 ApplicationSubmissionContext。

ResourceManager 接收到应用后,会执行:

  1. 校验用户权限。
  2. 检查队列是否存在。
  3. 检查资源请求是否合法。
  4. 保存应用状态。
  5. 将应用交给调度器。

5.5 分配 ApplicationMaster Container

调度器为 ApplicationMaster 分配第一个 Container。

该 Container 也被称为:

AM Container

5.6 启动 ApplicationMaster

ResourceManager 通知目标节点上的 NodeManager 启动 AM Container。

NodeManager 会:

  1. 下载应用依赖。
  2. 创建工作目录。
  3. 设置环境变量。
  4. 准备安全令牌。
  5. 执行 ApplicationMaster 启动命令。

5.7 ApplicationMaster 注册

ApplicationMaster 启动后,向 ResourceManager 注册自己。

注册成功后,ResourceManager 开始接受该 ApplicationMaster 的资源申请。

5.8 ApplicationMaster 申请资源

ApplicationMaster 根据应用执行计划向 ResourceManager 申请 Container。

例如,一个 Spark 应用可能申请:

  • 10 个 Executor Container
  • 每个 Container 4 GB 内存
  • 每个 Container 2 个 vCore

5.9 ResourceManager 分配 Container

Scheduler 根据以下因素进行分配:

  • 队列容量
  • 当前空闲资源
  • 应用优先级
  • 用户资源限制
  • 数据本地性
  • 节点标签
  • 资源请求大小

5.10 ApplicationMaster 启动任务

ApplicationMaster 收到 Container 分配结果后,联系对应的 NodeManager 启动 Container。

Container 中实际运行:

  • Map Task
  • Reduce Task
  • Spark Executor
  • Tez Task
  • 自定义计算进程

5.11 运行状态监控

运行期间:

  • NodeManager 向 ResourceManager发送节点心跳。
  • ApplicationMaster 向 ResourceManager 发送应用心跳。
  • Container 向 ApplicationMaster 汇报任务状态。
  • NodeManager 监控 Container 的资源使用情况。

5.12 应用完成

所有任务执行完成后,ApplicationMaster:

  1. 向 ResourceManager 注销。
  2. 上报最终应用状态。
  3. 清理临时资源。
  4. 结束自身进程。

应用最终状态可能包括:

  • FINISHED
  • FAILED
  • KILLED

完整流程如下:

Task ContainerApplicationMasterNodeManagerResourceManagerClientTask ContainerApplicationMasterNodeManagerResourceManagerClient申请 Application ID返回 Application ID上传依赖到 HDFS提交应用分配并启动 AM Container启动 ApplicationMaster注册 ApplicationMaster申请任务 Container返回 Container 分配结果请求启动任务 Container启动任务汇报执行状态注销并上报最终状态返回应用结果

6. ResourceManager 工作原理

ResourceManager 是 YARN 集群的全局资源管理组件。

它主要包含两个核心模块:

  1. ApplicationsManager
  2. Scheduler

6.1 ApplicationsManager

ApplicationsManager 负责管理应用生命周期,包括:

  • 接收客户端提交的应用。
  • 为 ApplicationMaster 申请首个 Container。
  • 启动 ApplicationMaster。
  • 监控 ApplicationMaster 状态。
  • 在 ApplicationMaster 失败后进行重试。
  • 保存和恢复应用状态。

ApplicationsManager 不负责应用内部任务的具体调度。

例如,Spark Executor 如何分配、MapReduce Task 如何重试,通常由各自的 ApplicationMaster 负责。

6.2 Scheduler

Scheduler 负责根据集群资源和调度规则为应用分配 Container。

Scheduler 的特点是:

  • 只负责资源分配。
  • 不负责启动任务。
  • 不负责监控任务执行逻辑。
  • 不处理应用内部失败恢复。
  • 按照队列、优先级、资源需求进行调度。

6.3 ResourceManager 维护的信息

ResourceManager 需要维护:

  • NodeManager 列表
  • 节点可用资源
  • 节点健康状态
  • 应用列表
  • ApplicationAttempt 状态
  • 队列资源使用情况
  • Container 分配关系
  • 用户资源使用情况

6.4 心跳机制

NodeManager 会周期性向 ResourceManager 发送心跳。

心跳内容通常包括:

  • 节点健康状态
  • 已使用资源
  • 可用资源
  • Container 运行状态
  • 已完成 Container
  • 节点标签
  • 本地化资源状态

ResourceManager 根据心跳判断节点是否可用。

如果长时间没有收到某个 NodeManager 的心跳,会将该节点标记为丢失,并重新处理该节点上运行的应用和 Container。


7. NodeManager 工作原理

NodeManager 运行在集群中的每一台工作节点上。

它负责管理本节点的资源和 Container。

7.1 NodeManager 的主要职责

NodeManager 负责:

  • 向 ResourceManager 注册节点。
  • 周期性发送心跳。
  • 接收 Container 启动请求。
  • 下载和本地化应用依赖。
  • 启动、停止和清理 Container。
  • 监控 Container 的 CPU 和内存使用。
  • 收集 Container 日志。
  • 上报 Container 状态。
  • 检查磁盘和节点健康状态。

7.2 Container 启动过程

NodeManager 收到启动请求后,会执行:

  1. 校验 Container Token。
  2. 创建应用目录。
  3. 创建 Container 工作目录。
  4. 下载依赖文件。
  5. 创建启动脚本。
  6. 设置环境变量。
  7. 使用指定用户启动进程。
  8. 监控进程资源使用情况。

Container 的工作目录通常包含:

container-local-dir/
├── launch_container.sh
├── default_container_executor.sh
├── job.jar
├── configuration.xml
├── stdout
├── stderr
└── syslog

具体文件会因计算框架和 Hadoop 版本而不同。

7.3 节点健康检查

NodeManager 会检查:

  • 本地磁盘是否可写。
  • 磁盘剩余空间是否充足。
  • 日志目录是否正常。
  • 自定义健康检查脚本是否执行成功。
  • 节点是否超过故障磁盘比例。

如果节点被标记为不健康,ResourceManager 通常不会继续向该节点分配新的 Container。


8. ApplicationMaster 工作原理

ApplicationMaster 是每个 YARN 应用自己的管理进程。

不同计算框架拥有不同的 ApplicationMaster 实现。

例如:

计算框架ApplicationMaster
MapReduceMRAppMaster
SparkSpark ApplicationMaster
TezTez ApplicationMaster
FlinkFlink ResourceManager 或对应 YARN 入口组件

8.1 ApplicationMaster 的主要职责

ApplicationMaster 负责:

  • 向 ResourceManager 注册应用。
  • 根据任务需求申请 Container。
  • 与 NodeManager 通信。
  • 启动计算任务。
  • 监控任务执行状态。
  • 处理任务失败。
  • 调整资源请求。
  • 上报应用进度。
  • 应用完成后注销。

8.2 ApplicationMaster 不是全局组件

每个应用都有自己的 ApplicationMaster,因此一个集群中可能同时存在大量 ApplicationMaster。

这种设计将应用内部调度压力分散到各个节点,避免 ResourceManager 处理所有任务级别的细节。

8.3 ApplicationMaster 失败

如果 ApplicationMaster 所在节点故障,ResourceManager 可以启动新的 ApplicationAttempt。

新的 ApplicationMaster 能否恢复原来的任务状态,取决于具体计算框架是否实现了状态恢复。

需要区分:

  • ApplicationMaster 重试
  • 任务重试
  • 整个应用重新提交

这三者不是同一个概念。


9. Container 资源模型

9.1 内存资源

Container 内存通常以 MB 为单位申请。

例如:

memory = 4096 MB

这表示 Container 最多可以使用约 4 GB 的受管理内存资源。

实际应用中不能只考虑 JVM 堆内存,还需要预留:

  • JVM Metaspace
  • 直接内存
  • 线程栈
  • 本地库内存
  • Python 子进程
  • 网络缓冲区
  • 框架额外开销

可以使用下面的思路估算:

Container 内存
= JVM Heap
+ JVM 非堆内存
+ Direct Memory
+ Native Memory
+ 子进程内存
+ 安全余量

9.2 vCore 资源

vCore 是 YARN 对 CPU 资源的逻辑抽象。

例如:

vcores = 2

表示 Container 申请两个虚拟 CPU 核心。

vCore 不一定与物理 CPU 核心一一对应。实际隔离强度取决于:

  • NodeManager 配置
  • Linux cgroups
  • ContainerExecutor
  • 操作系统调度
  • 集群资源超配策略

9.3 最小资源分配单位

YARN 通常会配置最小资源分配单位:

<property>
    <name>yarn.scheduler.minimum-allocation-mb</name>
    <value>1024</value>
</property>

<property>
    <name>yarn.scheduler.minimum-allocation-vcores</name>
    <value>1</value>
</property>

如果应用申请 1500 MB,而调度器以 1024 MB 为最小增量处理资源,实际资源分配可能向上调整。

因此,Container 规格应尽量与调度器资源粒度对齐,减少碎片。

9.4 最大资源分配

可以限制单个 Container 的最大资源:

<property>
    <name>yarn.scheduler.maximum-allocation-mb</name>
    <value>32768</value>
</property>

<property>
    <name>yarn.scheduler.maximum-allocation-vcores</name>
    <value>16</value>
</property>

如果应用申请超过最大值的 Container,提交或资源申请可能失败。

9.5 扩展资源

较新的 YARN 资源模型可以管理自定义资源,例如:

  • GPU
  • FPGA
  • 高性能网卡
  • 其他专用设备

应用可以在资源请求中声明所需的扩展资源,由调度器选择满足条件的节点。


10. YARN 的资源调度器

YARN 常见的调度器包括:

  1. FIFO Scheduler
  2. CapacityScheduler
  3. FairScheduler

不同 Hadoop 发行版和版本的默认配置可能不同,生产环境应以当前集群配置为准。

10.1 FIFO Scheduler

FIFO Scheduler 按照应用提交顺序进行调度。

特点:

  • 实现简单。
  • 先提交的应用优先获得资源。
  • 不适合多用户共享集群。
  • 大任务可能长时间阻塞后续小任务。

适用于:

  • 小型测试集群
  • 单用户环境
  • 任务类型比较单一的环境

10.2 CapacityScheduler

CapacityScheduler 将集群划分为多个队列,每个队列拥有一定比例的资源容量。

特点:

  • 支持多级队列。
  • 支持队列容量保证。
  • 支持队列最大容量。
  • 支持多租户。
  • 支持用户资源限制。
  • 支持弹性使用空闲资源。
  • 支持访问控制。
  • 支持节点标签。

适用于:

  • 企业级共享集群
  • 多部门环境
  • 需要资源隔离的生产集群

10.3 FairScheduler

FairScheduler 的目标是让应用在一定时间范围内公平共享资源。

当只有一个应用运行时,它可以使用大量集群资源;当其他应用提交后,调度器会逐步调整资源分配,使多个应用趋于公平。

适用于:

  • 多用户分析平台
  • 大量交互式任务
  • 希望减少小任务等待时间的场景

需要注意:

不同 Hadoop 版本和发行版对调度器的支持、默认值及推荐策略可能不同,部署前应检查对应版本文档。


11. CapacityScheduler 容量调度器

CapacityScheduler 是生产环境中常见的 YARN 调度器。

11.1 队列结构

假设企业中有生产、开发和测试三类任务,可以设计如下队列:

root
├── production
│   ├── realtime
│   └── offline
├── development
└── test

对应的基础配置示例:

yarn.scheduler.capacity.root.queues=production,development,test

yarn.scheduler.capacity.root.production.capacity=60
yarn.scheduler.capacity.root.development.capacity=25
yarn.scheduler.capacity.root.test.capacity=15

三个一级队列容量之和应满足调度器的配置要求,常见配置下为:

60 + 25 + 15 = 100

11.2 子队列配置

生产队列继续划分为实时和离线队列:

yarn.scheduler.capacity.root.production.queues=realtime,offline

yarn.scheduler.capacity.root.production.realtime.capacity=40
yarn.scheduler.capacity.root.production.offline.capacity=60

这里的 40 和 60 是相对于 production 队列的比例。

因此:

realtime 的集群保证容量 = 60% × 40% = 24%
offline 的集群保证容量 = 60% × 60% = 36%

11.3 最大容量

队列可以在其他队列空闲时临时使用更多资源。

例如:

yarn.scheduler.capacity.root.development.capacity=25
yarn.scheduler.capacity.root.development.maximum-capacity=50

含义是:

  • 开发队列保证容量为集群资源的 25%。
  • 资源空闲时最多可以使用集群资源的 50%。

11.4 队列权限

可以限制哪些用户能够向队列提交应用:

yarn.scheduler.capacity.root.production.acl_submit_applications=prod_user,prod_group
yarn.scheduler.capacity.root.production.acl_administer_queue=admin

具体用户组语法需要结合当前 Hadoop 版本及权限配置确认。

11.5 用户资源限制

如果一个队列允许多个用户提交应用,还需要限制单个用户独占队列。

常见配置思路包括:

yarn.scheduler.capacity.root.development.minimum-user-limit-percent=25
yarn.scheduler.capacity.root.development.user-limit-factor=2

合理的用户限制可以避免某个用户提交大量任务,导致其他用户无法获得资源。

11.6 ApplicationMaster 资源占比

每个应用都需要启动 ApplicationMaster。

如果同时提交大量应用,ApplicationMaster 可能消耗大量队列资源。

可以通过类似配置限制 AM 资源比例:

yarn.scheduler.capacity.root.maximum-am-resource-percent=0.1

如果该值过小,应用会长时间处于等待 AM 资源的状态;如果过大,又会挤压真正执行任务的 Container。


12. YARN 队列与资源隔离

12.1 保证容量不等于永久预留

队列容量通常表示资源保证,不一定意味着资源永远静态保留。

例如:

  • 队列 A 保证 60%。
  • 队列 B 保证 40%。
  • 当前只有队列 A 有任务。

如果允许弹性使用,队列 A 可以暂时使用超过 60% 的资源。

当队列 B 提交任务后,调度器会逐步回收或重新分配资源。

12.2 抢占机制

当某个队列长期占用其他队列的保证资源时,可以启用抢占机制。

抢占的大致过程是:

  1. 检测队列资源是否低于保证容量。
  2. 等待设定的容忍时间。
  3. 选择需要释放的 Container。
  4. 通知应用释放或直接终止部分 Container。
  5. 将资源重新分配给资源不足的队列。

抢占配置需要谨慎。

过于激进可能造成:

  • 任务频繁重试。
  • Spark Executor 大量丢失。
  • 计算结果延迟。
  • 集群吞吐下降。

12.3 节点标签

Node Label 可以将节点划分为不同资源池。

例如:

high-memory
gpu
ssd
normal

应用或队列可以声明只使用某种标签的节点。

典型场景:

  • Spark 大内存任务只运行在高内存节点。
  • AI 任务只运行在 GPU 节点。
  • 低优先级离线任务运行在普通节点。
  • 特殊业务运行在独立物理资源池。

12.4 资源隔离层次

YARN 的资源隔离通常包含多个层次:

  1. 调度器层面的资源配额。
  2. NodeManager 层面的资源监控。
  3. Linux 用户权限隔离。
  4. cgroups CPU、内存隔离。
  5. Docker 或其他容器运行时隔离。
  6. HDFS、Hive 等数据系统的权限隔离。

仅配置队列容量并不能完成完整的安全隔离。


13. YARN 资源本地化机制

应用依赖通常保存在 HDFS 等共享文件系统中。

Container 启动前,NodeManager 会将依赖下载到本地,这个过程称为资源本地化。

13.1 本地化资源类型

常见资源类型包括:

  • FILE:普通文件
  • ARCHIVE:解压后的归档文件
  • PATTERN:按照指定模式处理的资源

13.2 资源可见范围

资源可以具有不同可见性:

  • PUBLIC:所有用户都可以共享。
  • PRIVATE:同一用户的应用可以共享。
  • APPLICATION:仅当前应用使用。

13.3 本地缓存

NodeManager 会缓存已经下载的资源。

缓存的好处包括:

  • 减少重复下载。
  • 降低 HDFS 压力。
  • 缩短 Container 启动时间。

NodeManager 会根据缓存大小、资源使用状态和清理策略删除旧资源。

13.4 生产注意事项

如果每次提交任务都生成名称不同但内容相同的大型依赖包,会降低缓存命中率。

建议:

  • 保持公共依赖版本稳定。
  • 避免频繁生成无意义的新文件。
  • 控制单个依赖包大小。
  • 使用共享依赖机制。
  • 定期检查本地缓存目录磁盘占用。

14. YARN 高可用与故障恢复

14.1 ResourceManager 高可用

生产集群通常部署两个 ResourceManager:

  • Active ResourceManager
  • Standby ResourceManager

Active 节点负责提供服务,Standby 节点等待接管。

重新注册

Client

Active ResourceManager

Standby ResourceManager

ZooKeeper

NodeManagers

常见配置示例:

<property>
    <name>yarn.resourcemanager.ha.enabled</name>
    <value>true</value>
</property>

<property>
    <name>yarn.resourcemanager.cluster-id</name>
    <value>yarn-cluster</value>
</property>

<property>
    <name>yarn.resourcemanager.ha.rm-ids</name>
    <value>rm1,rm2</value>
</property>

<property>
    <name>yarn.resourcemanager.hostname.rm1</name>
    <value>rm-host-1</value>
</property>

<property>
    <name>yarn.resourcemanager.hostname.rm2</name>
    <value>rm-host-2</value>
</property>

<property>
    <name>yarn.resourcemanager.recovery.enabled</name>
    <value>true</value>
</property>

<property>
    <name>yarn.resourcemanager.store.class</name>
    <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>

<property>
    <name>yarn.resourcemanager.zk-address</name>
    <value>zk1:2181,zk2:2181,zk3:2181</value>
</property>

实际配置还要结合 Hadoop 版本、ZooKeeper、安全认证和网络环境调整。

14.2 ResourceManager 状态存储

为了在故障切换后恢复应用,ResourceManager 需要持久化关键状态,例如:

  • 应用提交信息
  • ApplicationAttempt 信息
  • 安全令牌
  • Delegation Token
  • 队列相关状态

14.3 NodeManager 故障

当 NodeManager 故障时:

  1. ResourceManager 无法继续收到节点心跳。
  2. 节点被标记为 Lost。
  3. 该节点上的 Container 被认为已经丢失。
  4. ApplicationMaster 根据框架策略重新申请资源。
  5. 任务可能在其他节点重新执行。

14.4 ApplicationMaster 故障

ApplicationMaster 失败后,ResourceManager 可以启动新的 ApplicationAttempt。

最大重试次数可以由集群配置和应用自身配置共同影响。

14.5 Container 故障

Container 故障通常由 ApplicationMaster 负责处理。

例如:

  • MapReduce 重新执行失败的 Task。
  • Spark 根据数据血缘重新计算丢失分区。
  • Flink 根据 Checkpoint 恢复任务状态。

15. YARN 安全机制

YARN 的安全不能只依赖操作系统用户,需要与 Hadoop 安全体系共同使用。

15.1 Kerberos 认证

在安全集群中,Kerberos 用于验证用户和服务身份。

常见服务身份包括:

  • ResourceManager Principal
  • NodeManager Principal
  • HTTP Principal
  • JobHistoryServer Principal

15.2 Delegation Token

用户通过 Kerberos 完成初始认证后,长时间运行的应用通常使用 Delegation Token 访问 HDFS 等服务。

这样可以避免应用长期持有用户密码或 Keytab。

15.3 Container Token

ResourceManager 向 ApplicationMaster 分配 Container 时,会生成相应的安全令牌。

NodeManager 根据令牌校验:

  • Container 是否由合法 ResourceManager 分配。
  • 请求是否已过期。
  • Container ID 是否匹配。
  • 资源参数是否被篡改。

15.4 Application ACL

YARN 可以限制哪些用户能够:

  • 查看应用。
  • 修改应用。
  • 停止应用。
  • 查看日志。
  • 管理队列。

15.5 LinuxContainerExecutor

生产环境可以使用 LinuxContainerExecutor,以指定操作系统用户身份启动 Container。

相比默认执行器,它能够提供更强的用户隔离能力,但需要正确配置:

  • 文件权限
  • 用户白名单或黑名单
  • cgroups
  • 容器运行时
  • NodeManager 用户权限

配置错误可能造成 Container 无法启动,甚至引入权限风险。


16. YARN 日志管理

16.1 Container 日志

一个 Container 通常会生成:

  • stdout
  • stderr
  • syslog
  • 框架自定义日志

NodeManager 默认将日志写入本地日志目录。

16.2 日志聚合

如果启用日志聚合,应用完成后,NodeManager 会将 Container 日志上传到 HDFS 等远程文件系统。

基础配置示例:

<property>
    <name>yarn.log-aggregation-enable</name>
    <value>true</value>
</property>

<property>
    <name>yarn.nodemanager.remote-app-log-dir</name>
    <value>/tmp/logs</value>
</property>

<property>
    <name>yarn.log-aggregation.retain-seconds</name>
    <value>604800</value>
</property>

604800 秒等于 7 天。

16.3 查看应用日志

yarn logs -applicationId application_1723456789000_0012

查看指定 Container:

yarn logs \
  -applicationId application_1723456789000_0012 \
  -containerId container_1723456789000_0012_01_000003

查看指定节点上的日志时,还可以结合当前版本支持的 yarn logs 参数进行过滤。

16.4 日志聚合常见问题

如果无法查看日志,应检查:

  • 是否启用了日志聚合。
  • 应用是否已经完成。
  • NodeManager 是否成功上传日志。
  • 远程日志目录是否存在。
  • 当前用户是否有读取权限。
  • HDFS 是否可用。
  • 日志是否已经过期被清理。

17. YARN 常用配置

以下配置通常位于 yarn-site.xml

17.1 ResourceManager 地址

<property>
    <name>yarn.resourcemanager.hostname</name>
    <value>rm-host</value>
</property>

生产环境使用 HA 时,应配置不同 ResourceManager ID 对应的地址。

17.2 NodeManager 可分配内存

<property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>65536</value>
</property>

不要直接将服务器全部物理内存分配给 YARN,还需要为以下组件预留内存:

  • 操作系统
  • NodeManager
  • DataNode
  • 日志代理
  • 监控代理
  • 安全组件
  • 页面缓存
  • 其他守护进程

17.3 NodeManager 可分配 CPU

<property>
    <name>yarn.nodemanager.resource.cpu-vcores</name>
    <value>16</value>
</property>

17.4 调度器类型

<property>
    <name>yarn.resourcemanager.scheduler.class</name>
    <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
</property>

17.5 MapReduce Shuffle 服务

<property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
</property>

MapReduce 在 YARN 上运行时通常需要 NodeManager 提供 Shuffle 辅助服务。

17.6 本地目录

<property>
    <name>yarn.nodemanager.local-dirs</name>
    <value>/data1/yarn/local,/data2/yarn/local</value>
</property>

17.7 日志目录

<property>
    <name>yarn.nodemanager.log-dirs</name>
    <value>/data1/yarn/logs,/data2/yarn/logs</value>
</property>

使用多块磁盘可以分散 I/O 压力,但应持续监控磁盘健康和空间使用情况。

17.8 内存检查

YARN 可以监控 Container 的物理内存和虚拟内存。

配置时需要注意 JVM、直接内存和本地进程的实际用量,不能简单通过关闭检查来掩盖内存配置问题。


18. YARN 常用命令

18.1 查看正在运行的应用

yarn application -list

查看所有状态的应用:

yarn application -list -appStates ALL

查看指定应用:

yarn application -status application_1723456789000_0012

18.2 停止应用

yarn application -kill application_1723456789000_0012

停止应用会中断正在运行的任务,生产环境执行前应确认应用 ID、业务影响和恢复方式。

18.3 查看节点

yarn node -list

查看全部节点状态:

yarn node -list -all

查看指定节点:

yarn node -status worker-01:8041

18.4 查看队列

yarn queue -status production

18.5 查看日志

yarn logs -applicationId application_1723456789000_0012

18.6 查看 ApplicationAttempt

yarn applicationattempt \
  -list application_1723456789000_0012

查看指定 Attempt:

yarn applicationattempt \
  -status appattempt_1723456789000_0012_000001

18.7 查看 Container

yarn container \
  -list appattempt_1723456789000_0012_000001

查看指定 Container:

yarn container \
  -status container_1723456789000_0012_01_000003

18.8 查看 ResourceManager 状态

yarn rmadmin -getServiceState rm1
yarn rmadmin -getServiceState rm2

18.9 刷新队列

yarn rmadmin -refreshQueues

刷新前应先验证队列配置,避免因为容量之和、队列路径或权限配置错误影响线上调度。


19. 在 YARN 上运行 MapReduce

19.1 配置 MapReduce 使用 YARN

mapred-site.xml 中配置:

<property>
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
</property>

19.2 提交示例任务

hadoop jar \
  "$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar" \
  wordcount \
  /input \
  /output

19.3 MapReduce 对应的 YARN 组件

MapReduce 概念YARN 中的表现
JobApplication
MRAppMasterApplicationMaster
Map TaskContainer 中的任务
Reduce TaskContainer 中的任务
Job 提交客户端YARN Client
Task 日志Container 日志

19.4 MapReduce 执行流程

  1. 客户端提交作业。
  2. ResourceManager 分配 AM Container。
  3. NodeManager 启动 MRAppMaster。
  4. MRAppMaster 计算 InputSplit。
  5. MRAppMaster 申请 Map Container。
  6. Map Task 读取数据并输出中间结果。
  7. MRAppMaster 申请 Reduce Container。
  8. Reduce Task 拉取 Map 输出。
  9. Reduce Task 执行聚合并写入 HDFS。
  10. MRAppMaster 上报作业完成。

20. 在 YARN 上运行 Spark

Spark 支持两种常见的 YARN 部署模式。

20.1 Client 模式

spark-submit \
  --master yarn \
  --deploy-mode client \
  --class com.example.WordCount \
  app.jar

Client 模式下:

  • Driver 运行在提交客户端。
  • ApplicationMaster 主要负责向 YARN 申请 Executor。
  • 客户端断开可能影响应用。
  • 适合开发调试和交互式场景。

20.2 Cluster 模式

spark-submit \
  --master yarn \
  --deploy-mode cluster \
  --class com.example.WordCount \
  --driver-memory 2g \
  --executor-memory 4g \
  --executor-cores 2 \
  --num-executors 10 \
  --queue production \
  app.jar

Cluster 模式下:

  • Driver 运行在 YARN 管理的 Container 中。
  • 客户端提交完成后可以退出。
  • 更适合生产任务。

20.3 Spark 资源计算

假设配置:

executor-memory = 4 GB
executor-memoryOverhead = 1 GB
executor-cores = 2
num-executors = 10

Executor Container 的内存资源大致为:

4 GB + 1 GB = 5 GB

10 个 Executor 大致申请:

内存:5 GB × 10 = 50 GB
CPU:2 vCore × 10 = 20 vCore

此外,还需要计算:

  • Driver 或 ApplicationMaster 资源
  • 动态资源分配带来的变化
  • Python Worker 内存
  • 堆外内存
  • 失败重试资源
  • 其他框架开销

20.4 Spark 动态资源分配

动态资源分配允许 Spark 根据任务负载增减 Executor。

优点:

  • 空闲时释放资源。
  • 提高共享集群利用率。
  • 减少固定 Executor 数量造成的浪费。

风险:

  • Executor 频繁增减可能影响稳定性。
  • Shuffle 数据管理需要正确配置。
  • 初始、最小和最大 Executor 数量需要合理设置。
  • 队列最大容量仍然会限制应用扩容。

21. YARN 性能优化

21.1 合理设置节点资源

不要把节点全部资源交给 YARN。

例如,一台服务器有:

128 GB 内存
32 个 CPU 核心

可以根据同机服务情况,为操作系统、DataNode、NodeManager 和监控组件预留资源后,再将剩余资源配置给 YARN。

示例仅作为估算:

YARN 内存:100 GB
YARN vCore:28
系统及守护进程预留:28 GB、4 Core

实际值应根据监控数据确定。

21.2 Container 规格对齐

如果最小分配内存为 1 GB,应用最好申请:

1 GB、2 GB、4 GB、8 GB

长期大量申请 1.1 GB、2.1 GB 等不规则规格,可能造成资源取整和碎片。

21.3 避免超大 Container

Container 过大可能导致:

  • 很难找到满足条件的节点。
  • 应用长时间等待资源。
  • 单个 Container 失败损失较大。
  • 集群资源碎片严重。

21.4 避免过小 Container

Container 过小也会产生问题:

  • Container 数量过多。
  • ApplicationMaster 调度压力增加。
  • NodeManager 进程管理开销增加。
  • JVM 启动开销占比变高。
  • 日志文件数量快速增长。

21.5 合理设置队列容量

队列规划应参考:

  • 部门业务优先级
  • 历史资源使用量
  • 峰值资源需求
  • 实时任务 SLA
  • 离线任务时间窗口
  • 用户并发数量
  • ApplicationMaster 数量

21.6 数据本地性

YARN 的资源请求可以包含位置偏好:

  1. Node Local:任务与数据位于同一节点。
  2. Rack Local:任务与数据位于同一机架。
  3. Off Switch:任务与数据跨机架。

通常数据本地性越好,网络传输越少。

但如果为了等待本地节点而长时间不调度,也可能降低整体执行效率,因此需要在本地性和等待时间之间平衡。

21.7 控制小任务数量

大量小任务会给以下组件带来压力:

  • ResourceManager
  • ApplicationMaster
  • NodeManager
  • NameNode
  • JobHistoryServer
  • Timeline Service
  • 日志系统

可以通过合并输入文件、调整分区数量、减少无意义的小批次作业等方式优化。

21.8 监控 ApplicationMaster 占比

如果大量应用处于 ACCEPTED 状态,应检查:

  • 队列 AM 资源是否达到上限。
  • 集群是否缺少满足 AM 规格的节点。
  • 用户并发应用数是否达到限制。
  • 队列是否有可用容量。
  • 节点标签是否匹配。

22. YARN 常见故障排查

22.1 应用长时间处于 ACCEPTED

可能原因:

  • 集群资源不足。
  • 队列容量不足。
  • ApplicationMaster 资源达到队列上限。
  • 用户资源限制生效。
  • 请求的 Container 过大。
  • 节点标签不匹配。
  • 队列最大应用数已达到限制。
  • 调度器配置异常。

排查命令:

yarn application -status <application_id>
yarn queue -status <queue_name>
yarn node -list -all

重点查看应用 Diagnostics 和 ResourceManager Web UI 中的调度信息。

22.2 Container 因内存超限被终止

常见诊断信息可能包含:

Container killed by YARN for exceeding memory limits

可能原因:

  • JVM Heap 设置过大。
  • Memory Overhead 设置过小。
  • Direct Memory 使用过多。
  • Python 子进程内存过高。
  • 本地库存在内存泄漏。
  • 同一个 Container 内启动过多子进程。

处理思路:

  1. 查看 Container 日志。
  2. 区分物理内存和虚拟内存超限。
  3. 查看 JVM 堆与非堆使用情况。
  4. 增加合理的 Container Overhead。
  5. 排查堆外内存和子进程。
  6. 避免直接关闭内存保护机制。

22.3 Container 启动失败

可能原因:

  • 依赖文件不存在。
  • HDFS 权限不足。
  • 本地磁盘故障。
  • 启动脚本没有执行权限。
  • 环境变量错误。
  • Java 路径错误。
  • Container Token 过期。
  • LinuxContainerExecutor 配置错误。

重点检查:

  • NodeManager 日志
  • Container stderr
  • Container syslog
  • 本地化资源目录
  • HDFS 文件权限

22.4 NodeManager 被标记为不健康

可能原因:

  • 磁盘空间不足。
  • 本地目录不可写。
  • 日志目录故障。
  • 故障磁盘比例过高。
  • 健康检查脚本失败。
  • NodeManager 与 ResourceManager 通信异常。

查看节点状态:

yarn node -status <node_id>

22.5 应用不断重试

需要先确定失败层次:

  • ApplicationMaster 失败
  • Container 失败
  • 具体 Task 失败
  • 节点失败
  • 外部依赖失败

排查顺序:

  1. 查看 Application 状态。
  2. 查看 ApplicationAttempt 列表。
  3. 确定失败的 Attempt。
  4. 查看 AM Container 日志。
  5. 查找第一个异常。
  6. 再检查后续级联错误。

不要只看日志最后一行,因为最后一行经常只是“应用失败”的汇总信息。

22.6 ResourceManager 无法切换

应检查:

  • ZooKeeper 是否可用。
  • 两个 RM 是否使用相同 Cluster ID。
  • RM ID 配置是否一致。
  • 状态存储是否正常。
  • Kerberos Principal 是否正确。
  • 时间是否同步。
  • 防火墙和端口是否放通。
  • Active 与 Standby 是否出现双主风险。

22.7 无法获取应用日志

可能原因:

  • 未启用日志聚合。
  • 应用尚未结束且日志仍在节点本地。
  • 日志上传失败。
  • HDFS 权限不足。
  • 日志保留时间已过期。
  • NodeManager 本地日志已被清理。
  • 查询的 Application ID 错误。

23. YARN 与 Kubernetes 的区别

YARN 和 Kubernetes 都可以管理集群资源,但设计目标不同。

对比项YARNKubernetes
最初目标大数据计算资源管理通用容器编排
基本运行单位ContainerPod
应用管理者ApplicationMasterController、Operator
资源管理ResourceManagerScheduler、Controller Manager
节点代理NodeManagerkubelet
数据本地性与 Hadoop/HDFS 集成紧密可通过存储和调度能力实现
服务发现较弱,依赖应用框架内置 Service 和 DNS
长期服务可以支持,但不是传统优势非常适合
批处理任务成熟通过 Job、Operator 等实现
大数据生态Hadoop 生态集成成熟云原生生态更丰富
隔离方式进程、cgroups、可选容器运行时容器运行时、Namespace、cgroups

23.1 YARN 更适合的场景

  • 已经建设成熟 Hadoop 集群。
  • 大量任务依赖 HDFS。
  • 主要运行 MapReduce、Hive、Spark、Tez。
  • 强调数据本地性。
  • 已经具有成熟的 YARN 队列治理体系。

23.2 Kubernetes 更适合的场景

  • 企业基础设施以云原生为主。
  • 同时运行微服务、AI、批处理等多种负载。
  • 需要完善的服务发现、弹性伸缩和容器编排。
  • 希望统一应用交付方式。
  • 依赖 Operator 和云原生生态。

23.3 两者并非绝对替代关系

企业可以根据业务场景同时使用:

  • YARN 承载传统 Hadoop 大数据任务。
  • Kubernetes 承载微服务、AI 和新型数据平台。
  • 部分 Spark、Flink 任务逐步迁移到 Kubernetes。
  • 存量 Hive、MapReduce 任务继续运行在 YARN。

选择时应综合考虑:

  • 数据位置
  • 运维能力
  • 任务类型
  • 迁移成本
  • 安全体系
  • 调度需求
  • 生态依赖

24. 生产环境最佳实践

24.1 启用 ResourceManager HA

生产环境应避免 ResourceManager 单点故障,并定期验证故障切换能力。

24.2 启用日志聚合

没有日志聚合时,节点故障或本地日志清理后可能无法追踪历史问题。

24.3 使用分层队列

建议按照业务重要性划分:

root
├── production
│   ├── realtime
│   └── offline
├── development
└── test

不要为每个小项目都建立过深队列,否则配置和容量治理会变得复杂。

24.4 对实时和离线任务进行隔离

实时任务通常要求:

  • 更稳定的保证资源。
  • 更短的调度等待时间。
  • 更严格的用户权限。
  • 更谨慎的抢占策略。

离线任务可以利用空闲资源,但不应影响实时任务 SLA。

24.5 建立资源规格规范

统一常用 Container 规格,例如:

规格内存vCore适用场景
Small2 GB1小型任务
Medium4 GB2常规计算
Large8 GB4大内存计算
XLarge16 GB8特殊任务

规格需要结合服务器配置和任务特征制定。

24.6 监控关键指标

建议监控:

  • 集群总资源
  • 已使用资源
  • 可用资源
  • 各队列资源使用率
  • Pending Container 数量
  • Running Application 数量
  • Accepted Application 数量
  • NodeManager 健康数量
  • Lost Node 数量
  • Container 失败数量
  • ApplicationMaster 重试次数
  • 磁盘使用率
  • 日志聚合失败次数
  • 调度延迟

24.7 定期治理僵尸应用

需要关注:

  • 长时间无进度的应用
  • 长期占用少量资源的应用
  • 不断失败重试的应用
  • 无业务价值的常驻 Session
  • 用户忘记关闭的交互式任务

停止应用前应先确认业务负责人、数据一致性和恢复方式。

24.8 控制用户提交权限

通过队列 ACL 和数据权限限制:

  • 谁可以提交生产任务。
  • 谁可以停止其他人的应用。
  • 谁可以读取应用日志。
  • 谁可以修改调度器配置。
  • 谁可以使用 GPU 等特殊节点。

24.9 建立配置变更流程

调度器配置变更可能影响整个集群。

建议流程:

  1. 在测试环境验证配置。
  2. 检查队列容量关系。
  3. 检查队列路径和权限。
  4. 评估正在运行的应用。
  5. 备份旧配置。
  6. 在低峰期刷新或发布。
  7. 观察调度器和队列指标。
  8. 准备回滚方案。

24.10 容量规划应基于历史数据

不要只根据服务器物理规格规划队列。

还应分析:

  • 业务峰值
  • 日均资源使用量
  • P95 资源使用量
  • 任务等待时间
  • 资源碎片率
  • Container 失败率
  • 各部门增长趋势
  • 节假日和月末峰值

25. 总结

YARN 是 Hadoop 生态中的通用资源管理和任务调度平台。

它通过以下核心组件完成分布式资源管理:

  • ResourceManager 负责全局资源管理。
  • NodeManager 负责单节点资源和 Container 管理。
  • ApplicationMaster 负责单个应用的调度与生命周期。
  • Container 表示应用实际获得的资源。
  • Scheduler 根据队列和资源策略完成分配。

理解 YARN 时,需要重点掌握以下内容:

  1. YARN 只负责资源管理,不负责具体业务计算。
  2. ApplicationMaster 将应用内部调度从 ResourceManager 中分离出来。
  3. Container 是资源分配单位,不等同于 Docker 容器。
  4. CapacityScheduler 通过队列实现多租户和容量隔离。
  5. 队列容量通常是资源保证,并不一定是静态资源预留。
  6. Application 长时间处于 ACCEPTED,通常与 AM 资源、队列容量或资源规格有关。
  7. Container 内存需要包含堆内、堆外和进程额外开销。
  8. ResourceManager HA、日志聚合和资源监控是生产环境的重要基础能力。
  9. 排查故障时,应区分 Application、ApplicationAttempt、ApplicationMaster、Container 和具体 Task。
  10. YARN 与 Kubernetes 的目标不同,技术选型应结合数据位置、任务类型和现有基础设施。

从本质上看,YARN 解决的是一个核心问题:

在一个多用户、多任务、多计算框架共享的分布式集群中,如何安全、稳定并高效地分配有限的计算资源。

更多推荐