【发布时间】:2017-01-22 09:43:13
【问题描述】:
我正在 YARN 客户端模式下运行一个 Spark 应用程序,其中有六个执行器(每个四个核心和执行器内存 = 6 GB,开销 = 4 GB,Spark 版本:1.6.3 / 2.1.0)。
我发现我的 executor 内存一直在增加,直到被节点管理器杀死;它给出了告诉我提升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)
源文件可能有成百上千级的分区。 Parquet 文件的总大小约为 1 到 5 GB。
另外我发现在shuffle从不同机器读取数据的步骤中,shuffle read的大小大约是输入大小的4倍,这是连线还是什么原理我不知道。
无论如何,我已经为这个问题做了一些搜索。有文章说是在直接缓冲内存上(我自己没设置)。
有人说人们用更频繁的full GC来解决它。
另外,我在 StackOverflow 上发现一个人的情况非常相似:Ever increasing physical memory for a Spark application in YARN
这家伙声称这是镶木地板的错误,但有评论质疑他。此邮件列表中的人也可能在数小时前收到一封来自 blondowski 的电子邮件,他在编写 JSON 时描述了此问题:Executors - running out of memory
所以对于不同的输出格式来说,这似乎是一个常见的问题。
我希望有此问题经验的人可以对此问题进行解释。为什么会发生这种情况以及解决此问题的可靠方法是什么?
【问题讨论】:
-
我首先要说
repartition(1)和/或coalesce(1)在 Spark 中主要是反模式,除非您的数据非常小,然后您可以收集结果并以通常的方式写入. -
@eliasah 还有其他有效的方法来完成我的组合工作吗?
-
为什么要把所有东西都放在一个 parquet 文件中?
-
@eliasah 实际上,我知道这会是个问题。但组长确定每天只有一个文件。另外,我希望知道为什么引擎会返回堆外内存的信息。 THX
-
这是问题所在。在 1 到 5G 之间拥有一个文件是分布式环境中的另一个巨大反模式。换句话说,就是不要这样做。
标签: hadoop apache-spark memory-management