任何水平缩放Spark的技巧

时间:2018-05-17 05:58:23

标签: apache-spark yarn

将Spark执行从几个大节点移动到更多更小的节点时,有没有人有任何提示?

我正在运行一个带有4个执行器的系统,每个执行器都有24Gb的ram和12个内核。如果我尝试将其扩展到12个执行器,每个4个核心和8 Gb ram(相同的总RAM,相同的总核心,只是分布不同)我遇到内存不足错误: Container killed by YARN for exceeding memory limits. 8.8 GB of 8.8 GB physical memory used.

我已将分区数增加了3倍,以创建更多(更小)的分区,但这没有帮助。

有人有任何提示吗?试图水平缩放火花时的技巧?

1 个答案:

答案 0 :(得分:2)

这是一个非常广泛的问题,执行者在Spark中的大小是一种非常复杂的黑魔法,并且2015年正确的经验法则现在已经过时了,就像我说的那样,在下一个Spark版本的6个月内就会过时了。很多事情都归结为您正在做的事情,并避免数据中的关键偏差。

这是一个开始学习和发展自己理解的好地方: https://spark.apache.org/docs/latest/tuning.html

Slideshare上还有很多关于调优Spark的演示文稿,尝试阅读/观看最新版本。任何超过18个月的人都会持怀疑态度,任何超过2年的事情都会被忽视。

我将假设您至少使用Spark 2.x。

您遇到的错误确实是因为执行程序规模较小。发生的事情是你的遗嘱执行人试图立刻做太多事情,并在内存耗尽时自己跑到地上。

所有其他条件相同的是我应用它们时的当前经验法则:

简短版

  • 3 - 4个虚拟(超线程)内核和29GB内存是一个合理的默认执行程序大小(我将在后面解释原因)。如果你什么都不知道,那就好好划分数据并使用它。
  • 您通常应该将数据分区大小(在内存中)的目标设定为~100MB到~3GB

我申请的公式

执行程序内存=执行程序核心数*分区大小* 1.3(安全系数)

分区大小=数据磁盘上的大小/分区数* deser ratio

反序列化比率是磁盘上数据大小与内存中数据大小之间的比率。相同数据的Java内存表示往往比磁盘上大一点。

您还需要考虑您的数据是否已压缩,许多常见格式(如Parquet和ORC)都使用压缩,如gzip或snappy。

对于snappy压缩文本数据(非常容易压缩),我使用 ~10X - 100X 。 对于包含文本,浮点数,日期等混合的快速压缩数据,我通常会看到3X和15X之间。

执行程序核心数= 3到4 执行程序核心完全取决于计算与计算内存的密集程度。尝试并查看最适合您的用例的内容。我已经从未看到任何有关Spark倡导超过6个核心的人。

Spark非常聪明,可以充分利用数据局部性,因此执行者越大,您的数据就越有可能PROCESS_LOCAL 更多的数据位置是好的,直到某一点。

当JVM变得太大时> 50GB,它开始在最初的设计之外运行,并且根据您的垃圾收集算法,您可能会开始看到降级的性能和高GC时间。

https://databricks.com/blog/2015/05/28/tuning-java-garbage-collection-for-spark-applications.html

在Java中也恰好有一个性能技巧,如果你的JVM小于32GB,你可以使用32位压缩指针而不是64位指针,这样可以节省空间并降低缓存压力。

https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html https://blog.codecentric.de/en/2014/02/35gb-heap-less-32gb-java-jvm-memory-oddities/

YARN还会为您的执行程序大小增加7%或384MB的RAM(以较大者为准)的开销/安全系数,这是29GB的经验法则来源: 29GB + 7%〜= 32GB

您提到您正在使用12核,24GB RAM执行程序。这给我发了一个红旗。

为什么?

因为执行者中的每个“核心”都被分配了一个“任务”。任务等同于计算从“阶段”A到“阶段”B的一个分区的转换所需的工作。

https://jaceklaskowski.gitbooks.io/mastering-apache-spark/content/spark-taskscheduler-tasks.html https://jaceklaskowski.gitbooks.io/mastering-apache-spark/content/spark-DAGScheduler-Stage.html

如果你的执行者有12个核心,那么它将尝试用24GB内存预算同时完成12个任务。 24GB / 12核心=每核心2GB。如果您的分区大于2GB,则会出现内存不足错误。如果特定的转换使输入的大小加倍(甚至是中间),那么你也需要考虑到这一点。