我正在对YARN上的Spark作业进行一些内存调整,我注意到不同的设置会产生不同的结果,并影响Spark作业运行的结果。然而,我很困惑,也不完全理解为什么会发生这种情况,如果有人能给我一些指导和解释,我将不胜感激。
我将提供一些背景信息,并在下面发布我的问题,并描述我在这些问题之后所经历的案例。
我的环境设置如下:
我的代码递归地过滤RDD以使其更小(作为算法的一部分删除示例),然后执行mapToPair和collect来收集结果并将其保存在列表中。
问题
spark.driver.memory + spark.yarn.driver.memoryOverhead = YARN将创建JVM的内存
= 11g + (driverMemory * 0.07,最小384m) = 11g + 1.154g = 12.154g
因此,从公式中,我可以看到我的作业需要大约12.154g的MEMORY_TOTAL才能成功运行,这就解释了为什么我需要超过10g的驱动程序内存设置。
但对于第四种情况,
spark.driver.memory + spark.yarn.driver.memoryOverhead = YARN将创建JVM的内存
=2+ (driverMemory * 0.07,最小384m) = 2g + 0.524g = 2.524g
似乎只要将内存开销小幅增加1024(1g),就可以在驱动内存仅为2g、MEMORY_TOTAL仅为2.524g的情况下成功运行作业!然而,如果没有开销配置,低于11g的驱动程序内存会失败,但从公式中看它没有意义,这就是我感到困惑的原因。
为什么增加内存开销(对于驱动程序和执行器)可以让我的工作以较低的MEMORY_TOTAL (12.154g vs 2.524g)成功完成?在工作中,我还遗漏了一些其他内部的东西吗?
第一个案例
/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 7g --executor-memory 1g --num-executors 3 --executor-cores 1 --jars <jar file>
如果我用少于11g的驱动内存运行我的程序,我会得到下面的错误,下面是停止的SparkContext,或者是一个类似的错误,是在停止的SparkContext上调用的方法。据我所知,这与内存不足有关。
第二种情况
/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 7g --executor-memory 3g --num-executors 3 --executor-cores 1 --jars <jar file>
如果我使用相同的驱动程序内存但更高的执行程序内存运行程序,作业运行的时间(大约3-4分钟)比第一种情况更长,然后它将遇到与前面不同的错误,即容器请求/使用的内存超过允许的内存,并因此被终止。虽然我觉得这很奇怪,因为执行程序的内存增加了,并且这个错误发生了,而不是第一种情况下的错误。
第三种情况
/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 11g --executor-memory 1g --num-executors 3 --executor-cores 1 --jars <jar file>
驱动程序内存大于10g的任何设置都将导致作业能够成功运行。
第四种情况
/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 2g --executor-memory 1g --conf spark.yarn.executor.memoryOverhead=1024 --conf spark.yarn.driver.memoryOverhead=1024 --num-executors 3 --executor-cores 1 --jars <jar file>
使用此设置(驱动程序内存2g和执行器内存1g )作业将成功运行,但会增加驱动程序内存开销(1g)和执行器内存开销(1g)。
任何帮助我都将不胜感激,这将有助于我对Spark的理解。提前谢谢。
发布于 2016-04-28 08:06:42
你所有的箱子都使用
--executor-cores 1
根据我们的经验和Spark developers的建议,这是最好的做法,超过1。不要超过5。
例如:http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/:
A rough guess is that at most five tasks per executor
can achieve full write throughput, so it’s good to keep
the number of cores per executor below that number
我现在找不到建议每个执行器超过1个内核的参考资料。但其想法是,在同一个executor中运行多个任务使您能够共享一些公共内存区域,因此它实际上节省了内存。
从-- executor -cores 2开始,使用double --executor-memory (因为--executor-cores还会告诉您一个执行器将并发运行多少个任务),看看它能为您做些什么。您的环境在可用内存方面是紧凑的,因此将可用内存设置为3或4将使您的内存利用率更高。
我们使用Spark 1.5并停止使用--executor-cores 1很久了,因为它给GC带来了问题;它看起来也像Spark bug,因为仅仅提供更多的内存并不像仅仅切换到每个容器有更多的任务一样有帮助。我猜同一个executor中的任务可能会在不同的时间达到其内存消耗的峰值,因此您不必浪费/不必过度配置内存来使其正常工作。
另一个好处是Spark的共享变量(累加器和广播变量)每个执行器只有一个副本,而不是每个任务-所以切换到每个执行器的多个任务可以直接节省内存。即使你不显式使用Spark共享变量,Spark也很可能会在内部创建它们。例如,如果您通过Spark SQL连接两个表,Spark的CBO可能会决定广播一个较小的表(或较小的数据帧),以使join运行得更快。
http://spark.apache.org/docs/latest/programming-guide.html#shared-variables
https://stackoverflow.com/questions/32292414
复制相似问题