在当今的大数据领域,Apache Hadoop 无疑是最基础且广泛使用的框架之一。但在早期的 Hadoop 1.0 版本中,我们面临着严峻的性能瓶颈:系统仅能支持 MapReduce 一种计算框架,且集群的资源管理效率低下。为了解决这些问题,Hadoop 2.0 引入了一个革命性的组件——YARN(Yet Another Resource Negotiator)。
在今天的文章中,我们将不再浅尝辄止,而是作为资深大数据工程师,深入 YARN 的内部世界。我们将一起探讨它是如何通过“资源管理与作业调度分离”的架构变革,让 Hadoop 摆脱 MapReduce 的束缚,进化为一个能够同时运行流处理、交互式 SQL 和机器学习任务的高效大数据操作系统。你将了解 YARN 的核心组件构成、工作流程、调度策略,以及如何在实际生产环境中优化它的性能。
目录
YARN 的定义与核心设计哲学
首先,让我们明确一下 YARN 到底是什么。YARN 代表“Yet Another Resource Negotiator”,意为“另一种资源协调者”。这听起来像是一个自嘲的名字,但它实际上承载了 Hadoop 架构中最关键的使命。
在 Hadoop 1.x 中,MapReduce 既负责计算,又负责资源管理,这就像是一个大厨既要负责切菜做饭,还要管理整个厨房的食材分配,效率自然低下。YARN 的引入,本质上是为了将“资源管理”从“编程模型”中剥离出来。简而言之,YARN 是 Hadoop 集群的“操作系统”,它负责管理集群中的 CPU 和内存,并将其分配给运行在 Hadoop 上的各种应用程序。
它的核心目的可以总结为以下几点:
- 通用性:不仅仅支持 MapReduce,还支持 Apache Spark、Apache Flink 等多种处理引擎。
- 可扩展性:通过将调度器与应用程序分离,使得集群规模可以扩展到数千甚至上万节点。
- 高利用率:通过动态资源分配,最大化集群资源的利用率。
YARN 的核心架构组件
理解 YARN 的关键在于理解它的三个主要组件:ResourceManager、NodeManager 和 ApplicationMaster。让我们通过一个比喻来拆解它们:如果把 Hadoop 集群比作一家大型物流公司,那么这三个组件各司其职。
1. ResourceManager (RM):公司的总调度中心
ResourceManager 是 YARN 的主守护进程,也是集群的“大脑”。它负责整个集群的资源管理和调度。它通常运行在专用的主节点上,以避免因资源竞争而影响其稳定性。RM 包含两个主要组件:
- 调度器:这是一个纯调度器,不负责监控或跟踪应用程序的状态。它只根据资源需求和策略(如 FIFO、容量或公平调度)将资源分配给各个应用程序。你可以把它想象成公司的“排班经理”,只负责把司机和卡车分配给订单,不管具体的运输过程。
- 应用程序管理器:负责接收作业提交,协商第一个容器用于运行 ApplicationMaster,并在应用程序失败时重启它。这是“客户接待员”,负责对接客户并启动项目。
2. NodeManager (NM):每个物流站点(节点)的主管
NodeManager 运行在集群中的每个工作节点(DataNode)上。它是 ResourceManager 的“执行者”。
- 主要职责:它监控容器中资源的使用情况(CPU、内存、磁盘),并定期向 ResourceManager 发送心跳报告。如果节点上的某个容器占用了超过其分配限额的资源,NodeManager 会将其杀死,以确保“坏邻居”不会影响其他任务。
- 容器:这是 YARN 中的资源抽象概念。一个容器包含特定节点上的特定资源量(例如:2GB 内存,1 个 CPU 核心)。
3. ApplicationMaster (AM):具体的物流项目经理
每个应用程序都有自己专属的 ApplicationMaster。它是一个框架特定的库(比如 MapReduce AM, Spark AM),负责与 ResourceManager 协商资源,并与 NodeManager 协同工作来执行和监控任务。
- 职责:一旦应用程序启动,AM 会向 RM 申请容器,然后在 NM 上启动具体的任务进程。它还负责任务容器的容错和重试。
YARN 的工作流程:从提交到完成
让我们通过一个实际场景来理解这一过程。假设我们提交了一个 MapReduce 作业来分析日志文件。下图描述了这一流程,我们将逐步拆解:
- 作业提交:客户端向 ResourceManager 申请提交一个新作业。RM 返回提交路径和资源容量。
- 启动 ApplicationMaster:客户端将作业资源提交到 HDFS,并通知 ResourceManager。RM 的应用程序管理器在一个 NodeManager 上为该作业分配一个容器,并启动 ApplicationMaster (AM)。
- 资源申请:AM 启动后,它会根据作业的切片情况,向 ResourceManager 的调度器申请运行任务所需的容器资源。
- 资源分配与任务启动:调度器根据策略分配资源给 AM。AM 拿到资源清单后,与对应的 NodeManager 通信,要求它们启动具体的任务进程。
- 监控与更新:NodeManager 监控任务状态,并通过心跳向 AM 反馈。AM 收集所有任务进度,并定期向 RM 报告。
- 作业完成:所有任务完成后,AM 向 RM 注销自己,容器被释放,资源回归资源池。
YARN 中的三种核心调度器
作为管理员,你经常会面临多用户争抢集群资源的情况。YARN 允许我们通过配置不同的调度器来解决资源争抢问题。以下是三种最常用的调度策略及其代码配置示例:
1. FIFO Scheduler(先进先出)
这是最简单的调度器。它按照作业提交的时间顺序进行调度。优点是实现简单,但缺点很明显:大的分析任务会阻塞后面的小任务,导致交互式查询响应极慢。
2. Capacity Scheduler(容量调度器)- Hadoop 默认推荐
这是企业级应用最广泛的调度器。它将集群资源划分为多个队列,每个队列分配一定的资源容量。
- 应用场景:多租户环境。例如,你需要为“生产环境”分配 80% 的资源,为“开发测试”分配 20%,但允许开发队列在空闲时借用生产队列的资源。
代码示例:配置 Capacity Scheduler (capacity-scheduler.xml)
在 Hadoop 的配置文件中,我们可以定义层级队列。以下代码展示了如何为 INLINECODE8294f0de 下的两个队列 INLINECODEea78d152 和 production 配置资源比例。
yarn.scheduler.capacity.root.queues
default,production
这里的配置表示在根队列下定义了两个子队列:default 和 production。
我们可以根据部门或业务需求随意扩展此列表。
yarn.scheduler.capacity.root.default.capacity
50
default 队列默认占用 50% 的集群资源。
yarn.scheduler.capacity.root.production.capacity
50
production 队列默认占用 50% 的集群资源。
yarn.scheduler.capacity.root.production.maximum-am-resource-percent
0.5
限制 production 队列中用于 ApplicationMaster 的资源比例,防止资源耗尽。
3. Fair Scheduler(公平调度器)
Fair Scheduler 的目标是让所有作业在时间维度上平均分配资源。如果只有一个作业运行,它能独占集群;如果有新作业提交,它会释放部分资源给新作业,最终达到一种公平状态。
实际配置差异:你可以通过设置 INLINECODEadfa673d 为 INLINECODEc27dbefe 来切换到此模式。
深入解析:Container(容器)与资源隔离
在 YARN 中,Container 是资源的逻辑封装单元。每当你启动一个 Map 任务或 Spark Executor,它们都是运行在某个 Container 中的。
我们可以通过配置 yarn-site.xml 来控制单个容器和单个节点(NodeManager)的资源限制。这对于防止“失控”进程导致整个集群宕机至关重要。
实战配置:内存与 CPU 的资源管理
以下是一个典型的 yarn-site.xml 配置片段,展示了如何定义内存和 CPU 的最小分配单位和最大限制。
yarn.nodemanager.resource.memory-mb
65536
这是这台机器上所有容器能共享的内存总和。
yarn.scheduler.minimum-allocation-mb
2048
调度器分配内存时,必须是 2048MB 的倍数。这有助于减少内存碎片。
yarn.scheduler.maximum-allocation-mb
32768
防止某个任务独占节点所有资源,影响其他任务的调度。
yarn.nodemanager.vmem-pmem-ratio
2.1
这是每个容器可以使用的虚拟内存相对于物理内存的倍数。
如果你看到任务因 "Container killed by YARN for exceeding virtual memory limits" 被杀,
可以尝试调高这个值,或者优化代码的内存使用。
代码解析与常见问题:
在实际开发中,你可能会遇到任务被 NodeManager 强制杀死的错误日志。这通常是因为任务申请了 4GB 内存,但实际运行时堆外内存溢出。YARN 的内存监控机制会检测到进程使用的物理内存超过了 Container 的限制,从而触发 KILL 信号来保护节点不因内存溢出(OOM)而崩溃。
应用程序提交实战:使用 Client API 提交任务
作为开发者,我们通常不需要直接操作 ResourceManager 的 API,因为 Spark 或 MapReduce 的脚本已经帮我们做了。但是,理解底层 API 有助于调试。
以下是一个简化的 Java 代码片段,展示了如何使用 YARN Client API 来获取集群统计信息。这段代码对于编写监控工具非常有用。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.*;
import org.apache.hadoop.yarn.client.api.YarnClient;
import org.apache.hadoop.yarn.exceptions.YarnException;
import java.io.IOException;
public class YarnClusterMonitor {
public static void main(String[] args) throws IOException, YarnException {
// 1. 创建 Hadoop 配置对象
Configuration conf = new Configuration();
// 可以在这里添加自定义配置,例如 conf.set("fs.defaultFS", "hdfs://...");
// 2. 初始化 YarnClient
YarnClient yarnClient = YarnClient.createYarnClient();
yarnClient.init(conf);
yarnClient.start();
try {
// 3. 获取集群信息
YarnClusterMetrics clusterMetrics = yarnClient.getYarnClusterMetrics();
System.out.println("当前集群节点总数: " + clusterMetrics.getNumNodeManagers());
// 4. 遍历所有运行中的应用程序
for (ApplicationReport app : yarnClient.getApplications()) {
System.out.println(
String.format("应用 ID: %s, 类型: %s, 状态: %s",
app.getApplicationId(),
app.getApplicationType(),
app.getYarnApplicationState()
)
);
}
} finally {
// 5. 清理资源
yarnClient.stop();
}
}
}
这段代码做了什么?
它建立了一个与 ResourceManager 的连接,并打印出了当前集群活跃的 NodeManager 数量以及所有运行中的应用程序(包括 Spark、MapReduce 等)。你可以扩展此代码来自动化告警——例如,当运行中的应用程序数量超过阈值时发送邮件通知。
性能优化与最佳实践
最后,让我们聊聊在实际生产环境中,如何让 YARN 跑得更快、更稳。以下是我们总结的经验:
- 内存与 CPU 的平衡:不要只关注内存。如果你的计算任务是 CPU 密集型的(如加密、压缩),记得在配置中增加
yarn.nodemanager.resource.cpu-vcores的值,并在提交任务时请求相应的虚拟核心。
- 开启标签调度:在异构硬件集群中,有些节点可能配备了 SSD 或更强大的 CPU。你可以通过 Node Label(节点标签)功能,将 Spark SQL 作业强制调度到高性能节点上,而将清洗作业调度到普通节点上。
yarn.node-labels.enabled
true
- 避免“小文件”问题:这虽然主要是 MapReduce 的问题,但会直接影响 YARN。成千上万个小文件会启动成千上万个 Mapper 任务,导致 YARN 调度器压力过大,AM 频繁申请和释放容器,导致吞吐量下降。建议在入库前使用
HAR工具或合并任务处理小文件。
- 调整 Container 预分配延迟:对于短命的作业,可以减小
yarn.resourcemanager.nodemanagers.heartbeat-interval-ms,让 RM 更快地发现空闲资源并分配容器,但这会增加 RM 的网络负担。
结论
回顾全文,YARN 不仅仅是一个“Yet Another Resource Negotiator”,它是 Hadoop 从单一的批处理工具进化为全能数据操作系统的基石。通过将资源管理与计算逻辑解耦,YARN 赋予了我们处理海量数据的无限可能性。
对于大数据工程师而言,深刻理解 ResourceManager 的调度机制、NodeManager 的资源隔离方式以及 Container 的生命周期管理,是构建高性能、高可用数据平台的关键。无论是在处理实时流处理,还是运行复杂的 SQL 查询,YARN 都在幕后默默地为你协调着数千个节点的资源。掌握它,你就掌握了大数据集群的“交通指挥权”。