【YARN 权威指南】8. 理解 MapReduce on YARN


MapReduce 运行在 YARN 上以后,最容易产生的误解是:YARN 只是把原来的 MapReduce 作业搬到另一套资源管理器上运行。这个理解只对了一半。真正重要的变化,是 MapReduce 不再独占集群调度模型。它退回成 YARN 上的一种应用框架,和其它框架一样,通过 ResourceManager 申请资源,通过 NodeManager 启动 Container,再由自己的 ApplicationMaster 管理应用内部逻辑。

这意味着 MapReduce 的核心概念仍然存在:Job、Map Task、Reduce Task、InputSplit、Shuffle、Counter、OutputCommitter 都还在。但这些概念的运行边界发生了变化。集群资源不再由 MapReduce 自己的中心节点直接管理,任务进程也不再由 TaskTracker 这种 MapReduce 专用守护进程启动。ResourceManager 不参与 MapReduce 任务语义,但仍参与资源调度;NodeManager 负责节点执行;MRAppMaster 才负责 MapReduce 作业本身。

在测试环境里,我提交了一个 Pi 示例任务到 root.etl 队列:

hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.4.1.jar \
  pi -Dmapreduce.job.queuename=etl 6 4000

这次任务生成的标识如下:

Application ID: application_1739344332779_0001
Job ID:         job_1739344332779_0001
Queue:          root.etl
State:          FINISHED
Final Status:   SUCCEEDED

这组标识很适合用来拆解 MapReduce on YARN 的运行链路。application_1739344332779_0001 是 YARN 视角的应用,job_1739344332779_0001 是 MapReduce 视角的作业。前者回答“这个应用在集群资源层面如何运行”,后者回答“这个 MapReduce 作业内部如何执行”。两者通常一一对应,但生命周期视角不完全相同:Application 关注 AM、Container、队列和资源状态,Job 关注 Map/Reduce、TaskAttempt、Counter 和输出提交。

ResourceManager 中的 MapReduce 应用详情

1. MapReduce On YARN 的角色模型

1.1 从 JobTracker 到 YARN 角色拆分

MRv1 时代的 JobTracker 同时承担了太多职责:接收作业、调度任务、跟踪 TaskTracker、处理失败重试、维护作业状态,还要提供历史和监控入口。集群规模变大以后,这种设计的问题很明显。一个中心角色既要管资源,又要懂 MapReduce 作业语义,还要处理大量任务心跳,扩展性和隔离性都会受到限制。

YARN 把这些职责拆开:

MRv1 职责 YARN 下的角色
全局资源管理 ResourceManager
节点资源和进程执行 NodeManager
单个 MapReduce 作业协调 MRAppMaster
Map 或 Reduce 任务执行 Container 内的 Task 进程
作业完成后的历史查询 JobHistoryServer 与日志聚合

这个拆分的价值不只是“性能更好”。更关键的是,资源管理变成了集群公共能力,MapReduce 只是这套公共能力上的一个应用类型。Spark、Tez、Flink 等框架也可以用同样的资源申请和 Container 启动模型接入 YARN。MapReduce 不再需要拥有集群,它只需要在自己的 ApplicationMaster 里管理作业语义。

这也是排查思路必须变化的原因。一个作业失败时,不能只盯着 MapReduce 日志看。它可能失败在客户端提交阶段,可能失败在 ResourceManager 接受应用阶段,可能失败在 MRAppMaster 启动阶段,也可能失败在某个 Map 或 Reduce Container 里。不同阶段对应不同组件,排查入口也不同。

1.2 客户端提交:作业先变成 YARN Application

一次 MapReduce 作业从 hadoop jar 开始。客户端不会直接在本机执行 Map 和 Reduce,而是先完成提交准备:

  1. 解析命令行参数和作业配置。
  2. 计算输入数据的 InputSplit。
  3. 把作业 jar、配置文件、分片信息等资源放入 staging 目录。
  4. 向 ResourceManager 提交一个 YARN Application。
  5. 等待 ResourceManager 分配第一个 Container,用来启动 MRAppMaster。

在这个阶段,mapreduce.job.queuename=etl 很关键。它并不是让 MapReduce 自己去选择机器,而是把应用提交到 Capacity Scheduler 的 root.etl 队列。调度器会根据队列容量、最大容量、当前资源使用、用户限制和应用状态决定它什么时候可以获得资源。

ResourceManager 应用列表里可以直接看到这层关系:

ResourceManager 应用列表中 MapReduce 作业进入 root.etl 队列

这里的 Application Type=MAPREDUCE 表示应用框架类型,Queue=root.etl 表示它进入的调度队列,State=FINISHED 和 FinalStatus=SUCCEEDED 表示 YARN 层面应用已经完成且结果成功。对使用者来说,这个页面比单纯看命令行输出更有价值,因为它把应用类型、队列归属、资源视角和最终状态放在同一个地方。

提交阶段常见问题主要有三类。第一类是客户端配置不对,比如 mapreduce.framework.name 没有设置为 yarn,导致作业没有按 YARN 模式提交。第二类是 HDFS staging 目录权限或空间问题,客户端资源上传失败。第三类是队列不存在或 ACL 不允许提交,应用还没进入执行阶段就被拒绝。遇到这些问题时,优先看客户端异常、ResourceManager 应用状态和调度器队列配置。

客户端提交还有一个细节值得单独看:staging 目录不是临时小文件的随意堆放,而是作业交给集群前的交接区。MapReduce 会把作业配置、分片信息、jar 包和需要分发的资源放进去,MRAppMaster 启动后再从这里读取作业定义。也就是说,客户端不是把“一个命令”交给集群,而是把一份可被 ApplicationMaster 接管的作业描述交给集群。

这个设计带来两个实际影响。第一,提交端和执行端可以分离。客户端提交完成、Application 已被 RM 接受并且 AM 能成功启动后,真正的作业推进由 MRAppMaster 接手,客户端退出通常不影响作业继续运行。第二,HDFS 元数据和权限会参与作业启动。如果 staging 路径所属用户不对、目录权限不对、空间不足、文件丢失或 NameNode 不稳定,作业可能还没到 AM 阶段就失败。很多人看到 MapReduce 作业失败,会直接找 Map 或 Reduce 日志,其实提交阶段的问题根本不会产生有效 Task 日志。

还有一个经常被忽略的点是输入分片。InputSplit 是客户端提交阶段计算出来的逻辑任务划分,它不是 YARN 的资源划分,也不等同于 HDFS block。一个 Split 可以对应一个或多个 block,也可能因为输入格式、压缩格式和切分策略发生变化。YARN 只看 Container 资源请求,MapReduce 才知道某个 Map Task 对应哪个输入分片。

数据本地性也由 MRAppMaster 在申请 Container 时表达:它会把期望节点、机架等信息带给 ResourceManager,让调度器尽量把 Map Task 放到靠近数据的位置。常见层次包括 node-local、rack-local 和 off-rack。node-local 表示计算就在数据所在节点上;rack-local 表示在同机架节点上读取;off-rack 则需要跨机架或更远路径读取。调度器能不能满足本地性,要看队列资源、节点状态和等待策略。

1.3 MRAppMaster:单个作业的应用级协调器

YARN 给应用分配第一个 Container 后,启动的不是 Map Task,而是 MRAppMaster。MRAppMaster 是 MapReduce on YARN 里最容易被低估的角色。它不是全局控制器,而是单个 MapReduce 作业的状态机和调度协调器,负责这个作业内部的完整生命周期。

MRAppMaster 的主要职责包括:

职责 说明
作业状态机 管理 Job、Task、TaskAttempt 的状态转换
资源申请 根据 Map/Reduce 任务需求向 ResourceManager 申请 Container
任务调度 结合输入分片、本地性和任务优先级安排 Task Attempt
失败处理 处理 Task 失败、Container 失败、节点异常和重试
推测执行 识别慢任务并按策略启动额外 attempt
心跳处理 接收 Task Attempt 状态更新并推进状态机
计数器汇总 收集 Map/Reduce Counters,形成作业级统计
输出提交 协调作业成功后的输出提交和失败清理

这个角色解释了为什么 YARN 能同时运行不同框架。ResourceManager 并不知道 MapReduce 的 Shuffle 细节,也不关心一个 Job 有几个 Map、几个 Reduce。它只处理资源请求。MRAppMaster 才知道哪些任务已经完成,哪些任务需要重试,哪些 Reduce 要等待 Map 输出。

在应用详情页里,Attempt ID 对应 ApplicationMaster 的一次尝试,Node 显示它运行在哪个 NodeManager 上,Logs 是进入 AM 日志的入口。对于单机环境,AM 和任务 Container 都在同一个节点上;但在真实集群里,AM 是作业级协调器,Map 和 Reduce 任务可能分散在不同节点。

MRAppMaster 失败时,YARN 可以重新启动 Application Attempt。这个能力和普通 Task 重试不同。Task 重试是 MapReduce 作业内部的失败恢复,AM 重启是 YARN 应用级别的失败恢复,也是 appattempt 机制的核心价值。两者配合起来,才能让一个作业在节点抖动、Container 异常、短暂资源问题下有机会恢复。

从排查角度看,MRAppMaster 日志比普通 Map/Reduce 日志更适合回答“作业为什么这样调度”。普通 Task 日志通常只能说明某个任务进程做了什么,AM 日志则能看到任务状态转换、资源申请、失败重试和作业完成提交。如果应用状态是 FAILED,而 Task 日志里没有明显异常,AM 日志往往是第一入口。

MRAppMaster 还承担了一个很重要的协调职责:它要在 Map 阶段、Shuffle 阶段和 Reduce 阶段之间维护依赖关系。Map 任务不是全部成功以后才对系统可见,Reduce 可以在部分 Map 完成后逐步拉取输出,但最终 Reduce 的输入完整性、失败重试和输出提交仍然由 AM 管理。这个角色使 MapReduce 能在 YARN 通用资源模型上保留自己的执行语义。

因此,MRAppMaster 既不是 ResourceManager 的替代,也不是一个普通 Task。它是单个作业内部的协调器。RM 只承诺“给你资源”,NM 只承诺“帮你启动和监管进程”,AM 才承诺“把这个作业按 MapReduce 的规则跑完”。理解这个边界后,很多问题就不会互相甩锅:调度慢不一定是 AM 问题,Task 失败不一定是 RM 问题,队列拒绝更不是 MapReduce 算法问题。

1.4 Map 和 Reduce Task 运行在 Container 中

MRAppMaster 启动以后,会向 ResourceManager 继续申请资源。Map Task 和 Reduce Task 不再由专用 TaskTracker 进程启动,而是在 NodeManager 分配的 Container 中运行。Container 是 YARN 的资源执行单元,包含内存、vcore、本地目录、环境变量、本地化资源和启动命令;Task 是 Container 内部启动的 JVM/Process,不是 Container 抽象本身。

这个模型有两个好处。第一,MapReduce 任务的资源边界更清楚。一个 Map Task 可以有自己的内存配置,一个 Reduce Task 也可以有自己的内存配置,NodeManager 负责按 Container 维度管理进程。第二,MapReduce 不再绑定节点守护进程的执行模型。NodeManager 只需要知道如何启动、监控和清理 Container,不需要理解 MapReduce 作业逻辑。

MapReduce 任务资源通常由这些参数控制:

参数 作用
mapreduce.map.memory.mb Map Task 申请的 Container 内存
mapreduce.reduce.memory.mb Reduce Task 申请的 Container 内存
mapreduce.map.java.opts Map Task JVM 参数
mapreduce.reduce.java.opts Reduce Task JVM 参数
yarn.scheduler.minimum-allocation-mb 调度器最小内存分配单位
yarn.scheduler.maximum-allocation-mb 单个 Container 可申请的最大内存
yarn.nodemanager.resource.memory-mb NodeManager 可提供给 YARN 的内存

这里有一个容易踩坑的地方:MapReduce 的内存参数不是孤立生效的。mapreduce.map.memory.mb 配得再大,如果超过 yarn.scheduler.maximum-allocation-mb,调度器也不会正常分配。mapreduce.map.java.opts 配得接近 Container 内存上限,也可能因为 JVM 堆外内存、native buffer、压缩库、排序缓冲区或 Shuffle buffer 导致进程被 NodeManager 杀掉。生产环境里要给 off-heap 和框架缓冲区留出余量。

更稳妥的做法是把三层参数一起看:任务 JVM 参数、MapReduce Container 内存、YARN 调度器和 NodeManager 的资源上限。Container 是资源边界,JVM 只是 Container 内部的一个进程。把这两层混在一起,是很多 MapReduce 内存问题的根源。

在小集群里,资源参数还有一个更现实的约束:AM 自己也需要 Container。一个队列看起来有足够资源,但如果最大应用数、用户限制或 AM 资源比例卡住,作业也可能长时间等待。MapReduce 作业启动时先要拿到 AM Container,AM 启动后才能继续申请 Map 和 Reduce Container。所以 ACCEPTED 卡住时,不要只盯着 Map/Reduce 资源参数,也要看队列是否允许新的 AM 启动。

本地资源也是 Container 模型的一部分。NodeManager 启动 Container 前,会把作业 jar、配置文件、缓存文件等资源本地化到节点目录。这个过程由 YARN 负责,不由 MapReduce 自己到处复制文件。好处是应用资源管理统一了,坏处是本地目录、磁盘空间、权限和清理策略都会影响任务启动。单机环境里这些问题不明显,多节点环境里一台机器本地目录损坏,就可能造成某些 Container 反复失败。

日志目录也类似。Container 标准输出、标准错误和框架日志先落在 NodeManager 本地目录,再根据日志聚合配置上传。作业运行时看 NM 本地日志最快,作业结束后看聚合日志更方便。这个流程解释了为什么有时 RM 页面上的 Logs 链接能打开,有时要等日志聚合完成后才能通过 yarn logs 查看完整内容。

1.5 Shuffle 为什么依赖 NodeManager 辅助服务

MapReduce on YARN 里,Shuffle 是一个很好的边界示例。Map Task 结束后会在本地生成输出,Reduce Task 需要从各个节点拉取这些 Map 输出。如果只看 MapReduce 逻辑,Shuffle 像是 Reduce 和 Map 之间的数据传输。但在 YARN 运行模型里,Map Task 作为 Container 结束后,Map 输出仍然要能被 Reduce 拉取,这就需要 NodeManager 提供长期可用的 Shuffle 服务。

这就是 mapreduce_shuffle 辅助服务的作用。它配置在 yarn-site.xml 里,随 NodeManager 启动,并运行在 NodeManager 内部的 HTTP server 上,为 Reduce 端提供 map output fetch endpoint。没有这个服务,Map Task 可以跑完,Reduce Task 却可能在拉取 Map 输出时报错。

常见配置类似这样:

<property>
  <name>yarn.nodemanager.aux-services</name>
  <value>mapreduce_shuffle</value>
</property>
<property>
  <name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name>
  <value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>

这个配置也说明,MapReduce on YARN 并不是“MapReduce 完全自带一切”。它把作业控制逻辑放在 MRAppMaster,把任务进程放在 Container,但 Shuffle 这种跨任务、跨 Container 生命周期的数据服务,需要 NodeManager 配合。

这次 Pi 示例的计数器里能看到 Shuffle 过程是正常的:

Launched map tasks=6
Launched reduce tasks=1
Data-local map tasks=6
Map input records=6
Map output records=12
Reduce input groups=2
Reduce shuffle bytes=168
Reduce input records=12
Shuffled Maps=6
Failed Shuffles=0
Merged Map outputs=6

这几行比 Pi 的结果更有排查价值。Launched map tasks=6 对应命令里的 6 个 map;Launched reduce tasks=1 说明示例作业启动了一个 reduce;Shuffled Maps=6 和 Failed Shuffles=0 表示 Reduce 成功拉取了全部 Map 输出;Merged Map outputs=6 表示 Reduce 端完成了 Map 输出合并。如果 Shuffle 服务异常,这些计数器通常会暴露问题。

Shuffle 的复杂度在于它跨越了多个边界。Map 输出先写在本地磁盘,Reduce 通过网络从多个节点拉取,拉取后还要在 Reduce 端合并、排序,再进入用户的 reduce 函数。这个拉取不是一次性动作,而是 Reduce 端多线程 fetch、失败重试、持续 merge 的过程。任何一个环节出问题,最终都可能表现为 Reduce 慢、Reduce 重试、Fetch failed 或磁盘空间不足。

所以 Reduce 慢不一定是 reduce 函数慢。它可能在等待 Map 输出,也可能在反复拉取失败,也可能在本地 merge 阶段消耗大量磁盘和 CPU。排查时至少要分清三件事:Map 是否稳定产出,Shuffle 是否稳定拉取,Reduce 函数是否真正开始处理数据。Counter、Reduce 日志和 NodeManager 日志组合起来,才能把这三件事拆开。

mapreduce_shuffle 还有一个工程上的启示:YARN 的通用性不是完全无框架感知。YARN 核心不理解 MapReduce 作业语义,但 NodeManager 可以通过 auxiliary service 为特定框架提供节点级服务。这样既保持了资源模型统一,又给 MapReduce 这种有特殊数据交换需求的框架留出了扩展点。

2. 标识、历史和兼容性

2.1 Application ID 和 Job ID 不要混用

MapReduce on YARN 同时存在 Application ID 和 Job ID,这是很多排查混乱的来源。

标识 所属层次 用途
application_1739344332779_0001 YARN ResourceManager 视角的应用
appattempt_1739344332779_0001_000001 YARN ApplicationMaster 的一次尝试
container_1739344332779_0001_01_000001 YARN 运行 AM 或 Task 的 Container
job_1739344332779_0001 MapReduce MapReduce 视角的作业
task_* / attempt_* MapReduce Map 或 Reduce 的任务和尝试

ResourceManager 页面通常围绕 Application ID 展开,JobHistoryServer 更偏向 Job ID、Task ID 和 Counter。命令行也一样,yarn application -status 使用 Application ID,mapred job -status 或历史服务相关接口更关注 Job ID。两者编号后缀看起来相似,但不能随便替换。

还要注意 Application Attempt。appattempt_* 表示 ApplicationMaster 的一次尝试,是 AM failover/retry 的核心标识。一个 Application 可能因为 AM 失败产生多个 attempt,而每个 attempt 又会对应自己的 AM Container 和日志入口。排查 AM 重启、短暂节点故障或应用级恢复时,不能只看 Application ID,还要看具体 appattempt。

在排查时,我通常按这个顺序看:

  1. 先用 Application ID 确认 YARN 层面是否成功启动应用。
  2. 再看 AM Attempt 是否启动、是否有日志入口。
  3. 如果应用进入运行态但作业失败,再进入 MapReduce Job、Task 和 Counter 层面。
  4. 如果 Reduce 阶段异常,重点看 Shuffle、磁盘、本地目录和 NodeManager 日志。
  5. 如果作业完成但输出不正确,再看 OutputCommitter、输入路径、输出路径和业务逻辑。

这个顺序能避免一开始就陷入某个 Task 日志。YARN 层面失败和 MapReduce 内部失败是两类问题,先分层再定位,会快很多。

2.2 JobHistoryServer 和日志聚合的价值

MapReduce 作业完成后,ResourceManager 不会永久保存所有任务细节。它更像应用入口和资源视图,不是完整历史作业视图。真正要看任务列表、Counter、失败尝试和历史执行细节,需要依赖 JobHistoryServer 和日志聚合。

日志聚合的意义在于,Container 运行在各个 NodeManager 本地,日志默认也分散在节点目录里。开启日志聚合后,YARN 会把应用日志收集到 HDFS 等集中位置,用户可以通过 yarn logs -applicationId 查看。对于多节点集群,这比逐台机器登录查看本地日志可靠得多。

这次应用详情里可以看到 Log Aggregation Status=SUCCEEDED,说明日志聚合已经完成。实际排查时可以用:

yarn logs -applicationId application_1739344332779_0001

如果只是验证作业是否成功,ResourceManager 的 state=FINISHED 和 FinalStatus=SUCCEEDED 需要一起看。FINISHED 只是生命周期状态,不等于成功;最终是否成功由 FinalStatus 决定。如果要分析 Map 或 Reduce 为什么慢、哪个 Task 重试最多、Shuffle 是否频繁失败,就需要继续看 JobHistoryServer 和聚合日志。作业运行时看 RM 和 NM,作业完成后看 JHS 和日志,这是 MapReduce on YARN 比较清晰的一条观察路径。

日志聚合还有一个小陷阱:它成功不代表作业成功,它只是说明日志收集动作完成了。一个失败应用也可以有成功的日志聚合,一个成功应用也可能因为日志聚合配置或 HDFS 权限问题导致日志查看不完整。因此状态判断要分开:应用最终状态看 FinalStatus,任务细节看 JobHistory,日志可用性看 Log Aggregation Status。

Counter 也要理解成周期性汇总结果,而不是严格实时的流式指标。Task Attempt 会在运行中汇报进度和计数器,MRAppMaster 聚合后形成作业级 Counter。作业运行时 Counter 可能有延迟或不完整,完成后的 JobHistory 视图通常更适合做最终分析。

命令行和页面也各有价值。页面适合快速看状态、队列、AM、节点和时间线;命令行适合保存证据、批量查询和脚本化排查。例如:

yarn application -status application_1739344332779_0001
yarn logs -applicationId application_1739344332779_0001
hdfs dfs -ls /tmp/hadoop-yarn/staging/root/.staging

前两个命令面向 YARN 应用,第三个命令面向提交阶段的 staging 路径。它们覆盖的是三个不同问题:应用有没有被 RM 接受,Container 日志是否可查,客户端资源是否正常上传。把这些命令串起来,比单独记一个 Web UI 地址更可靠。

2.3 MRv1 兼容性应该怎么看

Hadoop 2 之后仍然保留了大量 MRv1 兼容能力,原因很现实:很多旧作业、脚本、调度平台和数据处理流程不能因为底层资源管理模型变化就全部重写。兼容性让旧 MapReduce API、命令行脚本和历史作业迁移到 YARN 时成本低很多。

但兼容不等于运行模型没有变化。即使用旧 API 编写的作业,到了 YARN 环境里,资源申请、AM 启动、Container 管理、日志聚合、队列调度仍然走 YARN 模型。旧 API 主要影响作业编程接口和部分配置名称,不应该再按 JobTracker/TaskTracker 的方式理解运行路径。

这里需要保留两个判断:

判断 说明
业务代码可以兼容 很多旧 MapReduce 代码仍可运行,不必为了迁移而重写算法
运维模型必须更新 队列、Container、AM、NM、日志聚合是新的排查边界

如果旧脚本只是在命令行里调用 hadoop jar,迁移通常比较直接。如果脚本依赖旧的 JobTracker 地址、旧的历史页面、旧的计数器采集方式,就需要改造监控和排查链路。对于长期运行的集群,真正难的往往不是代码能不能跑,而是周边平台是否已经理解 YARN 的应用模型。

兼容性还会影响配置命名。很多老资料里会出现 mapred.、mapreduce. 混用的情况。YARN 环境仍然保留了不少兼容处理,但新配置应优先使用 mapreduce.* 和 YARN 相关参数。这样做不是为了追求形式统一,而是为了减少团队协作时的歧义。一个配置到底是旧接口兼容项,还是当前运行路径真正读取的参数,排查时差别很大。

对于需要长期维护的作业,我更倾向于把迁移分成两层:代码层尽量保持稳定,只做必要 API 适配;运行层则明确改成 YARN 语言,包括队列、Container、AM、日志聚合、History、资源参数和调度器限制。这样迁移风险最小,也能让运维和开发用同一套词汇讨论问题。

3. 排查链路

3.1 一条更实用的排查链路

MapReduce on YARN 的排查可以按状态分层:

阶段 观察对象 常见问题
提交前 客户端配置、HDFS 路径 jar 不存在、输入路径错误、staging 权限不足
SUBMITTED/ACCEPTED RM、Scheduler、队列 队列容量不足、ACL 拒绝、资源不满足
AM 启动 Application Attempt、AM 日志 AM Container 申请失败、环境变量或本地资源异常
Task 运行 Task Attempt、NM 日志 JVM OOM、磁盘不足、输入数据异常
Shuffle Reduce 日志、Shuffle Counters Shuffle 服务异常、Map 输出丢失、网络或磁盘问题
提交输出 OutputCommitter、HDFS 输出目录已存在、权限不足、提交失败
完成后 JobHistory、聚合日志 任务耗时、重试次数、Counter 异常

这张表比记住某一个命令更重要。MapReduce 作业的生命周期横跨客户端、HDFS、ResourceManager、NodeManager、MRAppMaster 和 JobHistoryServer。只看其中一个组件,很容易把问题定位错。

例如应用长时间处于 ACCEPTED,优先看队列资源和调度器;Map 任务全部完成但 Reduce 卡住,优先看 Shuffle;应用显示成功但输出目录没有预期文件,优先看 OutputCommitter 和输出路径;任务偶发失败但最终成功,优先看 TaskAttempt 重试和节点健康状态。

再举几个更具体的判断。应用刚提交就失败,通常先看客户端和 AM 启动日志,不要急着查 Reduce。应用进入 RUNNING 后很快失败,重点看 AM 是否拿到了作业配置和本地资源。Map 大量失败但 Reduce 没开始,重点看输入数据、Mapper 逻辑和节点本地目录。Reduce 开始后频繁失败,优先看 Shuffle、排序合并、Reduce 内存和磁盘空间。作业最终成功但耗时异常,重点看 Counter、数据倾斜和慢任务。

如果只用一句话概括,就是先判断失败发生在哪个层次,再选择对应工具。YARN 层看 RM、Scheduler、NM 和 Application 日志;MapReduce 层看 Job、Task、Counter 和 JobHistory;数据层看 HDFS 路径、输入格式、输出提交和权限。MapReduce on YARN 的复杂度正来自这些层次叠在一起,排查效率也来自把它们拆开。

4. 小结

MapReduce on YARN 可以用一个统一模型来记:

角色 定位
ResourceManager scheduler,负责集群资源调度和应用生命周期入口
NodeManager executor,负责节点侧 Container 启动、监控和清理
MRAppMaster coordinator,负责单个 MapReduce 作业的状态机和执行协调
Container resource unit,表示一次资源分配和运行上下文
Map/Reduce Task execution unit,是 Container 内部启动的 JVM/Process

MapReduce on YARN 的关键不是 MapReduce 语义变了,而是它从“集群内置执行模型”变成了“YARN 上的一种应用框架”。ResourceManager 管全局资源,NodeManager 管节点执行,MRAppMaster 管单个作业,Container 承载 AM 和 Task,Shuffle 通过 NodeManager 辅助服务支撑 Reduce 拉取 Map 输出,JobHistoryServer 和日志聚合负责完成后的追踪。

这套拆分让 MapReduce 继续保留成熟的数据处理模型,同时把资源管理能力交给 YARN。理解这一点后,很多配置和排查动作就更自然了:队列问题看 Scheduler,应用状态看 RM,节点执行看 NM,作业内部看 MRAppMaster 和 JobHistory,Shuffle 问题看 NodeManager 辅助服务和 Counter。MapReduce 仍然是 MapReduce,但它已经运行在一个更通用的资源操作系统上。


文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录