Spark - java.lang.OutOfMemoryError:请求的数组大小超过VM限制

时间:2018-05-02 22:07:57

标签: apache-spark pyspark

我正在尝试对一个7节点集群上Cloudera的Spark(2.1.0)中的数据帧进行groupBy操作,总共有大约512GB的RAM。我的代码如下。

ndf = ndf.repartition(20000)
by_user_df = ndf.groupBy(ndf.name) \
            .agg(collect_list("file_name")) \
            .withColumnRenamed('collect_list(file_name)', 'file_names')


by_user_df = by_user_df.repartition(20000)    
by_user_df.count()

ndf是一个包含2列的数据帧,用户ID和文件名。我试图通过userid创建一个文件名列表,以传递给CountVectorizer和集群。

我收到以下错误

java.lang.OutOfMemoryError: Requested array size exceeds VM limit
    at org.apache.spark.sql.catalyst.expressions.codegen.BufferHolder.grow(BufferHolder.java:73)
    at org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIterator.processNext(Unknown Source)
    at org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43)
    at org.apache.spark.sql.execution.WholeStageCodegenExec$$anonfun$8$$anon$1.hasNext(WholeStageCodegenExec.scala:377)
    at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:408)
    at org.apache.spark.shuffle.sort.UnsafeShuffleWriter.write(UnsafeShuffleWriter.java:166)
    at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)
    at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)
    at org.apache.spark.scheduler.Task.run(Task.scala:99)
    at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:322)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

根据我的阅读,这是因为分配的数组要大于VM在连续内存中可以处理的数组,要么大于数组大小的系统最大值。许多建议是通过拆分更多分区来实现更多并行化。

我有大约6k用户和大约7k的文件名。我注意到死亡的执行者大部分时间都花在垃圾收集中。

到目前为止,我已尝试过以下内容:

  1. 重新分区ndf数据帧和结果数据帧。我已经在每个重新分区参数中尝试了多达60k。
  2. 我已经将步骤中的“spark.sql.shuffle.partitions”设置为20000
  3. 我已将执行程序内存提升到25G
  4. 即使死亡的执行者似乎不是驱动程序,我也将驱动程序内存提升到了25G。
  5. 作为这个问题的更新:我意识到在这种情况下我正在对数据进行二进制聚类,所以我真的只需要每个文件名中的一个。将collect_list更改为collect_set会使我获得所需的输出,并且显然足够小以在给定参数内运行。我仍然会尝试修复原始案例。

1 个答案:

答案 0 :(得分:0)

首先,我不太明白为什么你需要这么高的分区值。我不知道你在7名工作人员中拥有多少核心,但我怀疑你需要超过200个分区(你使用的分区数量极高,实际上可以解释为什么你的工人死于垃圾收集)

您的问题看起来像JVM定义中的内存问题,所以我认为没有理由增加驱动程序或工作程序内存。

我认为您需要的是设置Xss或Xmx或MaxPermSize,如下所示:How to fix "Requested array size exceeds VM limit" error in Java?

为此,您需要在运行spark时使用--conf spark.driver.extraJavaOptions和--conf spark.executor.extraJavaOptions。

例如:

--conf spark.driver.extraJavaOptions="-Xss10m -XX:MaxPermSize=512M " --conf spark.executor.extraJavaOptions="-Xss10m -XX:MaxPermSize=128M "