Apache Spark 内存不足,分区数量较少

Posted

技术标签:

【中文标题】Apache Spark 内存不足,分区数量较少【英文标题】:Apache Spark running out of memory with smaller amount of partitions 【发布时间】:2016-06-30 21:42:52 【问题描述】:

我有一个 Spark 应用程序,内存不断不足,集群有两个节点,内存大约 30G,输入数据大小约为几百 GB。

该应用程序是一个 Spark SQL 作业,它从 HDFS 读取数据并创建一个表并缓存它,然后执行一些 Spark SQL 查询并将结果写回 HDFS。

最初我将数据分成 64 个分区并得到 OOM,然后我能够通过使用 1024 个分区来解决内存问题。但是为什么使用更多的分区可以帮助我解决 OOM 问题呢?

【问题讨论】:

【参考方案1】:

大数据的解决方案是分区(分而治之)。由于不是所有的数据都可以放入内存,也不能在单机上处理。

每个分区都可以在相对较短的时间内放入内存并处理(映射)。在为每个分区处理数据之后。它需要合并(减少)。这是传统map reduce

将数据拆分到更多分区意味着每个分区越来越小。

[编辑]

Spark 使用称为弹性分布式数据集 (RDD) 的革命概念。

有两种类型的操作,转换和动作 转换是从一个 RDD 映射到另一个。它是懒惰的评估。这些 RDD 可能会被视为我们不想得到的中间结果。 当您真正想要获取数据时使用操作。那些 RDD/数据可以被视为我们想要的,比如 take top failure。 Spark 会在执行前分析所有操作并创建 DAG(有向无环图)。 触发操作时,Spark 从源 RDD 开始计算。那就算了吧。

(来源:cloudera.com)

我为 Youtube Spark Makes Big Data Sparking 上的演示制作了一个小截屏视频。

【讨论】:

我同意每个分区的大小更小,但是由于我正在缓存 RDD(应该在帖子中提到这一点),这些分区应该仍然在内存中,对吗?所以不管分区多少,内存中数据的大小应该是一样的【参考方案2】:

Spark 的操作符在内存无法容纳的情况下将数据溢出到磁盘, 允许它在任何大小的数据上运行良好”。大问题 分区产生OOM

分区决定并行度。 Apache Spark 文档说,分区大小应该至少等于集群中的核心数。

更少的分区导致

更少的并发, 为涉及 shuffle 的转换增加内存压力 更容易受到数据倾斜的影响。

许多分区也可能产生负面影响

安排多个任务花费了太多时间

将您的数据存储在 HDFS 上,将根据您的 HDFS 配置将其分区为 64 MB 或 128 MB 块使用 spark 读取 HDFS 文件时,DataFrame 分区的数量 df.rdd.getNumPartitions取决于以下属性

spark.default.parallelism(应用程序可用的内核) spark.sql.files.maxPartitionBytes(默认 128MB) spark.sql.files.openCostInBytes(默认 4MB)

链接:

https://spark.apache.org/docs/latest/tuning.html https://databricks.com/session/a-deeper-understanding-of-spark-internals https://spark.apache.org/faq.html

在 Spark 峰会期间,Aaron Davidson 提供了一些关于分区调优的技巧。他还定义了合理的分区数恢复到3点以下:

通常在 100 到 10000 个分区之间(注意:以下两点更可靠,因为此处的“通常”取决于数据集和集群的大小) 下限 = 至少 2* 集群中的核心数 上限 = 任务必须在 100 毫秒内完成

【讨论】:

【参考方案3】:

Rockie 的回答是对的,但他没有明白你问题的重点。

当你缓存一个 RDD 时,他的所有分区都会被持久化(以storage level 表示)——尊重 spark.memory.fractionspark.memory.storageFraction属性。

除此之外,根据documentation,在某个时刻Spark 可以自动删除一些内存分区(或者您可以使用 RDD.unpersist() 手动为整个 RDD 执行此操作)。

因此,由于您有更多分区,Spark 在 LRU 中存储的分区更少,因此它们不会导致 OOM(这也可能产生负面影响,例如需要重新缓存分区)。

另一个重要的一点是,当您使用 X 个分区将结果写回 HDFS 时,您的所有数据都有 X 个任务 - 将所有数据大小除以 X,这就是内存对于每个任务,在每个(虚拟)核心上执行。所以,不难看出 X = 64 会导致 OOM,但 X = 1024 不会。

【讨论】:

以上是关于Apache Spark 内存不足,分区数量较少的主要内容,如果未能解决你的问题,请参考以下文章

如何确定 Apache Spark 数据帧中的分区大小

Apache Spark s3a 提交者 - 线程堆栈 - 内存不足问题

为啥 Spark DataFrame 会创建错误数量的分区?

如何在 partitionBy 输出之前平衡 Spark DataFrame 数据

如何在 apache spark 中读取最新的分区

Apache spark如何计算分区以及在executor中如何处理分区