配置Yarn内存的核心答案是:先明确物理机可用内存,再依次设置NodeManager总内存、Container内存上下限,最后调整应用的内存比例,三层缺一不可。
yarn 内存配置 最佳实践
很多人在配Yarn时只改一个yarn.nodemanager.resource.memory-mb,结果集群不是内存超卖就是大量Container被杀,业内专家指出,Yarn的内存管理本质是“租约制”:NodeManager向系统“租”一块内存,再切分成小份租给Container,你管不好这层租约,应用跑得再欢也白搭。
第一层:NodeManager可分配内存
配置文件是yarn-site.xml,核心参数是yarn.nodemanager.resource.memory-mb,这个值表示本节点所有Container能使用的物理内存总和,它不等于机器内存,例如一台128GB内存的服务器,要预留系统进程、OS页缓存、HDFS DataNode等约25%的内存,留下的75%才能交给Yarn。
此时别急着填96GB,还要考虑是否部署了其他服务,如果节点同时跑了HBase RegionServer或Elasticsearch,那memory-mb要再砍掉一大块,行业共识认为,单机内存超过64GB时,Yarn分配比控制在70%~80%是比较稳妥的区间。
第二层:Container内存上下限
yarn.scheduler.minimum-allocation-mb和yarn.scheduler.maximum-allocation-mb定义了每个Container的内存范围,前者默认为1GB,后者默认8GB,重点在于:maximum值决定了单个任务能申请的内存上限,如果你的Spark Executor要12GB,而maximum还是8GB,任务会直接申请失败,日志里出现“Invalid request”或内存不足信息。
建议把这两个值调整为:
- minimum:2GB或4GB
- maximum:等于NodeManager总内存,或者其一半(如果你希望单个任务独占一半以上内存,就设为全部)
同时确保yarn.nodemanager.vmem-check-enabled的设置符合预期,默认true,会检查虚拟内存,经常误杀容器,对于Spark或Flink跑大内存作业,可以将yarn.nodemanager.vmem-pmem-ratio调大到2.5或更大,甚至直接关闭虚拟内存检查。
第三层:分配给应用的内存比例
Yarn只管分配,不关心应用内部怎么用,但应用自己需要向Yarn申请内存,这一层最容易“内存不够”却怪Yarn配置错了。

例如MapReduce,mapreduce.map.memory.mb和mapreduce.reduce.memory.mb要显式设置,不要依赖默认值,因为默认Map内存是1GB,遇到大字典或复杂解析会OOM,还要调整mapreduce.map.java.opts(老版本是mapred.child.java.opts),让堆内存约占Container内存的80%,Container给了2GB,堆却只给512MB,浪费空间不说,GC也会频繁触发。
实操验证配置是否生效
修改完配置文件后,执行以下步骤验证:
- 首先关闭旧服务:
yarn-daemon.sh stop resourcemanager和yarn-daemon.sh stop nodemanager(新版本用yarn --daemon stop)。 - 然后清空临时状态:
rm -rf /tmp/hadoop-yarn/(仅测试环境用,生产环境谨慎)。 - 接着逐个启动ResourceManager和NodeManager。
- 使用
yarn node -list -all查看节点状态,确认内存值显示正确。 - 在Web UI的“Nodes”页面,检查
Vmem和Physical Memory使用率,确保没有接近100%。
yarn 内存溢出 怎么解决
当你的任务反复报Container killed by the ApplicationMaster、OutOfMemoryError或者GC overhead limit exceeded,多数组件问题出在应用自身而非Yarn,但“yarn 内存溢出 怎么解决”这个搜索词背后,大家真正想知道的是排查路径。
先看日志再调参
别一上来就加内存,第一件事是查看Container日志,在ResourceManager Web UI里找到任务,点开Attempt的日志链接,筛选stderr部分,如果是堆内存溢出,会出现java.lang.OutOfMemoryError: Java heap space;如果是堆外内存溢出,会出现Direct buffer memory或native memory相关字样。
| 症状 | 可能原因 | 优先调整项 |
|---|---|---|
| 频繁Full GC | 堆太小 | 增大容器内存及java.opts |
| 虚拟内存超限 | vmem检查误判 | 关闭vmem检查或调大比例 |
| 物理内存被kill | 节点总内存超卖 | 减少NodeManager内存 |
| 任务启动后瞬间失败 | maximum小于请求值 | 调大scheduler maximum |
调整有先后顺序:先扩堆,再扩容器
不少数据工程师直接改mapreduce.map.memory.mb翻倍,却忘记同步改java.opts,结果容器内存大了,堆还是原来那点,问题依旧,正确的顺序是:
- 把Container大小增加到需求值的1.2~1.5倍。
- 同步调整对应
java.opts为Container大小的75%~80%。 - 同时将
yarn.app.mapreduce.am.resource.mb(ApplicationMaster内存)适当调大,避免AM先死。
别忘了检查物理机缓存
Yarn执行任务时,HDFS读缓存和网络缓冲都会占用Page Cache,如果你的/proc/meminfo里Committed_AS接近CommitLimit,说明系统有内存泄漏风险,此时需要调低NodeManager的memory-mb,给系统留出足够余量,多数情况下,12GB内存的机器,Yarn最多给8GB是安全的。
不同集群规模的内存配置建议
没有一套配置能通吃所有机器,但可以参考下面的推荐值,这里以每台机器内存为基准,不考虑CPU密集模型训练场景。
- 48GB内存节点:NodeManager给24GB,yarn.scheduler.maximum设为8GB,单个Container上限2GB,适合小规模数据清洗。
- 64GB内存节点:NodeManager给40GB,maximum设12GB,minimum设2GB,适合跑中等Spark作业。
- 128GB内存节点:NodeManager给96GB,maximum设32GB,minimum设4GB,适合大容量ETL和机器学习训练。
- 256GB内存节点:NodeManager给192GB,maximum设48GB,但要注意
yarn.nodemanager.vmem-pmem-ratio必须调大或关闭检查。
如果你用的是CDH或HDP等发行版,建议在Cloudera Manager或Ambari的页面里修改,避免手改XML导致配置管理混乱,同时要记得给每个节点设置相同的yarn.scheduler.maximum-allocation-mb,否则任务在不同节点间迁移时会报错。
yarn 内存配置 对Spark任务的影响
如果你的作业是Spark On Yarn,那么spark.executor.memory、spark.executor.cores和spark.executor.memoryOverhead这三个参数需要和Yarn的maximum-allocation-mb

联动,常见错误是executor.memory + executor.memoryOverhead超过了Yarn允许的Container最大值,导致ApplicationMaster反复重试。
推荐计算公式:每个Executor的Spark内存申请 = spark.executor.memory + spark.executor.memoryOverhead(默认为Executor内存的10%),把这个总和与yarn.scheduler.maximum-allocation-mb比较,保证前者小于等于后者,例如你设置了2个Executor,每个分配8GB,overhead 1GB,那么Yarn的maximum至少是9GB,否则会出现“Container launch failed”或“Allocation request exceeds maximum”的提示。
Q&A:yarn 内存配置 常见问题
如何查看当前Yarn内存的实际使用情况?
在终端运行yarn node -list -all获取节点ID,再运行yarn node -status <节点ID>,输出中的Capability显示该节点可分配内存,Used Memory显示已占用,如果Used长期超过Capability的90%,说明集群内存紧张,需要降低应用并行度或增加节点。
关闭了虚拟内存检查会不会导致物理内存被过量使用?
关闭yarn.nodemanager.vmem-check-enabled只是放弃了对虚拟内存上限的监控,物理内存超限仍由操作系统内核强制回收,如果Container内存总和超过机器物理内存,会发生严重换页甚至是OOM Kill,所以关闭虚拟内存检查的前提是你已经限制了NodeManager总内存,并且应用堆外内存消耗可控,对于JVM作业,同时控制-XX:MaxDirectMemorySize可以降低风险。
同一套Yarn集群可以同时跑MapReduce和Spark吗?
可以,但需要为两类任务分别规划内存,MapReduce任务建议在配置中设置yarn.app.mapreduce.am.resource.mb和yarn.app.mapreduce.am.command-opts,Spark任务则通过Spark配置覆盖资源需求,为了防止Spark挤占MapReduce资源,可以在调度器上配置容量百分比,例如默认队列给MapReduce留30%内存,Spark队列占70%,同时使用分层队列管理。
配置内存的核心原则:先给操作系统留足余量,再给NodeManager封顶,最后让应用在Container范围内自治,按这个顺序去检查你的yarn-site.xml,大部分内存问题都能迎刃而解。

