如果一个 Container 运行期间使用的内存超出了分配的限制,YARN 的默认处理机制是什么?
在 YARN 中,如果一个 Container 运行期间使用的内存超出了系统为其分配的限制,YARN 的默认处理机制是:由该节点上的 NodeManager 直接将该 Container 强制杀死(Kill)。
具体来说,YARN 的内存监控和处理机制包含以下几个核心细节:
1. 监控主体与方式
- 执行者:每个节点上的 NodeManager 负责监控运行在该节点上的所有 Container。
- 监控方式:NodeManager 会启动一个监控线程(默认每隔 3 秒检查一次),通过读取 Linux 系统的
/proc目录,计算出该 Container 及其产生的所有子进程(Process Tree)所消耗的内存总和。
2. 物理内存与虚拟内存的双重检查
YARN 默认会同时检查 物理内存(Physical Memory, pmem) 和 虚拟内存(Virtual Memory, vmem)。只要其中任何一个超标,Container 都会被杀掉。
- 物理内存超限 (PMEM Check):
- 如果 Container 的实际物理内存使用量超过了分配的值(例如分配了 1GB,但使用了 1.1GB)。
- 默认配置:
yarn.nodemanager.pmem-check-enabled默认为true。
- 虚拟内存超限 (VMEM Check):
- YARN 默认允许的虚拟内存是物理内存的 2.1 倍(由
yarn.nodemanager.vmem-pmem-ratio控制)。例如,分配了 1GB 物理内存,则虚拟内存上限为 2.1GB。 - 如果进程树申请的虚拟内存总量超标,哪怕实际物理内存没用完,也会被杀掉。
- 默认配置:
yarn.nodemanager.vmem-check-enabled默认为true。(注:在较新的 Hadoop 版本中,由于 Java 进程(尤其是 CentOS 6/7 环境下)经常会申请大量无害的虚拟内存导致误杀,很多企业会在配置中将此项设为 false)。
- YARN 默认允许的虚拟内存是物理内存的 2.1 倍(由
3. 典型的错误日志
当 Container 因为内存超限被杀掉时,你通常会在 ApplicationMaster 或 NodeManager 的日志中看到类似下面这样非常经典的报错信息:
Container [pid=xxx,containerID=xxx] is running beyond physical memory limits. Current usage: 1.2 GB of 1 GB physical memory used; 2.5 GB of 2.1 GB virtual memory used. Killing container.
4. 杀死 Container 后的影响
- 任务重试:Container 被杀掉后,ApplicationMaster(例如 Spark 的 Driver 或 MapReduce 的 MRAppMaster)会收到该 Container 失败的通知。通常,计算框架会尝试在其他节点上重新运行该任务(Task)。
- 应用失败:如果同一个任务重试失败的次数达到了框架设定的上限(例如 MapReduce 默认 4 次),则整个应用程序(Application)将宣告失败。
💡 常见的解决建议
如果你遇到了这种默认被 Kill 的情况,通常有以下几种处理方式:
- 调大分配内存:增加单个 Container 的内存配置(例如调大 Spark 的
spark.executor.memory或 MR 的mapreduce.map.memory.mb)。 - 增加堆外内存/Overhead:Java 进程除了 JVM 堆内存,还需要堆外内存。可以调大
spark.yarn.executor.memoryOverhead以防止物理内存超限。 - 关闭虚拟内存检查:如果是虚拟内存超限但物理内存正常,强烈建议在
yarn-site.xml中将yarn.nodemanager.vmem-check-enabled设置为false。