Hadoop YARN参数介绍(一)

很多朋友在刚开始搭建和使用 YARN 集群的时候,很容易就被纷繁复杂的配置参数搞晕了:参数名称相近、新老命名掺杂、文档说明模糊 。特别是那几个关于内存的配置参数,即使看好几遍文档也不能完全弄懂含义不说,配置时一不小心就会张冠李戴,犯错误。

如果你同样遇到了上面的问题,没有关系,在这篇文章中,我就为大家梳理一下 YARN 的几个不易理解的内存配置参数,并结合源码阐述它们的作用和原理,让大家彻底清楚这些参数的含义。

一、YARN 的基本架构

介绍 YARN 框架的介绍文章网上随处都可以找到,我这里就不做详细阐述了。下面附上一张 YARN 框架图,方便引入我们的后续内容:

                                                                                  yarn架构图

二、内存相关参数

YARN中关于内存配置的参数呢,主要也就是那么几个,我已经整理出来列在了下表中。大家先看一下,对于表中各列的意义,我会在本节后面详细说明;而对于每个参数的意义,我会放在下节进行详细解释。

                                                                                      内存参数列表

三、参数说明

下面分别来讲解每个参数的功能和意义。

mapreduce.map.java.opts 和 mapreduce.map.memory.mb

我反复斟酌了一下,觉得这两个参数还是要放在一起讲才容易让大家理解,否则割裂开会让大家困惑更大。这两个参数的功能如下:

  1. mapreduce.map.java.opts: 运行 Map 任务的 JVM 参数,例如 -Xmx 指定最大内存大小;

  2. mapreduce.map.memory.mb: Container 这个进程的最大可用内存大小。

这两个参数是怎样一种联系呢?首先大家要了解 Container 是一个什么样的进程。简单地说,Container 其实就是在执行一个脚本文件(launch_container.sh),而脚本文件中,会执行一个 Java 的子进程,这个子进程就是真正的 Map Task。

                                                                              Container 和 Map Task 的关系图 

理解了这一点大家就明白了,mapreduce.map.java.opts 其实就是启动 JVM 虚拟机时,传递给虚拟机的启动参数,而默认值 -Xmx200m 表示这个 Java 程序可以使用的最大堆内存数,一旦超过这个大小,JVM 就会抛出 Out of Memory 异常,并终止进程。而 mapreduce.map.memory.mb 设置的是 Container 的内存上限,这个参数由 NodeManager 读取并进行控制,当 Container 的内存大小超过了这个参数值,NodeManager 会负责 kill 掉 Container。在后面分析 yarn.nodemanager.vmem-pmem-ratio 这个参数的时候,会讲解 NodeManager 监控 Container 内存(包括虚拟内存和物理内存)及 kill 掉 Container 的过程。

紧接着,一些深入思考的读者可能就会提出这些问题了:

Q: 上面说过,Container 只是一个简单的脚本程序,且里面仅运行了一个 JVM 程序,那么为何还需要分别设置这两个参数,而不能简单的设置 JVM 的内存大小就是 Container的大小?

A: YARN 作为一个通用的计算平台,设计之初就考虑了各种语言的程序运行于这个平台之上,而非仅适用 Java 及 JVM。所以 Container 被设计成一个抽象的计算单元,于是它就有了自己的内存配置参数。

Q: JVM 是作为 Container 的独立子进程运行的,与 Container 是两个不同的进程。那么 JVM 使用的内存大小是否受限于 Container 的内存大小限制?也就是说,mapreduce.map.java.opts 参数值是否可以大于 mapreduce.map.memory.mb 的参数值?

A: 这就需要了解 NodeManager 是如何管理 Container 内存的了。NodeManager 专门有一个 monitor 线程,时刻监控所有 Container 的物理内存和虚拟内存的使用情况,看每个 Container 是否超过了其预设的内存大小。而计算 Container 内存大小的方式,是计算 Container 的所有子进程所用内存的和。上面说过了,JVM 是 Container 的子进程,那么 JVM 进程使用的内存大小,当然就算到了 Container 的使用内存量之中。一旦某个 Container 使用的内存量超过了其预设的内存量,则 NodeManager 就会无情地 kill 掉它。

mapreduce.reduce.java.opts 和 mapred.job.reduce.memory.mb

和上面介绍的参数类似,区别就是这两个参数是针对 Reducer 的。

 

mapred.child.java.opts

这个参数也已经是一个旧的参数了。在老版本的 MR 中,Map Task 和 Reduce Task 的 JVM 内存配置参数不是分开的,由这个参数统一指定。也就是说,这个参数其实已经分成了 mapreduce.map.java.opts 和 mapreduce.reduce.java.opts 两个,分别控制 Map Task 和 Reduce Task

yarn.nodemanager.resource.memory-mb
从这个参数开始,我们来看 NodeManager 的配置项。
这个参数其实是设置 NodeManager 预备从本机申请多少内存量的,用于所有 Container 的分配及计算。这个参数相当于一个阈值,限制了 NodeManager 能够使用的服务器的最大内存量,以防止 NodeManager 过度消耗系统内存,导致最终服务器宕机。这个值可以根据实际服务器的配置及使用,适度调整大小。例如我们的服务器是 96GB 的内存配置,上面部署了 NodeManager 和 HBase,我们为 NodeManager 分配了 52GB 的内存。

yarn.nodemanager.vmem-pmem-ratio 和 yarn.nodemanager.vmem-check-enabled
yarn.nodemanager.vmem-pmem-ratio 这个参数估计是最让人困惑的了。下面给大家解释一下这个参数到底在控制什么。

首先,NodeManager 接收到 AppMaster 传递过来的 Container 后,会用 Container 的物理内存大小 (pmem) * yarn.nodemanager.vmem-pmem-ratio 得到 Container 的虚拟内存大小的限制,即为 vmemLimit。

然后,NodeManager 在 monitor 线程中监控 Container 的 pmem(物理内存)和 vmem(虚拟内存)的使用情况。如果当前 vmem 大于 vmemLimit 的限制,则 kill 掉进程。

上述控制是针对虚拟内存的,针对物理内存的使用 YARN 也有类似的监控。yarn.nodemanager.vmem-check-enabled 参数则十分简单,就是上述监控的开关。

上面的介绍提到了 vmemLimit,也许大家会有个疑问:这里的 vmem 究竟是否是 OS 层面的虚拟内存概念呢?我们来看一下源码是怎么做的。

ContainerMontor 就是上述所说的 NodeManager 中监控每个 Container 内存使用情况的 monitor,它是一个独立线程。ContainerMonitor 获得单个 Container 内存(包括物理内存和虚拟内存)使用情况的逻辑如下:

Monitor 每隔 3 秒钟就更新一次每个 Container 的使用情况;更新的方式是:

  1. 查看 /proc/pid/stat 目录下的所有文件,从中获得每个进程的所有信息;

  2. 根据当前 Container 的 pid 找出其所有的子进程,并返回这个 Container 为根节点,子进程为叶节点的进程树;在 Linux 系统下,这个进程树保存在 ProcfsBasedProcessTree 类对象中;

  3. 然后从 ProcfsBasedProcessTree 类对象中获得当前进程 (Container) 总虚拟内存量和物理内存量。

由此大家应该立马知道了,内存量是通过 /proc/pid/stat 文件获得的,且获得的是该进程及其所有子进程的内存量。所以,这里的 vmem 就是 OS 层面的虚拟内存概念。

 

                                                  内存参数组合示意图

原文地址:https://www.cnblogs.com/coco2015/p/11435185.html