我正在对YARN上的Spark作业进行一些内存调整,我注意到不同的设置会产生不同的结果并影响Spark作业运行的结果 . 但是,我很困惑,并不完全理解为什么会发生这种情况,如果有人能给我一些指导和解释,我会很感激 .
我将提供一些背景信息并发布我的问题并描述我之后经历过的案例 .
My environment setting were as below:
-
内存20G,每个节点20个VCores(总共3个节点)
-
Hadoop 2.6.0
-
Spark 1.4.0
我的代码递归地过滤RDD以使其变小(将示例作为算法的一部分移除),然后执行mapToPair并收集以收集结果并将其保存在列表中 .
问题
-
为什么抛出了不同的错误,并且第一个和第二个案例之间的作业运行时间更长(第二种情况)只增加了执行程序内存?这两个错误是否以某种方式相关联?
-
第三和第四种情况都成功了,我明白这是因为我提供了更多的内存来解决内存问题 . 但是,在第三种情况下,
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 . 提前致谢 .
1 回答
你所有的情况都使用
这是最好的做法,超过1.并且不要超过5.从我们的经验和Spark开发人员的推荐 .
例如 . http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/:
我现在找不到参考建议每个执行者超过1个核心的地方 . 但是这个想法是在同一个 Actuator 中运行多个任务,这使你能够共享一些公共内存区域,从而实际上节省了内存 .
从--executor-cores 2开始,双--executor-memory(因为--executor-cores还告诉一个执行程序将运行多少个任务),并看看它为你做了什么 . 您的环境在可用内存方面是紧凑的,因此转到3或4将为您提供更好的内存利用率 .
我们使用Spark 1.5并且很久以前停止使用--executor-cores 1,因为它给了GC问题;它看起来也像是一个Spark bug,因为只是提供更多的内存并不像每个容器只需要更多的任务那么多 . 我想同一个执行程序中的任务可能会在不同的时间达到峰值内存消耗,所以你不要浪费/不必为了使它工作而过度配置内存 .
另一个好处是Spark的共享变量(累加器和广播变量)每个 Actuator 只有一个副本,而不是每个任务 - 所以每个 Actuator 切换到多个任务就是直接节省内存 . 即使你不使用Spark明确共享变量,Spark很可能无论如何都在内部创建它们 . 例如,如果您通过Spark SQL连接两个表,Spark的CBO可能决定广播较小的表(或较小的数据帧)以使连接运行更快 .
http://spark.apache.org/docs/latest/programming-guide.html#shared-variables