将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倍,以创建更多(更小)的分区,但这没有帮助。
有人有任何提示吗?试图水平缩放火花时的技巧?
答案 0 :(得分:2)
这是一个非常广泛的问题,执行者在Spark中的大小是一种非常复杂的黑魔法,并且2015年正确的经验法则现在已经过时了强大的>,就像我说的那样,在下一个Spark版本的6个月内就会过时了。很多事情都归结为您正在做的事情,并避免数据中的关键偏差。
这是一个开始学习和发展自己理解的好地方: https://spark.apache.org/docs/latest/tuning.html
Slideshare上还有很多关于调优Spark的演示文稿,尝试阅读/观看最新版本。任何超过18个月的人都会持怀疑态度,任何超过2年的事情都会被忽视。
我将假设您至少使用Spark 2.x。
您遇到的错误确实是因为执行程序规模较小。发生的事情是你的遗嘱执行人试图立刻做太多事情,并在内存耗尽时自己跑到地上。
所有其他条件相同的是我应用它们时的当前经验法则:
简短版
我申请的公式
执行程序内存=执行程序核心数*分区大小* 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,则会出现内存不足错误。如果特定的转换使输入的大小加倍(甚至是中间),那么你也需要考虑到这一点。