驱动程序内存、执行程序内存、驱动程序内存开销和执行程序内存开销对作业运行成功的影响

ntjbwcob  于 2021-06-03  发布在  Hadoop
关注(0)|答案(1)|浏览(431)

我正在对yarn上的spark作业进行一些内存调整,我注意到不同的设置会产生不同的结果,并影响spark作业运行的结果。但是,我很困惑,不完全理解为什么会这样,如果有人能给我一些指导和解释,我将不胜感激。
我将提供一些背景资料,并张贴我的问题,并描述我经历过的案件后,他们在下面。
我的环境设置如下:
内存20g,每个节点20个vCore(共3个节点)
hadoop 2.6.0版
Spark1.4.0
我的代码递归地过滤rdd使其变小(将示例作为算法的一部分删除),然后执行maptopair和collect以收集结果并将其保存在列表中。

问题

为什么在第一种情况和第二种情况之间抛出不同的错误并且作业运行更长时间(对于第二种情况),而只增加执行器内存?这两个错误有某种联系吗?
第三个和第四个案例都成功了,我明白这是因为我给了更多的内存,解决了内存问题。然而,在第三种情况下,
spark.driver.memory+spark.yarn.driver.memoryoverhead=yarn将创建jvm的内存
=11g+(驱动器内存0.07,最小384m)=11g+1.154g=12.154g
因此,从公式中可以看出,我的作业需要总共12.154g左右的内存才能成功运行,这就解释了为什么我需要超过10g的驱动程序内存设置。
但对于第四种情况,
spark.driver.memory+spark.yarn.driver.memoryoverhead=yarn将创建jvm的内存
=2+(驱动器内存
0.07,最小384m)=2g+0.524g=2.524g
似乎只需将内存开销增加1024(1g)就可以成功运行该作业,而驱动程序内存仅为2g,内存总量仅为2.524g!然而,没有开销配置,驱动程序内存小于11g失败,但它没有意义,从公式,这就是为什么我感到困惑。
为什么增加内存开销(对于驱动程序和执行程序)可以使我的作业以较低的内存总量(12.154g对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。提前谢谢。

rjee0c15

rjee0c151#

你所有的案子都用

--executor-cores 1

最好的做法是超过1。不要超过5。根据我们的经验和spark开发者的推荐。
例如。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 cores 2,double--executor内存开始(因为--executor cores还告诉一个executor将同时运行多少个任务),看看它能为您做些什么。在可用内存方面,您的环境是紧凑的,因此选择3或4将为您提供更好的内存利用率。
我们使用spark1.5,不久前就停止使用--executor core1,因为它给gc带来了问题;它看起来也像一个spark bug,因为仅仅提供更多的内存并没有像切换到每个容器有更多的任务那样有效。我猜同一个执行器中的任务可能会在不同的时间达到内存消耗的峰值,因此您不必浪费/不必过度提供内存来让它工作。
另一个好处是spark的共享变量(累加器和广播变量)每个执行器只有一个副本,而不是每个任务-因此每个执行器切换到多个任务是一种直接的内存节省。即使没有显式使用spark共享变量,spark也很可能在内部创建它们。例如,如果您通过sparksql连接两个表,spark的cbo可能会决定广播一个较小的表(或较小的Dataframe),以使连接运行得更快。
http://spark.apache.org/docs/latest/programming-guide.html#shared-变量

相关问题