我在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
所以看起来它是不同输出格式的常见问题。
我希望有这个问题经验的人可以对这个问题做出解释。为什么会发生这种情况以及解决这个问题的可靠方法是什么?
答案 0 :(得分:1)
我这几天和我的同事一起做了一些调查。这是我的想法:从spark 1.2开始,我们使用带有堆外内存的Netty来在混洗和缓存块传输期间减少GC。在我的情况下,如果我试图增加足够大的内存开销。我将获得Max直接缓冲区异常。当Netty阻止传输时,默认情况下会有五个线程将数据块抓取到目标执行器。在我的情况下,一个单块太大而无法放入缓冲区。所以gc在这里没有帮助。我的最终解决方案是在重新分配之前再做一次重新分配(1)。只需要比原始分区多10倍的分区。通过这种方式,我可以减少每个块Netty传输的大小。通过这种方式,我终于成功了。
我还想说,将大数据集重新分区为单个文件并不是一个好的选择。这种极不平衡的场景会浪费您的计算资源。
欢迎任何评论,我仍然不理解这一部分。