YARN

时间:2017-01-22 09:43:14

标签: hadoop apache-spark memory-management

我在YARN客户端模式下运行Spark应用程序,有六个执行程序(每个四个核心和执行程序内存= 6 GB,开销= 4 GB,Spark版本:1.6.3 / 2.1.0)。

我发现我的执行程序内存不断增加,直到被节点管理器杀死;它提供的信息告诉我提升spark.yarn.excutor.memoryOverhead

我知道这个参数主要控制堆外分配的内存大小。但我不知道Spark引擎何时以及如何使用这部分内存。同时增加那部分内存并不总能解决我的问题。有时它有效,有时不行。当输入数据很大时,它趋于无用。

仅供参考,我的应用程序的逻辑非常简单。这意味着将一天内生成的小文件(一天一个目录)合并为一个,然后写回HDFS。以下是核心代码:

val df = spark.read.parquet(originpath)
              .filter(s"m = ${ts.month} AND d = ${ts.day}")
              .coalesce(400)
val dropDF = df.drop("hh").drop("mm").drop("mode").drop("y").drop("m").drop("d")

dropDF.repartition(1).write
      .mode(SaveMode.ErrorIfExists)
      .parquet(targetpath)

源文件可能有数百到数千个级别的分区。整个镶木地板文件大约是1到5 GB。

此外,我发现在从不同机器读取数据的步骤中,随机读取的大小大约是输入大小的四倍,这是有线的或我不知道的一些原则。

无论如何,我已经为这个问题做了一些搜索。有些文章说它是在直接缓冲存储器上(我没有设置自己)。

有些文章说人们用更频繁的全GC来解决它。

此外,我发现Stack Overflow上有一个人的情况非常相似: Ever increasing physical memory for a Spark application in YARN

这家伙声称这是一个镶木地板的错误,但一条评论质疑他。此邮件列表中的人员也可能在几小时前收到来自blondowski的电子邮件,他在撰写JSON时描述了此问题: Executors - running out of memory

所以看起来它是不同输出格式的常见问题。

我希望有这个问题经验的人可以对这个问题做出解释。为什么会发生这种情况以及解决这个问题的可靠方法是什么?

1 个答案:

答案 0 :(得分:1)

我这几天和我的同事一起做了一些调查。这是我的想法:从spark 1.2开始,我们使用带有堆外内存的Netty来在混洗和缓存块传输期间减少GC。在我的情况下,如果我试图增加足够大的内存开销。我将获得Max直接缓冲区异常。当Netty阻止传输时,默认情况下会有五个线程将数据块抓取到目标执行器。在我的情况下,一个单块太大而无法放入缓冲区。所以gc在这里没有帮助。我的最终解决方案是在重新分配之前再做一次重新分配(1)。只需要比原始分区多10倍的分区。通过这种方式,我可以减少每个块Netty传输的大小。通过这种方式,我终于成功了。

我还想说,将大数据集重新分区为单个文件并不是一个好的选择。这种极不平衡的场景会浪费您的计算资源。

欢迎任何评论,我仍然不理解这一部分。