Spark java.lang.OutOfMemoryError: Java heap space

290

我的集群:1个主节点,11个从节点,每个节点都有6GB的内存。

我的设置:

spark.executor.memory=4g, Dspark.akka.frameSize=512

问题如下:

首先,我从HDFS中读取了一些数据(2.19 GB)到RDD中:

val imageBundleRDD = sc.newAPIHadoopFile(...)

其次,对这个RDD执行一些操作:

val res = imageBundleRDD.map(data => {
                               val desPoints = threeDReconstruction(data._2, bg)
                                 (data._1, desPoints)
                             })

最后,输出到HDFS:

res.saveAsNewAPIHadoopFile(...)

当我运行我的程序时,它会显示:

.....
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:24 as TID 33 on executor 9: Salve7.Hadoop (NODE_LOCAL)
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:24 as 30618515 bytes in 210 ms
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:36 as TID 34 on executor 2: Salve11.Hadoop (NODE_LOCAL)
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:36 as 30618515 bytes in 449 ms
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Starting task 1.0:32 as TID 35 on executor 7: Salve4.Hadoop (NODE_LOCAL)
Uncaught error from thread [spark-akka.actor.default-dispatcher-3] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[spark]
java.lang.OutOfMemoryError: Java heap space

任务太多了吗?

PS:当输入数据约为225MB时,一切正常。

我该如何解决这个问题?


如何运行Spark?是从控制台吗?还是使用哪些部署脚本? - Tombart
我使用sbt编译和运行我的应用程序。sbt package然后sbt run。一个月前,我在hadoop上实现了相同的程序,并遇到了OutOfMemoryError的问题,但在hadoop中,可以通过将mapred.child.java.opts的值从Xmx200m增加到Xmx400m来轻松解决。Spark是否有任何JVM设置来处理其任务?我想知道spark.executor.memory是否与hadoop中的mapred.child.java.opts具有相同的含义。在我的程序中,spark.executor.memory已经设置为4g,比hadoop中的Xmx400m大得多。谢谢~ - Hellen
你提到的三个步骤是唯一需要执行的吗?(data._1, desPoints) 生成的数据大小是多少?如果将此数据随后洗牌到另一个阶段,它应该适合内存。 - Arnon Rotem-Gal-Oz
2
驱动程序的内存配置是什么?检查哪个服务器出现了内存不足错误。是驱动程序还是其中一个执行器。 - RanP
查看所有配置属性请点击此链接:https://spark.apache.org/docs/2.1.0/configuration.html - Naramsim
@hequn8128 如果您能在这里接受一个答案的话,将来参考起来会很方便。说实话,我个人比较喜欢samthebest的回答。 - Naman
14个回答

2

如果您正在使用脚本或Jupyter笔记本,则只需在构建Spark会话时设置配置路径即可简单地完成此操作。

spark = SparkSession.builder.master('local[*]').config("spark.driver.memory", "15g").appName('testing').getOrCreate()

对我来说就像魔法一样好用! - Merin Nakarmi

2
据我对上述代码的理解,它会加载文件并进行映射操作,然后保存回去。没有任何需要洗牌的操作。此外,也没有需要将数据带到驱动程序的操作,因此调整与洗牌或驱动程序相关的任何内容可能没有影响。当任务过多时,驱动程序确实会出现问题,但这仅适用于spark 2.0.2版本之前。有两件事情可能出了问题。
  • 只有一个或几个执行器。增加执行器的数量,以便它们可以分配给不同的从节点。如果您使用yarn,则需要更改num-executors配置;如果您使用独立的spark,则需要调整每个执行器的核心数和spark最大核心数配置。在独立模式下,num executors = max cores / cores per executor。
  • 分区数非常少,甚至只有一个。因此,即使我们有多个核心、多个执行器,如果分区数较少,也不会有太大的帮助,因为并行化取决于分区数。所以通过执行imageBundleRDD.repartition(11)来增加分区数。

1
堆空间错误通常是由于将过多的数据带回驱动程序或执行程序而引起的。 在您的代码中,似乎没有将任何东西带回驱动程序,但是您可能正在过载执行器,这些执行器正在使用threeDReconstruction()方法将输入记录/行映射到另一个记录/行。我不确定方法定义中有什么,但这绝对会导致执行器的过载。 现在你有两个选择,
  1. 编辑您的代码以更有效地进行3-D重建。
  2. 不编辑代码,但给您的执行器提供更多内存,并提供更多内存开销。[spark.executor.memory或spark.driver.memoryOverhead]
我建议小心增加内存并且仅使用您需要的内存。每个作业在其内存要求方面是独特的,因此我建议经验性地尝试不同的值,每次增加2的幂 (256M、512M、1G 等等)。
您将得出适用于执行器内存的值。在选择此配置之前,请尝试使用此值重新运行作业3或5次。

-1

设置这些精确的配置有助于解决问题。

spark-submit --conf spark.yarn.maxAppAttempts=2 --executor-memory 10g --num-executors 50 --driver-memory 12g

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接