我的群集:1个主服务器,11个从服务器,每个节点有6 GB内存。
我的设置:
spark.executor.memory=4g, Dspark.akka.frameSize=512
以下是问题:
首先,我从HDFS到RDD读取了一些数据(2.19 GB):
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 :当输入数据大约为225 MB时,每件事情都可以。
我该如何解决这个问题?
答案 0 :(得分:310)
我有一些建议:
spark.executor.memory=6g
。通过检查用户界面确保你正在使用尽可能多的内存(它会说明你正在使用多少内存)spark.storage.memoryFraction
减少为缓存保留的内存部分。如果你的代码中没有使用cache()
或persist
,那么它也可能是0.它的默认值是0.6,这意味着你的堆只能得到0.4 * 4g的内存。 IME减少内存压力通常会使OOM消失。 更新:从火花1.6开始,我们将不再需要使用这些值,火花将自动确定它们。String
和重度嵌套的结构(如Map
和嵌套的案例类)。如果可能,尝试仅使用原始类型并索引所有非基元,特别是如果您期望大量重复。尽可能在嵌套结构上选择WrappedArray
。或者甚至推出自己的序列化 - 您将获得有关如何有效地将数据备份为字节的最多信息,使用IT !Dataset
来缓存您的结构,因为它将使用更高效的序列化。与前一个要点相比,这应被视为黑客攻击。将您的领域知识构建到您的算法/序列化中可以将内存/缓存空间最小化100倍或1000倍,而所有Dataset
可能会在内存中提供2x - 5x,在磁盘上压缩10x(镶木地板)。http://spark.apache.org/docs/1.2.1/configuration.html
编辑:(所以我可以更容易谷歌)以下也表明了这个问题:
java.lang.OutOfMemoryError : GC overhead limit exceeded
答案 1 :(得分:48)
要向此添加一个通常没有讨论过的用例,我会在本地模式下通过Spark
提交spark-submit
申请时提出解决方案。
根据Mastering Apache Spark的gitbook Jacek Laskowski:
您可以在本地模式下运行Spark。在这种非分布式单JVM部署模式中,Spark在同一个JVM中生成所有执行组件 - 驱动程序,执行程序,后端和主服务器。这是使用驱动程序执行的唯一模式。
因此,如果您遇到OOM
的{{1}}错误,则只需调整heap
而不是driver-memory
。
以下是一个例子:
executor-memory
答案 2 :(得分:14)
看看the start up scripts那里设置了Java堆大小,看起来你没有在运行Spark worker之前设置它。
# Set SPARK_MEM if it isn't already set since we also use it for this process
SPARK_MEM=${SPARK_MEM:-512m}
export SPARK_MEM
# Set JAVA_OPTS to be able to load native libraries and to set heap size
JAVA_OPTS="$OUR_JAVA_OPTS"
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$SPARK_LIBRARY_PATH"
JAVA_OPTS="$JAVA_OPTS -Xms$SPARK_MEM -Xmx$SPARK_MEM"
您可以找到部署脚本here的文档。
答案 3 :(得分:14)
您应该增加驱动程序内存。在你的$ SPARK_HOME / conf文件夹中,你应该找到文件spark-defaults.conf
,根据主人的内存编辑和设置spark.driver.memory 4000m
,我想。
这就是为我解决问题并且一切顺利进行的原因
答案 4 :(得分:7)
您应该配置offHeap内存设置,如下所示:
val spark = SparkSession
.builder()
.master("local[*]")
.config("spark.executor.memory", "70g")
.config("spark.driver.memory", "50g")
.config("spark.memory.offHeap.enabled",true)
.config("spark.memory.offHeap.size","16g")
.appName("sampleCodeForReference")
.getOrCreate()
根据您的计算机RAM可用性为驱动程序提供内存和执行程序内存。 如果您仍然面临OutofMemory问题,可以增加offHeap尺寸。
答案 5 :(得分:4)
从广义上讲,spark Executor的JVM内存可以分为两部分。 Spark内存和用户内存。这由属性spark.memory.fraction
控制-值介于0和1之间。
在Spark应用程序中处理图像或进行内存密集型处理时,请考虑减少spark.memory.fraction
。这将使更多的内存可用于您的应用程序工作。 Spark可能会溢出,因此它仍将以较少的内存份额工作。
问题的第二部分是分工。如果可能,将数据分成较小的块。较小的数据可能需要较少的内存。但是,如果这不可能,那么您将牺牲内存的计算能力。通常,一个执行程序将运行多个内核。执行程序的总内存必须足以处理所有并发任务的内存需求。如果不能增加执行程序的内存,则可以减少每个执行程序的内核,以便每个任务都可以使用更多的内存。 使用1个具有最大可能内存的核心执行程序进行测试,然后不断增加核心,直到找到最佳核心数量。
答案 6 :(得分:4)
您是否转储了主gc日志?所以我遇到了类似的问题,我发现SPARK_DRIVER_MEMORY只设置了Xmx堆。初始堆大小保持为1G,并且堆大小永远不会扩展到Xmx堆。
传递“ --conf” spark.driver.extraJavaOptions = -Xms20g“解决了我的问题。
ps aux | grep java,您将看到以下日志:=
24501 30.7 1.7 41782944 2318184 pts / 0 Sl + 18:49 0:33 / usr / java / latest / bin / java -cp / opt / spark / conf /:/ opt / spark / jars / * -Xmx30g -Xms20g
答案 7 :(得分:3)
这个问题让我非常痛苦,我们使用动态资源分配,我认为它将利用我的群集资源来最适合该应用程序。
但是事实是,动态资源分配不会设置驱动程序内存,而是将其保留为默认值1g。
我已通过将spark.driver.memory设置为适合我的驱动程序内存的数字(对于32gb的内存,我将其设置为18gb)来解决了该问题
您可以使用spark提交命令进行设置,如下所示:
spark-submit --conf spark.driver.memory=18gb ....cont
非常重要的一点是,根据spark文档,如果您通过代码进行设置,则不会考虑该属性:
Spark属性主要可以分为两种:一种与部署相关,例如“ spark.driver.memory”,“ spark.executor.instances”,当通过SparkConf进行编程设置时,此类属性可能不会受到影响。运行时,或行为取决于选择的集群管理器和部署模式,因此建议通过配置文件或spark-submit命令行选项进行设置;另一个主要与Spark运行时控件有关,例如“ spark.task.maxFailures”,可以用任何一种方式设置这种属性。
答案 8 :(得分:2)
设置内存堆大小的位置(至少在spark-1.0.0中)位于conf / spark-env中。
相关变量为SPARK_EXECUTOR_MEMORY
& SPARK_DRIVER_MEMORY
。
更多文档位于deployment guide
另外,不要忘记将配置文件复制到所有从属节点。
答案 9 :(得分:1)
对于上述错误,我几乎没有建议。
●检查分配为执行程序的执行程序内存可能必须处理需要比分配的内存更多的分区。
●尝试查看是否有更多的shuffle,因为shuffle是昂贵的操作,因为它们涉及磁盘I / O,数据序列化和网络I / O
●使用广播加入
●避免使用groupByKeys并尝试将其替换为ReduceByKey
●避免在发生改组的地方使用大型Java对象
答案 10 :(得分:1)
设置这些确切的配置有助于解决此问题。
spark-submit --conf spark.yarn.maxAppAttempts=2 --executor-memory 10g --num-executors 50 --driver-memory 12g
答案 11 :(得分:0)
据我对上面提供的代码的理解,它加载文件并执行映射操作并将其保存回去。没有需要洗牌的操作。另外,由于没有需要将数据带给驱动程序的操作,因此调整与随机播放或驱动程序相关的任何内容都不会产生影响。当任务太多时,驱动程序确实有问题,但这只是在spark 2.0.2版本之前。可能有两件事出了问题。
答案 12 :(得分:0)
堆空间错误通常是由于将太多数据带回驱动程序或执行程序而发生的。 在您的代码中,似乎并没有将任何东西带回驱动程序,但是您可能会使用ThreeDReconstruction()方法来重载将输入记录/行映射到另一个记录的执行程序。我不确定方法定义中包含什么,但这肯定会导致执行程序超载。 现在您有2个选择,
我建议增加使用量时要小心,并且仅在需要时使用。就内存需求而言,每个作业都是唯一的,因此我建议您凭经验建议每次尝试将不同的值增加2的幂(256M,512M,1G等)
您将获得将起作用的执行程序内存的值。尝试使用此值重新运行作业3或5次,然后再设置此配置。