深入理解 Hadoop YARN:架构、调度原理、运行流程与生产实践
YARN 全称为 Yet Another Resource Negotiator,是 Hadoop 2.x 引入的通用资源管理与任务调度框架。它将集群资源管理与具体计算逻辑解耦,使 MapReduce、Spark、Flink、Tez 等计算框架能够共享同一个集群。
1. YARN 是什么
YARN 是 Apache Hadoop 的资源管理和任务调度系统。
它主要负责两件事情:
- 管理集群中的 CPU、内存等计算资源。
- 根据应用提交的资源请求,为应用分配运行资源。
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 的核心架构由以下组件组成:
- ResourceManager
- NodeManager
- ApplicationMaster
- Container
- Client
整体关系如下:
各个组件的职责如下:
| 组件 | 作用 |
|---|---|
| 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 接收到应用后,会执行:
- 校验用户权限。
- 检查队列是否存在。
- 检查资源请求是否合法。
- 保存应用状态。
- 将应用交给调度器。
5.5 分配 ApplicationMaster Container
调度器为 ApplicationMaster 分配第一个 Container。
该 Container 也被称为:
AM Container
5.6 启动 ApplicationMaster
ResourceManager 通知目标节点上的 NodeManager 启动 AM Container。
NodeManager 会:
- 下载应用依赖。
- 创建工作目录。
- 设置环境变量。
- 准备安全令牌。
- 执行 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:
- 向 ResourceManager 注销。
- 上报最终应用状态。
- 清理临时资源。
- 结束自身进程。
应用最终状态可能包括:
FINISHEDFAILEDKILLED
完整流程如下:
6. ResourceManager 工作原理
ResourceManager 是 YARN 集群的全局资源管理组件。
它主要包含两个核心模块:
- ApplicationsManager
- 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 收到启动请求后,会执行:
- 校验 Container Token。
- 创建应用目录。
- 创建 Container 工作目录。
- 下载依赖文件。
- 创建启动脚本。
- 设置环境变量。
- 使用指定用户启动进程。
- 监控进程资源使用情况。
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 |
|---|---|
| MapReduce | MRAppMaster |
| Spark | Spark ApplicationMaster |
| Tez | Tez ApplicationMaster |
| Flink | Flink 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 常见的调度器包括:
- FIFO Scheduler
- CapacityScheduler
- 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 抢占机制
当某个队列长期占用其他队列的保证资源时,可以启用抢占机制。
抢占的大致过程是:
- 检测队列资源是否低于保证容量。
- 等待设定的容忍时间。
- 选择需要释放的 Container。
- 通知应用释放或直接终止部分 Container。
- 将资源重新分配给资源不足的队列。
抢占配置需要谨慎。
过于激进可能造成:
- 任务频繁重试。
- Spark Executor 大量丢失。
- 计算结果延迟。
- 集群吞吐下降。
12.3 节点标签
Node Label 可以将节点划分为不同资源池。
例如:
high-memory
gpu
ssd
normal
应用或队列可以声明只使用某种标签的节点。
典型场景:
- Spark 大内存任务只运行在高内存节点。
- AI 任务只运行在 GPU 节点。
- 低优先级离线任务运行在普通节点。
- 特殊业务运行在独立物理资源池。
12.4 资源隔离层次
YARN 的资源隔离通常包含多个层次:
- 调度器层面的资源配额。
- NodeManager 层面的资源监控。
- Linux 用户权限隔离。
- cgroups CPU、内存隔离。
- Docker 或其他容器运行时隔离。
- 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 节点等待接管。
常见配置示例:
<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 故障时:
- ResourceManager 无法继续收到节点心跳。
- 节点被标记为 Lost。
- 该节点上的 Container 被认为已经丢失。
- ApplicationMaster 根据框架策略重新申请资源。
- 任务可能在其他节点重新执行。
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 中的表现 |
|---|---|
| Job | Application |
| MRAppMaster | ApplicationMaster |
| Map Task | Container 中的任务 |
| Reduce Task | Container 中的任务 |
| Job 提交客户端 | YARN Client |
| Task 日志 | Container 日志 |
19.4 MapReduce 执行流程
- 客户端提交作业。
- ResourceManager 分配 AM Container。
- NodeManager 启动 MRAppMaster。
- MRAppMaster 计算 InputSplit。
- MRAppMaster 申请 Map Container。
- Map Task 读取数据并输出中间结果。
- MRAppMaster 申请 Reduce Container。
- Reduce Task 拉取 Map 输出。
- Reduce Task 执行聚合并写入 HDFS。
- 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 的资源请求可以包含位置偏好:
- Node Local:任务与数据位于同一节点。
- Rack Local:任务与数据位于同一机架。
- 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 内启动过多子进程。
处理思路:
- 查看 Container 日志。
- 区分物理内存和虚拟内存超限。
- 查看 JVM 堆与非堆使用情况。
- 增加合理的 Container Overhead。
- 排查堆外内存和子进程。
- 避免直接关闭内存保护机制。
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 失败
- 节点失败
- 外部依赖失败
排查顺序:
- 查看 Application 状态。
- 查看 ApplicationAttempt 列表。
- 确定失败的 Attempt。
- 查看 AM Container 日志。
- 查找第一个异常。
- 再检查后续级联错误。
不要只看日志最后一行,因为最后一行经常只是“应用失败”的汇总信息。
22.6 ResourceManager 无法切换
应检查:
- ZooKeeper 是否可用。
- 两个 RM 是否使用相同 Cluster ID。
- RM ID 配置是否一致。
- 状态存储是否正常。
- Kerberos Principal 是否正确。
- 时间是否同步。
- 防火墙和端口是否放通。
- Active 与 Standby 是否出现双主风险。
22.7 无法获取应用日志
可能原因:
- 未启用日志聚合。
- 应用尚未结束且日志仍在节点本地。
- 日志上传失败。
- HDFS 权限不足。
- 日志保留时间已过期。
- NodeManager 本地日志已被清理。
- 查询的 Application ID 错误。
23. YARN 与 Kubernetes 的区别
YARN 和 Kubernetes 都可以管理集群资源,但设计目标不同。
| 对比项 | YARN | Kubernetes |
|---|---|---|
| 最初目标 | 大数据计算资源管理 | 通用容器编排 |
| 基本运行单位 | Container | Pod |
| 应用管理者 | ApplicationMaster | Controller、Operator |
| 资源管理 | ResourceManager | Scheduler、Controller Manager |
| 节点代理 | NodeManager | kubelet |
| 数据本地性 | 与 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 | 适用场景 |
|---|---|---|---|
| Small | 2 GB | 1 | 小型任务 |
| Medium | 4 GB | 2 | 常规计算 |
| Large | 8 GB | 4 | 大内存计算 |
| XLarge | 16 GB | 8 | 特殊任务 |
规格需要结合服务器配置和任务特征制定。
24.6 监控关键指标
建议监控:
- 集群总资源
- 已使用资源
- 可用资源
- 各队列资源使用率
- Pending Container 数量
- Running Application 数量
- Accepted Application 数量
- NodeManager 健康数量
- Lost Node 数量
- Container 失败数量
- ApplicationMaster 重试次数
- 磁盘使用率
- 日志聚合失败次数
- 调度延迟
24.7 定期治理僵尸应用
需要关注:
- 长时间无进度的应用
- 长期占用少量资源的应用
- 不断失败重试的应用
- 无业务价值的常驻 Session
- 用户忘记关闭的交互式任务
停止应用前应先确认业务负责人、数据一致性和恢复方式。
24.8 控制用户提交权限
通过队列 ACL 和数据权限限制:
- 谁可以提交生产任务。
- 谁可以停止其他人的应用。
- 谁可以读取应用日志。
- 谁可以修改调度器配置。
- 谁可以使用 GPU 等特殊节点。
24.9 建立配置变更流程
调度器配置变更可能影响整个集群。
建议流程:
- 在测试环境验证配置。
- 检查队列容量关系。
- 检查队列路径和权限。
- 评估正在运行的应用。
- 备份旧配置。
- 在低峰期刷新或发布。
- 观察调度器和队列指标。
- 准备回滚方案。
24.10 容量规划应基于历史数据
不要只根据服务器物理规格规划队列。
还应分析:
- 业务峰值
- 日均资源使用量
- P95 资源使用量
- 任务等待时间
- 资源碎片率
- Container 失败率
- 各部门增长趋势
- 节假日和月末峰值
25. 总结
YARN 是 Hadoop 生态中的通用资源管理和任务调度平台。
它通过以下核心组件完成分布式资源管理:
- ResourceManager 负责全局资源管理。
- NodeManager 负责单节点资源和 Container 管理。
- ApplicationMaster 负责单个应用的调度与生命周期。
- Container 表示应用实际获得的资源。
- Scheduler 根据队列和资源策略完成分配。
理解 YARN 时,需要重点掌握以下内容:
- YARN 只负责资源管理,不负责具体业务计算。
- ApplicationMaster 将应用内部调度从 ResourceManager 中分离出来。
- Container 是资源分配单位,不等同于 Docker 容器。
- CapacityScheduler 通过队列实现多租户和容量隔离。
- 队列容量通常是资源保证,并不一定是静态资源预留。
- Application 长时间处于
ACCEPTED,通常与 AM 资源、队列容量或资源规格有关。 - Container 内存需要包含堆内、堆外和进程额外开销。
- ResourceManager HA、日志聚合和资源监控是生产环境的重要基础能力。
- 排查故障时,应区分 Application、ApplicationAttempt、ApplicationMaster、Container 和具体 Task。
- YARN 与 Kubernetes 的目标不同,技术选型应结合数据位置、任务类型和现有基础设施。
从本质上看,YARN 解决的是一个核心问题:
在一个多用户、多任务、多计算框架共享的分布式集群中,如何安全、稳定并高效地分配有限的计算资源。
更多推荐
所有评论(0)