资讯详情

YARN Capacity Scheduler默认配置全解析:从原理到调优实践

📅 2026/10/17 15:52:06 | 华诺云谱 👁 阅读
YARN Capacity Scheduler默认配置全解析:从原理到调优实践
1. 从一份空配置文件说起为什么默认值值得单独拎出来讲很多人第一次接触YARN的Capacity Scheduler都是被那一堆capacity-scheduler.xml里的配置项劝退的。更让人困惑的是你打开这个文件发现里面可能只有寥寥几行甚至干脆是空的——但集群照样跑起来了任务照样提交成功了。这时候问题就来了那些没写的配置项到底是谁在起作用默认值是什么它们会不会在某一天突然咬你一口我自己就吃过这个亏。早些年维护一个小规模集群capacity-scheduler.xml基本是原封不动从别处拷过来的里面只改了一个队列名。结果某天业务方反馈说一个明明资源很充裕的集群任务却排队排到天荒地老。排查了半天才发现是yarn.scheduler.capacity.maximum-am-resource-percent这个默认值在作祟——ApplicationMaster占用的资源比例被限制住了导致同时能跑的Application数量上不去后面的任务只能干等。这件事让我意识到一个道理默认配置不是没有配置而是别人替你做的配置决策。你如果不清楚这些决策是什么就等于把集群的调度行为交给了一个你从未谋面的陌生人。所以这篇内容我想把Capacity Scheduler的默认配置体系完整地拆一遍不是简单罗列参数表而是讲清楚每个默认值背后的设计意图、它在什么场景下会成为瓶颈、以及你应该在什么时候主动去改它。这篇内容适合谁看如果你正在搭建或维护一个基于YARN的集群不管是几台机器的小集群还是几十台的规模只要你用到了Capacity Scheduler这是目前生产环境最主流的调度器这些默认值就和你直接相关。如果你只是刚接触YARN想搞明白调度器到底怎么工作那从默认值入手其实是个很好的切入点——因为默认值反映的是社区对大多数场景的假设理解了这些假设你就理解了调度器的基本逻辑。需要提前说明的是不同发行版和不同版本的YARN默认值可能会有细微差异。我下面讲的内容以社区版Hadoop 3.x为主线涉及2.x有差异的地方会单独标注。另外所有参数的实际生效值最可靠的确认方式永远是查官方文档或者直接看源码里的默认常量我这里的经验之谈是帮你建立判断框架具体数值请以你实际使用的版本为准。2. 资源分配的基本盘那些决定集群能跑多少的默认参数2.1 队列容量与最大容量的默认逻辑Capacity Scheduler最核心的概念就是队列。你可以把整个集群的资源想象成一块大蛋糕每个队列分到一块。capacity-scheduler.xml里最基础的配置就是yarn.scheduler.capacity.root.queues它定义了根队列下面有哪些子队列。默认情况下如果你不配置这个参数root队列下只有一个名为default的队列。这个默认行为其实挺合理的——对于单队列场景你不需要做任何额外配置就能跑起来。但问题在于很多团队一开始就是单队列后来业务多了想拆队列却发现历史配置和默认值混在一起改起来容易出错。每个队列有两个关键容量参数capacity和maximum-capacity。capacity是保证容量表示这个队列至少能用到集群资源的百分比maximum-capacity是上限容量表示这个队列最多能用到的百分比。默认情况下capacity是100如果是root下唯一的队列maximum-capacity默认也是100。这里有个容易踩的坑maximum-capacity默认值100意味着队列可以弹性占用其他队列的空闲资源。这本来是Capacity Scheduler的一个优点——资源不浪费。但如果你有两个队列A和BA的capacity是60B是40maximum-capacity都是100那么当B空闲时A可以占用到100%的资源。听起来很好对吧但如果B突然来了大量任务A需要把资源还给B这个回收过程不是瞬间完成的需要等A上的Container自然结束。如果你的任务都是长任务那B就只能干等着。所以我的经验是对于有明确SLA要求的队列把maximum-capacity设成一个合理的值不要图省事用默认的100。比如A队列保证60%那maximum-capacity设成70或80就够了给其他队列留出足够的弹性空间也避免资源回收时的长时间等待。2.2 资源计算器与最小分配单元yarn.scheduler.capacity.resource-calculator这个参数决定了调度器用什么方式计算资源。默认值是org.apache.hadoop.yarn.util.resource.DefaultResourceCalculator它只考虑内存不考虑CPU。这个默认值在Hadoop 2.x时代是合理的因为那时候大部分集群的瓶颈在内存。但现在CPU密集型的任务越来越多只按内存调度就会出现内存还有富余但CPU已经打满的情况任务跑起来慢得要命。所以如果你用的是Hadoop 3.x并且集群里CPU密集型任务占比不低建议改成DominantResourceCalculator它会同时考虑内存和CPU取两者中占比更高的那个作为主导资源来调度。另一个关键默认值是yarn.scheduler.minimum-allocation-mb默认1024MB。这个值决定了单个Container能申请到的最小内存。如果你提交一个任务申请的内存小于这个值YARN会把它提升到这个最小值。比如你申请512MB实际会给你1024MB。这看起来是多给了但如果你有大量小内存任务每个都按1024MB算集群能同时跑的Container数量就会比预期少很多。对应的还有yarn.scheduler.maximum-allocation-mb默认8192MB。这个值限制单个Container能申请的最大内存。如果你有任务需要16GB内存不改这个参数就永远申请不到任务会一直卡在等待资源的状态。我见过好几次有人排查任务为什么一直ACCEPTED的问题最后发现就是这个默认值卡住的。提示minimum-allocation-mb和maximum-allocation-mb这两个值在yarn-site.xml里也有对应的配置项实际生效值以yarn-site.xml为准。capacity-scheduler.xml里的同名参数是调度器层面的覆盖优先级更高。改的时候两个文件都要看一眼避免改了没生效。2.3 队列资源限制的默认百分比除了队列级别的capacity和maximum-capacity还有几个全局的百分比限制参数它们的默认值直接影响集群的资源利用率。yarn.scheduler.capacity.maximum-am-resource-percent默认值是0.1也就是10%。这个参数限制所有ApplicationMaster能占用的最大资源比例。为什么要有这个限制因为AM本身不干活它只是管理任务的。如果AM占用了太多资源真正跑任务的Container就没资源了。10%的默认值在大多数场景下是合理的但如果你的任务都是小任务、多批次的模式——比如每个任务只跑几分钟但提交频率很高——那10%可能就不够用了AM会排队等待导致任务提交后迟迟不启动。yarn.scheduler.capacity.maximum-applications默认值是10000这是整个集群同时能处于运行状态的Application数量上限。yarn.scheduler.capacity.maximum-am-resource-percent和这个参数配合使用前者限制资源后者限制数量。一般来说10000够用了但如果你做的是大规模并行计算可能需要调高。还有一个容易被忽略的默认值yarn.scheduler.capacity.node-locality-delay默认是40。这个参数控制调度器在放弃节点本地性之前愿意等待多少个调度机会。简单说如果你的任务需要读取HDFS上的数据调度器会尽量把Container分配到数据所在的节点上减少网络传输。但如果等了40次机会还没等到那个节点有空闲资源调度器就会放弃本地性把Container分配到其他节点。40这个默认值在节点数量不多的集群里问题不大但在大规模集群里40次调度机会可能很快就过去了导致大量任务失去本地性网络传输成为瓶颈。如果你发现任务的数据本地性比例很低可以适当调高这个值比如到80或100给调度器更多时间去找本地节点。3. 队列层级与权限默认配置下的多租户行为3.1 子队列的默认继承规则当你开始规划多队列结构时会涉及到队列的层级关系。比如root下面有root.prod和root.devroot.prod下面又有root.prod.etl和root.prod.report。这种层级结构在capacity-scheduler.xml里是通过点号分隔的队列名来表示的。默认情况下子队列的容量之和必须等于父队列的容量。比如root.prod的capacity是60那root.prod.etl和root.prod.report的capacity加起来必须等于60。如果你配了不等于60的值调度器启动时会报错。这个规则在默认配置下是强制的没有开关可以关掉。但有一个默认行为很多人不知道如果你没有显式配置子队列的maximum-capacity它会继承父队列的maximum-capacity。这个继承逻辑在大多数情况下是合理的但如果你父队列的maximum-capacity是100子队列也继承100那子队列理论上可以占用整个集群的资源——这显然不是你想要的。所以我的习惯是每建一个子队列都显式地把capacity和maximum-capacity都写清楚不依赖继承。3.2 用户和组的默认限制Capacity Scheduler支持按用户和组做资源限制。默认情况下yarn.scheduler.capacity.root.queue.user-limit-factor的值是1。这个参数的含义是单个用户最多能使用队列capacity的多少倍。默认1表示用户最多用到队列的保证容量不能超用。但这里有个细节user-limit-factor只限制单个用户不限制用户组。如果你没有配置yarn.scheduler.capacity.root.queue.acl_submit_applications默认是所有用户都可以向这个队列提交任务。这在生产环境里是有风险的——万一某个用户写了个死循环疯狂提交任务整个队列的资源都会被它占满。所以我的建议是生产队列一定要配ACL。acl_submit_applications控制谁可以提交任务acl_administer_queue控制谁可以管理队列。默认值都是*所有人这个默认值在开发环境没问题在生产环境就是安全隐患。还有一个默认值是yarn.scheduler.capacity.root.queue.minimum-user-limit-percent默认100。这个参数保证每个用户至少能用到队列资源的这个百分比。默认100意味着如果一个队列有多个用户每个用户都觉得自己应该能用100%实际调度时会按活跃用户数平均分配。比如3个用户同时提交任务每个用户最多用到队列的33.3%。这个默认行为在大多数场景下是公平的但如果你有VIP用户需要优先保障就需要调低这个值给VIP用户配更高的user-limit-factor。3.3 队列状态与默认运行行为yarn.scheduler.capacity.root.queue.state的默认值是RUNNING。这意味着新建的队列默认就是运行状态可以接受任务提交。对应的还有STOPPING和STOPPED状态用于优雅地停止队列——STOPPING状态下不再接受新任务但已提交的任务继续跑完STOPPED状态下连已提交的任务也会被kill掉。这个默认值本身没什么问题但我想提醒的是如果你要做队列的临时下线维护不要直接改成STOPPED。我见过有人为了快速清空队列直接把state改成STOPPED结果正在跑的重要任务被kill了数据一致性出了问题。正确的做法是先改成STOPPING等任务自然跑完再改成STOPPED。另外yarn.scheduler.capacity.root.queue.max-parallel-apps这个参数在较新版本里才有默认值是-1表示不限制。如果你不限制一个队列里可以同时跑很多Application每个Application都要占一个AM的槽位。结合前面说的maximum-am-resource-percent默认10%如果Application数量太多AM资源不够后面的Application就会排队。所以在大规模场景下建议显式设置一个合理的max-parallel-apps值避免AM资源被过度争抢。4. 当默认值不够用典型场景下的调优判断与操作4.1 场景一小文件多、任务碎AM资源不够用这是我遇到最多的情况。业务方做的是日志分析每天产生几十万个小的分析任务每个任务跑几十秒就结束。集群资源其实很充裕但任务就是排队。排查思路是这样的先看yarn.scheduler.capacity.maximum-am-resource-percent的当前值。如果是默认的0.1那集群总资源的10%被用来跑AM。假设集群有100GB内存那AM最多用10GB。每个AM默认占1GByarn.app.mapreduce.am.resource.mb的默认值那同时最多跑10个Application。但你有几十万个任务要提交每个任务都要一个AM10个AM的并发度显然不够。调整方法把maximum-am-resource-percent调高比如到0.3或0.4。但要注意调高这个值意味着AM占用的资源多了真正跑任务的资源就少了。所以更好的做法是同时降低单个AM的资源占用——把yarn.app.mapreduce.am.resource.mb从默认的1536MB注意不是1024MapReduce的AM默认是1536MB降到1024MB甚至768MB。这样同样的资源比例下能跑更多的AM。还有一个配套参数是yarn.scheduler.capacity.maximum-applications默认10000。如果你每天提交几十万个任务这个值可能不够需要调高到几十万。但调太高也有风险——YARN的ResourceManager要维护每个Application的状态数量太多会加重RM的负担GC压力也会变大。所以这个值要结合RM的实际承载能力来定。4.2 场景二队列资源被一个用户占满前面提到过user-limit-factor默认是1minimum-user-limit-percent默认是100。这两个默认值组合起来在多用户场景下会出现一种情况如果队列里只有一个活跃用户它可以占用队列100%的资源因为minimum-user-limit-percent是100只有一个用户时它可以用全部。这本身没问题但如果这个用户是不速之客——比如某个开发人员不小心提交了一个大任务——它会把整个队列占满其他用户的任务全部排队。解决方法是双管齐下一方面把user-limit-factor设成一个小于1的值比如0.5这样单个用户最多用队列保证容量的一半另一方面把minimum-user-limit-percent也调低比如到25这样即使有多个用户每个用户也至少能用到25%的资源不会被完全饿死。但这里有个权衡user-limit-factor设得太低正常的大任务也会被限制跑起来变慢。我的经验值是对于共享队列user-limit-factor设在0.5到0.8之间比较合适既防止单用户霸占又不至于过度限制。4.3 场景三资源回收慢队列切换不顺畅前面讲过maximum-capacity默认100会导致资源弹性占用。当队列A占用了队列B的空闲资源而B突然需要资源时A需要归还。归还的过程是等A上的Container自然结束不再新建Container直到A的资源占用降到它的capacity以下。这个过程的快慢取决于A上任务的平均运行时长。如果A上都是长任务比如跑几个小时那B可能要等几个小时才能拿回资源。这在生产环境里是不可接受的。怎么判断和解决首先看你的任务类型。如果是长任务为主那maximum-capacity就不要设成100设成比capacity高10到20个百分点就够了。比如A的capacity是40maximum-capacity设成60。这样A最多超用20%的资源回收时也只需要等这20%的Container结束时间可控。另外可以配合yarn.scheduler.capacity.root.queue.maximum-allocation-mb和maximum-allocation-vcores来限制单个Container的大小。如果单个Container太大回收时等一个Container结束就要很久。把最大Container限制在一个合理范围回收的粒度就更细速度更快。4.4 场景四节点本地性差任务跑得慢如果你发现任务的Map阶段耗时很长而且日志里大量出现remote read或者数据本地性比例很低那可能是node-locality-delay的默认值40不够用。这个参数的工作机制是这样的调度器在分配Container时会优先考虑数据所在的节点。如果那个节点没有空闲资源调度器会把这次机会跳过等下一次调度机会再试。连续跳过40次之后调度器就放弃本地性把Container分配到其他节点。在大集群里调度机会来得很快40次可能几秒钟就过去了。如果你的任务数据量很大远程读取的代价很高那就应该调高这个值。我一般会调到80到100给调度器更多耐心。但也不能无限调高否则任务会一直等本地节点反而延长了等待时间。这个值的调整需要结合集群规模和任务的数据量来试没有万能值。还有一个相关参数是yarn.scheduler.capacity.node-locality-delay的兄弟——yarn.scheduler.capacity.rack-locality-additional-delay默认是-1表示禁用机架本地性延迟。机架本地性是比节点本地性更宽松的概念如果数据所在节点没资源但同机架的其他节点有资源也算本地因为机架内网络通常比跨机架快。默认禁用意味着调度器只考虑节点本地性不考虑机架本地性。如果你集群的机架内带宽很好可以启用这个参数设一个比node-locality-delay更大的值比如120让调度器在放弃节点本地性后再等一段时间看能不能找到同机架的节点。5. 默认配置的版本差异与验证方法5.1 Hadoop 2.x与3.x的关键默认值变化如果你是从Hadoop 2.x升级到3.x有几个默认值的变化需要特别注意。最明显的是yarn.scheduler.capacity.resource-calculator。在2.x里默认是DefaultResourceCalculator只算内存。到了3.x虽然默认值还是DefaultResourceCalculator但社区强烈建议改成DominantResourceCalculator而且很多发行版在打包时已经帮你改好了。如果你升级后发现CPU调度行为和以前不一样先检查这个参数。另一个变化是yarn.scheduler.capacity.maximum-am-resource-percent的默认值。2.x里是0.13.x里也是0.1但3.x对AM的资源计算更精细了同样的0.1在不同集群规模下效果可能不同。升级后建议重新评估这个值。还有yarn.scheduler.capacity.node-locality-delay2.x默认是403.x也是40但3.x的调度器实现有优化同样的延迟值下本地性表现可能更好。如果你在2.x里调过这个值升级后可以适当回调观察效果。5.2 怎么确认当前生效的默认值最直接的方法是看ResourceManager的Web UI。在Scheduler页面里有一个Configuration标签里面列出了所有调度器配置项的当前生效值。这个页面显示的是最终生效值也就是默认值和你的配置文件合并后的结果。如果你不确定某个参数到底是多少先来这里看。另一个方法是查日志。ResourceManager启动时会在日志里打印调度器的初始化配置。搜索capacity-scheduler或者CapacityScheduler关键字能看到它加载了哪些配置、哪些用了默认值。这个方法的好处是能看到哪些参数你显式配了哪些是默认的对于排查我明明配了为什么不生效这类问题特别有用。如果你有源码环境最权威的方法是直接看CapacitySchedulerConfiguration类里的常量定义。每个配置项的默认值都在那里而且有注释说明设计意图。这个方法适合想深入理解调度器行为的同学。注意修改capacity-scheduler.xml后不需要重启整个YARN集群。Capacity Scheduler支持热加载——在ResourceManager的Web UI上点击Refresh Queues按钮或者在命令行执行yarn rmadmin -refreshQueues新的配置就会生效。但要注意热加载只对队列结构、容量、权限这类配置生效像resource-calculator这种影响调度器核心逻辑的参数还是需要重启RM才能生效。改配置前最好确认一下这个参数是否支持热加载避免改了没生效还找不到原因。5.3 默认值不是最优值但通常是安全值最后我想强调一个观念默认值的设计目标是在大多数场景下不出错而不是在特定场景下最优。社区在设定默认值时优先考虑的是稳定性、兼容性和普适性。比如maximum-am-resource-percent默认0.1对于大多数批处理场景是够用的node-locality-delay默认40对于中小集群是合理的。但你的集群不是大多数场景你有自己的业务特点、硬件配置和SLA要求。所以正确的做法是先理解默认值是什么、为什么这么设然后根据你的实际情况去调整。调整的时候一次只改一个参数改完观察一段时间确认效果后再改下一个。不要一次性改一堆参数那样出了问题根本不知道是哪个参数导致的。我在实际运维中的体会是Capacity Scheduler的调优是一个渐进式的过程。集群刚上线时用默认值跑一段时间收集监控数据——队列资源利用率、任务等待时间、AM并发数、数据本地性比例。有了这些数据你才知道瓶颈在哪里才知道该调哪个参数。凭感觉调参往往是把一个问题换成另一个问题。另外每次调整配置后一定要记录改了什么、为什么改、改完效果如何。这个记录在几个月后你或者你的同事排查问题时价值巨大。我见过太多团队配置改来改去最后没人记得为什么某个参数是现在这个值出了问题只能从头排查。好的运维习惯比任何调优技巧都重要。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑