
说一个大多数人刚接触Hadoop时都会被绕晕、但集群一旦跑不顺十有八九跟它有关的东西——YARN。我第一次搭三节点集群的时候以为HDFS能正常读写数据了MapReduce作业也应该顺手就能跑起来。结果提交一个小作业等了五分钟还显示ACCEPTED翻到ResourceManager的Web界面一看队列可用内存是0容器一直起不来。那时候我才意识到真正卡住我的不是MapReduce代码而是最底层的资源管理没有配好。如果你拆开看整个Hadoop技术栈YARN是最容易被忽略、又最绕不开的一层。它负责统一管理和调度整个集群的CPU、内存、磁盘等资源让MapReduce、Spark、Flink这些计算框架按需申请资源、并发运行。说白了HDFS解决“数据放哪里”YARN解决“算力怎么分”这两者配合到位上层计算引擎才有发挥空间。这篇文章不打算罗列网上到处都能搜到的“YARN三大组件分别是什么”这类概念而是从一线运维和调优视角把YARN的架构逻辑、调度器选型、关键参数、实际配置和排错经验完整梳理一遍。不管你是刚搭完伪分布式集群的新手还是正在为集群资源利用率发愁的运维这套思路都可以直接参考。1. 为什么说YARN是大数据集群的“中枢神经”1.1 从第一代MapReduce说起资源管理为什么会被单独拆出来在YARN诞生之前Hadoop跑的是第一代MapReduce架构。那时候所有作业调度和资源分配都集中在JobTracker上而实际执行任务的TaskTracker分散在各个节点。JobTracker一个人要干好几份活既要做资源管理又要做作业调度还要管任务失败重试、进度监控和状态上报。集群规模一上来JobTracker就成了绝对瓶颈——单点故障、内存溢出、调度延迟高一个几千个Map任务的大作业能把整个集群拖到濒临崩溃。更麻烦的是这种设计把资源管理和MapReduce计算引擎强耦合在一起。你想让Spark在同样的HDFS数据上跑要么重新搭一套集群要么跟MapReduce排队抢资源共享程度非常差。所以社区后来下了决心干脆把资源管理这层从计算框架里抽出来做成一个独立的通用资源调度层这就是YARN诞生的直接背景。它解决的问题很本质让“资源分配”和“具体计算”解耦让多种计算框架共用同一批物理资源。1.2 一个作业在YARN上是怎么走完全程的我先用最直白的方式描述一下整个流程。你提交一个MapReduce作业或者说任何兼容YARN的应用实际上是提交给ResourceManagerRM会找一台NodeManager启动一个ApplicationMaster这个AM就是你这个作业的“项目经理”。它负责向RM申请资源、拿到资源后通知对应的NodeManager启动Container然后真正的计算任务在Container里跑。等任务全部完成AM再向RM注销所有资源释放回集群。从资源管理角度看整个生命周期最关键的有三个阶段客户端向RM申请启动AM、AM向RM请求后续运行所需的资源、任务运行期间NM和RM的心跳汇报。每一步都涉及内存和CPU的动态分配任何一处参数不匹配表现出的症状就是作业卡住、容器反复被杀、节点失联。这也是为什么很多人调业务代码调了半天没效果最后发现是YARN资源参数的问题。1.3 YARN的价值不只是“资源够不够”更是“多框架共存”我见过不少刚入行的同学以为YARN就是给MapReduce提供内存和CPU的东西。其实它最大的意义在于让计算框架和资源管理彻底解耦。同一个Hadoop集群上你可以同时跑MapReduce做批处理、Spark跑SQL、Flink跑实时流各算各的互不干扰靠的就是YARN统一的资源抽象。这也是大数据面试题里经常问“YARN和MapReduce是什么关系”的原因——很多人只记得Hadoop等于HDFS加MapReduce却忽略了中间还夹着一层更底层的资源调度系统。2. 认识YARN架构里的四个关键角色2.1 ResourceManager管全局的“总调度台”ResourceManager通常简称RM是整个YARN集群的决策层。它接收客户端的作业提交请求、维护整个集群的资源账本、决定哪个作业拿多少资源、让哪个节点启动Container。RM本身不直接执行计算任务它的职责就是“分配”和“拍板”。你可以把它理解成机场塔台所有飞机的起飞降落都得听它指挥但塔台自己不开飞机。生产环境里RM必须做高可用。最常见的方案是Active/Standby双节点部署让ZooKeeper帮忙做自动故障切换。如果你只在伪分布式环境里做实验不配RM高可用那RM宕机时整个集群所有作业都会中断只能等它恢复。这也是为什么在真实的高可用Hadoop集群里ZooKeeper不只是给HDFS的NameNode做HA用的它同时也在给YARN的RM值守。做集群整合的时候把RM和NameNode放在同一批ZK节点上管理是最常见的做法。2.2 NodeManager每个节点上的“资源管家”NodeManagerNM跟数据节点绑定每台机器跑一个。它负责启动和管理本机上的Container定时向RM主动汇报节点资源状态比如还剩多少内存、几个vcore、正在跑几个容器。RM做调度决策时会优先选择资源充足的节点。NM相当于每个仓库分站点的主管知道自己这有多少货架、多少货物定期向总部汇报。有一点我要特别提醒新手NodeManager只是个“管家”它不会替你做调度决策也不关心你跑的是MapReduce还是Spark。它只看容器的事启动、监控、回收。如果你某天发现某个节点任务总是失败先去排查这台机器的NM日志和本地目录磁盘占用大概率是磁盘满了或者资源被系统进程吃掉。2.3 ApplicationMaster每个作业的“项目经理”AM是YARN架构里最容易被忽略、但又非常重要的角色。每个提交到YARN上的应用都会有一个属于自己的AMMapReduce作业有MapReduce AMSpark on YARN会启动Spark AM。AM的作用是向RM申请Container资源、在这些Container上调度执行任务、跟踪任务状态、失败时重新申请资源和重试。理解了AM的存在你就知道为什么YARN能同时支撑多种计算框架。RM只负责给AM分配资源至于AM拿到资源后去跑什么任务是MapReduce的Mapper还是Spark的ExecutorRM根本不关心。这种“总调度台”加“项目经理”的协作模式让YARN天然支持多框架共存。如果你面试时被问到“YARN是如何支持多种计算框架的”核心回答点就在这里。2.4 Container最小资源单元到底是什么Container是YARN分配资源的最小单元它抽象了内存、CPU、磁盘等资源同一个节点上可以同时跑多个Container。Container的大小由RM配置决定比如最小分配1GB内存加1个vcore最大可以到几十GB。从实现层面看Container不是一台独立的虚拟机而是NodeManager进程内部的一个资源边界NodeManager通过控制进程和cgroup来约束它真正能使用多少CPU和内存。3. 三种调度器横评FIFO、Capacity、Fair3.1 先看核心差异与适用场景YARN内置三种资源调度器FIFO、Capacity Scheduler、Fair Scheduler。它们的核心差异在于“多个作业或队列抢资源时谁先谁后、能不能弹性扩容”。FIFO最简单粗暴严格按提交顺序先进先出前面的大作业不跑完后面的作业只能一直等待。好处是思路清晰、实现简单坏处是资源利用率低不适合多租户、多作业共存的场景。我只在本地做单作业测试时用过FIFO生产环境基本不会选它。Capacity Scheduler是生产环境默认配置也是大多数公司的选择。它把集群资源按比例切分成多个队列每个队列内部可以再切子队列队列之间互不抢占。比如default队列分60%、BI队列分30%、ad_hoc队列分10%每个队列有独立的资源上限和用户权限从机制上杜绝了一个作业吃光整个集群资源的极端情况。Fair Scheduler讲究“资源公平”不需要提前预留队列系统根据当前运行的作业数动态计算每个作业能分到多少资源跑得慢的作业可以让出资源给跑得快的作业。适合用户多、作业类型杂、期望资源动态平衡的团队。3.2 三种调度器的对比速查表对比维度FIFOCapacity SchedulerFair Scheduler调度模型先来先服务队列配额、层级按作业动态公平分配是否支持多队列否是是多租户隔离弱强中资源弹性无有支持maximum-capacity有适用场景测试、单作业生产默认、多业务线多用户共享、动态负载配置复杂度最低中等中等3.3 生产环境为什么默认选Capacity从我自己的实操经验来看绝大多数公司选Capacity并不是因为它的功能最多而是因为“队列资源隔离”这个特性太适合企业内部多团队共用一套集群的场景。数据平台给算法团队、数据仓库团队、报表团队各建一个队列分别设定资源比例再通过队列访问控制列表把用户分开。这样就算某个团队突然提交一堆大作业也不会把其他团队的资源全部抢走调度层面的“交通事故”能少很多。Fair Scheduler在资源公平性上有优势但它的动态分配机制在多队列配额控制上不够直观很多运维人员习惯用Capacity那种“明确百分比”的配置方式。两种调度器都能用但如果你接手的是别人搭好的集群建议先确认当前配置别轻易切换因为切换调度器会导致集群重启所有运行中作业全部中断。4. 集群当中最关键的配置项与计算逻辑4.1 内存和CPU从物理机到Container的换算这部分我直接上公式和例子。假设你有三台128GB内存、32核CPU的物理机。注意不是所有内存都能给YARN操作系统、HDFS DataNode、系统监控进程都要占用一部分。常见经验是给操作系统和non-YARN进程留25%到30%剩下大约70%到75%给YARN NodeManager。按这个比例算yarn.nodemanager.resource.memory-mb 128 * 1024 * 0.7算出来大约91750MB实践中我习惯取整到92160MB差不多90GB。yarn.nodemanager.resource.cpu-vcores 32 * 0.8约25个vcore。然后确定单个Container的最小和最大范围yarn.scheduler.minimum-allocation-mb 1024yarn.scheduler.maximum-allocation-mb 8192或根据大作业实际需要再调大yarn.scheduler.minimum-allocation-vcores 1yarn.scheduler.maximum-allocation-vcores 8这里有一个关键点RM在给容器分配资源时内存会按minimum-allocation的整数倍向上取整。比如任务申请1500MBRM实际分配时可能按2048MB计算。所以你会发现明明配置了Spark执行器内存是2GB实际容器占用的资源可能比这还多一点。4.2 一张表看懂yarn-site.xml里最值得调的参数参数默认值推荐调整说明yarn.scheduler.classCapacityScheduler生产环境显式配置避免环境差异导致默认值变化yarn.nodemanager.resource.memory-mb8192必须改成物理机实际可分配给YARN的内存yarn.nodemanager.resource.cpu-vcores8按物理核数乘以0.75到0.85计算yarn.scheduler.minimum-allocation-mb1024资源碎片最小粒度不需要频繁改yarn.scheduler.maximum-allocation-mb8192如果任务容器内存需求大适当调大yarn.nodemanager.pmem-check-enabledtrue容器频繁被杀时可临时关闭验证不建议长期关yarn.nodemanager.vmem-check-enabledtrue虚拟内存超限是常见杀手谨慎处理yarn.log-aggregation-enablefalse开启后日志集中聚合排错会方便很多4.3 为什么内存分配比例不同会导致任务失败写配置的时候最常见的坑就是MapReduce任务的内存参数和YARN容器内存参数不匹配。比如给某个Map任务申请了2048MB内存mapreduce.map.memory.mb2048但YARN单个Container最大只允许1024MB那任务会直接提交失败报错类似“Resource Request exceeds maximum allowed allocation”。反过来如果最大Container内存调得非常大但MapReduce任务声明的内存又太小会造成资源浪费一个10节点的集群可能只能同时跑几个任务看起来利用率极低。这个问题的核心矛盾是“容器资源”和“任务实际需要资源”之间的对齐。调优的经验法则是先定容器范围再设置MapReduce或Spark的执行内存保证所有申请值都能被YARN的容器资源范围覆盖同时给JVM堆外内存留出余量。比如任务实际需要2GB堆内存申请容器时最好给到2.5GB或3GB。4.4 capacity-scheduler.xml多队列配置实例下面是一份我在测试集群用过的配置片段逻辑就是建两个业务队列一个default跑日常批处理一个bi给报表任务用两个队列之间用maximum-capacity限制弹性上限。property nameyarn.scheduler.capacity.root.queues/name valuedefault,bi/value /property property nameyarn.scheduler.capacity.root.default.capacity/name value70/value /property property nameyarn.scheduler.capacity.root.bi.capacity/name value30/value /property property nameyarn.scheduler.capacity.root.bi.maximum-capacity/name value60/value /property这里的capacity是权重不是绝对内存两个队列加起来是100。maximum-capacity等于60表示当default队列没有任务时bi队列最多可以借用到60%的集群资源但不能超过这个上限。这样既做到基础隔离又保留弹性是很多公司实际采用的“配额加弹性”策略。5. 实操过程与核心环节实现5.1 三节点测试集群的搭建要点搭建一套能验证YARN行为的集群至少需要1台master跑RM2台worker跑NM。性能要求不用太高但有几个点必须注意所有节点时间要同步建议用NTP或chrony主机名和/etc/hosts要一致master要能SSH免密登录到所有workerJDK版本和Hadoop版本要匹配尽量选官方支持的LTS版本。配置方面把core-site.xml里的fs.defaultFS指向HDFS的NameNodeyarn-site.xml里把yarn.resourcemanager.hostname指向master然后整个配置目录完整分发到所有节点。记得在hadoop-env.sh、yarn-env.sh里设置好JAVA_HOME。我第一次搭建时漏了yarn-env.sh里的JAVA_HOME结果启动YARN时直接报找不到Java环境排查了半天才发现是环境变量没生效。这种小坑在集群初始化阶段特别常见建议所有配置文件修改后都用grep确认一遍关键项。5.2 启动确认YARN状态首次启动先用start-dfs.sh启动HDFS再执行start-yarn.sh启动YARN。启动完用jps查看进程master节点应该有ResourceManagerworker节点应该有NodeManager。接着可以用一组命令快速确认集群状态yarn node -list yarn application -list yarn top如果想用脚本或程序去管理YARN任务最方便的方式不是解析命令行输出而是直接调YARN的REST API。比如用Python访问http://rm-host:8088/ws/v1/cluster/apps就能拿到所有应用的JSON数据拿到指定应用状态就拼上applicationId。下面是一段我在自动化运维脚本里用过的Python调用片段import requests rm_host master01 apps_url fhttp://{rm_host}:8088/ws/v1/cluster/apps resp requests.get(apps_url) data resp.json() for app in data.get(apps, {}).get(app, []): print( app.get(id), app.get(name), app.get(state), app.get(queue) )这种方式比shell命令更容易集成到监控平台里而且REST API返回的信息更全比如应用提交时间、内存秒数、CPU秒数等。你在设计自动化运维系统时这一层接口非常值得提前接入。5.3 通过实际队列看资源分配配置好队列后提交一个测试MapReduce作业到不同队列观察效果。用hadoop jar命令加参数-Dmapreduce.job.queuenamebi指定队列。提交后打开RM的8088端口Web界面切到Scheduler页面可以看到每个队列的运行中应用数、容器数、活跃内存情况。按照常见经验如果bi队列下缓存了大量任务但default队列没任务资源会自动允许bi队列用到maximum-capacity上限。但如果你发现一个队列里积压了一堆任务却总是拿不到资源优先检查是不是队列的maximum-capacity或用户限制设得太小。这里有个细节用户在某个队列下的最大资源占用比例由yarn.scheduler.capacity.root. .user-limit-factor控制默认是1表示单个用户最多用到队列资源的一定比例多用户共享时特别值得关注。6. 常见问题与排查技巧实录6.1 任务一直等待、一直ACCEPTED八成是资源不足作业提交到YARN后一直显示ACCEPTED既不运行也不报错这种情况我遇到最多。首先要看RM Web界面的Scheduler页面确认目标队列的可用内存。如果可用内存为0或很小说明要么是其他任务占了资源要么是队列容量设置太小。也可以用命令yarn application -list -appStates ACCEPTED把所有等待中的应用列出来看谁在占用资源。这里有一个隐蔽的细节很多集群配置了延迟调度资源不足时会等待一段时间再触发所以看起来卡住不一定是故障。等一两分钟再观察如果还一直ACCEPTED再从资源配额上找原因。6.2 NodeManager失联优先查磁盘和心跳生产上最常见的NodeManager故障是节点“挂了”在RM页面能看到RUNNING节点数减少。排查顺序很重要先登录对应节点看磁盘NM本地目录满了会写不了状态直接导致失联再看NM日志重点找“Unexpected error”或“Connection refused”然后确认时间同步NM和RM时间差太大会导致心跳不合法如果NM内存资源被系统杀掉还得看dmesg。我自己处理过一次NM反复挂掉的事件最后发现是NM本地目录在/tmp下面/tmp被系统清理服务清空NM状态文件被删了。恢复方式就是清理残留后换一个稳定目录比如/data/yarn/nm-local-dir再从配置层面绑定到非临时目录。这类问题在虚拟机和容器环境里特别容易出现配置NM本地目录时一定要选持久化路径。6.3 容器被杀、OOM、虚拟内存超限容器启动后不久就被杀是最让人头疼的。常见原因有三个物理内存超过容器上限YARN通过监控会主动kill掉超限容器虚拟内存超限有些任务比如JVM、Python的虚拟内存占用很大导致vmem检查判死系统层面物理内存不足NM进程被系统OOM Killer杀掉。排查时先看container相关日志再检查yarn-site.xml里vmem-check-enabled开关。我的经验是如果确认任务本身没问题可以先临时把vmem-check-enabled设为false验证但不要长期关闭。真正要做的还是把任务的堆内存和JVM参数调好让申请值比实际使用量有20%到30%的余量。比如给Map任务申请3GB堆内存JVM参数-xmx最好设成2GB到2.5GB剩余空间留给元空间和堆外内存。6.4 新手避坑速查表现象大概率原因快速对策作业一直ACCEPTED队列资源不足查看Scheduler页面配额占用情况容器反复被杀内存参数不匹配检查MapReduce或Spark内存与容器范围对齐NM节点失联磁盘满或状态目录被清清理磁盘、换稳定NM本地目录报错超过max allocation任务申请内存超过最大容器调大scheduler.maximum-allocation-mb提交任务失败提示队列不存在未指定队列名用-Dmapreduce.job.queuename指定队列虚拟内存oomvmem检查误杀先验证再永久调整vmem-check-enabled7. 从资源管理角度回看整个大数据集群7.1 排查问题时先看资源再想代码我个人遇到大数据任务失败时排查顺序永远是“资源层优先”。如果YARN上的容器都起不来那就先别去一行行读业务代码错不错误。先确认队列空闲、内存充足、节点存活再进集群容器看日志。否则很容易绕一大圈最后才发现只是资源配置没对齐。7.2 日常巡检最该盯的几个指标日常维护中我会重点盯这几个指标RM Web界面里的集群可用内存与总内存是否有长时间ACCEPTED的应用NodeManager数量与实际节点数是否一致每个队列的利用率是否长期超过90%或长期低于10%。如果某个队列长期占用90%以上要么给任务瘦身要么调整队列容量。如果长期低于10%说明资源分配策略不合理。另外如果做了HDFS节点扩容记得同步检查新节点的NM资源配置否则数据量上去了计算资源反而跟不上。7.3 最后分享一个土办法有一次BI队列的任务总是凌晨堆积查了半天发现不是资源问题而是作业提交时间集中在整点把队列瞬时打满了。解决办法很简单在调度层给不同业务的定时任务错峰并给关键任务设置更高优先级。做资源管理不可能完全靠调参数业务侧的节奏和管理侧的习惯同样重要。这也是我后来给别人做集群资源评估时一定会先看任务时间分布的原因——很多“资源不够”的表象背后其实是“提交节奏不合理”。