Distcp - Container超出物理内存限制

时间:2016-12-19 15:44:07

标签: hadoop jvm oozie hortonworks-data-platform distcp

我已经和distcp一起玩了好几天了,我发誓我已经足够google了。这是我的用例:

使用案例

我在某个位置有一个主文件夹,说 / hdfs / root ,有很多子目录(深度不固定)和文件。

卷:200,000个文件〜= 30个GO

我需要在另一个位置复制客户端 / hdfs / root 的子集,例如/ hdfs / dest 该子集由可以随时间更新的绝对路径列表定义。

卷:50,000个文件〜= 5个GO

您理解我不能使用简单的hdfs dfs -cp /hdfs/root /hdfs dest,因为它没有经过优化,它会占用每个文件,并且它没有更新模式。

解决方案POC

我最终以两种方式使用hadoop distcp:

Algo 1 (simplified):
# I start up to N distcp jobs in parallel for each subdir, with N=MAX_PROC (~30)

foreach subdir in mylist: 
    # mylist = /hdfs/root/dirX/file1 /hdfs/root/dirX/file2 ...
    mylist = buildList(subdirs)
    hadoop distcp -i -pct -update mylist /hdfs/dest/subdir &

Algo 2
# I start one distcp that has a blacklist
blacklist = buildBlackList()
hadoop distcp -numListstatusThread 10 -filters blacklist -pct -update /hdfs/root /hdfs/dest

Algo 2甚至没有启动,似乎在源和黑名单之间建立差异对他来说太难了,所以我使用Algo 1,它可以工作。

OZZIE WORKFLOW

知道我需要在Oozie工作流程中安排所有工作流程。 我把algo 2放在shell动作中,因为我有很多distcp命令而且我没有掌握递归或在oozie中循环。

一旦启动,过了一会儿,我收到以下错误: 容器超出物理内存限制。当前用法:使用17.2 GB的16 GB物理内存

好吧那么,我会增加更多的记忆:

<configuration>
    <property>
        <name>oozie.launcher.mapreduce.map.memory.mb</name>
        <value>32768</value>
    </property>
    <property>
        <name>oozie.launcher.mapreduce.map.java.opts</name>
        <value>-Xmx512m</value>
    </property>
</configuration>

我仍然得到:容器超出物理内存限制。当前用法:使用32 GB GB 32 GB物理内存但是这项工作的寿命是前一次的两倍。

我的群集上的RAM不是无限的,所以我无法继续前进。以下是我的假设:

  1. distcp作业不释放内存(JVM垃圾收集器?)
  2. Oozie将所有distcp作业添加为当前内存使用情况,这是愚蠢的
  3. 这不是正确的方法(我知道,但仍然)
  4. 此外,我对内存管理还有很多不了解的事情,它非常模糊(yarn,oozie,jvm,mapreduce)。

    谷歌搜索时,我注意到很少有人在讨论真正的distcp用例,这篇文章是4天之久:https://community.hortonworks.com/articles/71775/managing-hadoop-dr-with-distcp-and-snapshots.html并解释了快照用法,我不能在我的案例中使用。

    我也听说过http://atlas.incubator.apache.org最终通过“标记”文件并授予特定用户访问权限来解决我的问题,因此我们可以避免复制到某个位置。我的管理团队正在研究它,但我们不会让它知道生产。

    我非常绝望。帮助我。

1 个答案:

答案 0 :(得分:7)

YARN容器建立在Linux&#34; cgroups&#34;之上。这些&#34; cgroups&#34;用于对CPU进行软限制,但不对RAM进行限制...
因此,YARN使用了一种笨拙的解决方法:它会定期检查每个容器使用多少RAM,并且强制杀死任何超过配额的内容。所以你丢失了执行日志,只得到你看到的那个可怕的消息。

在大多数情况下,您正在运行某种JVM二进制文件(即Java / Scala实用程序或自定义程序),因此您可以通过设置自己的JVM配额(尤其是-Xmx)来逃避,以便始终保持在YARN限制下。这意味着由于安全边际,一些浪费的RAM。但最糟糕的情况是,当JVM内存不足时,JVM会彻底失败,您可以获得执行日志 in extenso 并可以开始调整配额 - 或修复内存泄漏{ {1}}

那么在你的具体情况下会发生什么?您正在使用Oozie来启动shell - 然后shell启动:-/命令,该命令在JVM中运行。嵌入式JVM 的必须设置最大堆大小。

<小时/> 简而言之:如果你将32GB分配给运行shell的YARN容器(通过hadoop),那么你必须确保shell中的Java命令不会消耗超过28GB的堆(继续使用)安全的一面)。

如果幸运的话,设置一个env变量就可以了:

oozie.launcher.mapreduce.map.memory.mb

如果你不幸运,你将不得不打开export HADOOP_OPTS=-Xmx28G hadoop distcp ........... 混合使用不同设置的不同env变量的整个混乱(由显然讨厌你的人设置,在你甚至不知道的初始脚本中)由JVM使用复杂的优先级规则进行解释。玩得开心。您可以查看that very old post有关挖掘位置的提示。