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

Apache Spark Effects of Driver Memory, Executor Memory, Driver Memory Overhead and Executor Memory Overhead on success of job runs

我正在 YARN 上对我的 Spark 作业进行一些内存调整,我注意到不同的设置会产生不同的结果并影响 Spark 作业的结果 运行。但是,我很困惑,不完全理解为什么会这样,如果有人能为我提供一些指导和解释,我将不胜感激。

我将提供一些背景信息和post我的问题,并在下面描述我遇到的案例。

我的环境设置如下:

我的代码递归地过滤 RDD 以使其更小(作为算法的一部分删除示例),然后执行 mapToPair 和 collect 以收集结果并将它们保存在列表中。

问题

  1. 为什么在第一种情况和第二种情况之间抛出不同的错误并且作业 运行s 更长(对于第二种情况),只有执行程序内存增加?这两个错误是否以某种方式关联?

  2. 第三种和第四种情况都成功了,我明白是因为我给了更多的内存,解决了内存问题。然而,在第三种情况下,

spark.driver.memory + spark.yarn.driver.memoryOverhead = the memory that YARN will create a JVM

= 11g + (driverMemory * 0.07, with minimum of 384m) = 11g + 1.154g = 12.154g

所以,从公式中,我可以看出我的工作需要 MEMORY_TOTAL 大约 12.154g 到 运行 成功,这解释了为什么我需要更多驱动程序内存设置小于 10g。

但是对于第四种情况,

spark.driver.memory + spark.yarn.driver.memoryOverhead = the memory that YARN will create a JVM

= 2 + (driverMemory * 0.07, with minimum of 384m) = 2g + 0.524g = 2.524g

似乎仅通过将内存开销增加少量 1024(1g) 就可以成功 运行 驱动程序内存仅为 2g 并且 MEMORY_TOTAL只有2.524g!而在没有开销配置的情况下,驱动程序内存小于 11g 失败,但从公式中看不出任何意义,这就是我感到困惑的原因。

为什么增加内存开销(对于驱动程序和执行程序)允许我的工作以较低的 MEMORY_TOTAL(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>

如果我运行驱动程序内存相同但执行程序内存更高的程序,作业比第一种情况运行s长(大约3-4分钟)然后它会遇到与之前不同的错误是 Container requesting/using more memory than allowed and is being killed because of that.虽然我觉得很奇怪,因为执行程序内存增加了,并且发生了这个错误,而不是第一种情况下的错误。

第三个案例

/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。提前致谢。

你所有的案例都使用

--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-memory 开始(因为 --executor-cores 也告诉一个执行者将同时运行执行多少任务),看看它能为你做什么.您的环境在可用内存方面是紧凑的,因此转到 3 或 4 会给您更好的内存利用率。

我们使用 Spark 1.5 并在很久以前停止使用 --executor-cores 1 因为它会产生 GC 问题;它看起来也像一个 Spark 错误,因为仅仅提供更多内存并没有像切换到每个容器有更多任务那样有帮助。我猜同一个执行器中的任务可能会在不同时间达到内存消耗峰值,因此您不必 waste/don 不必为了使其正常工作而过度配置内存。

另一个好处是 Spark 的共享变量(累加器和广播变量)每个执行器只有一个副本,而不是每个任务 - 因此切换到每个执行器的多个任务是直接节省内存。即使您没有显式使用 Spark 共享变量,Spark 也很可能无论如何都会在内部创建它们。例如,如果您通过 Spark SQL 连接两个 table,Spark 的 CBO 可能会决定广播一个较小的 table(或较小的数据帧)以使连接 运行 更快.

http://spark.apache.org/docs/latest/programming-guide.html#shared-variables