为什么缓存小型 Spark RDD 需要在 Yarn 中分配大量内存?

Why caching small Spark RDDs takes big memory allocation in Yarn?

缓存的RDD(一共8个)不大,只有30G左右,但是在Hadoop上UI,说明Spark应用是占用大量内存(没有活动作业 运行),即 1.4T,为什么这么多?

为什么它显示大约 100 个执行程序(这里,即 vCores),即使没有活动作业 运行?

此外,如果缓存的 RDD 存储在 100 个执行程序中,这些执行程序是否会保留下来,不再有其他 Spark 应用程序可以将它们用于 运行 任务?换个说法:在执行器中保留一点内存资源(.cache)会阻止其他 Spark 应用程序利用它们的空闲计算资源吗?

有没有可能导致这种现象的Spark配置/zeppelin配置?


更新 1

查看 Spark conf (zeppelin) 后,似乎有 spark.executor.memory=10G 的默认设置(默认由管理员配置),这可能是原因。

但是,这里有一个新问题:是否可以只保留每个执行程序中缓存的RDD所需的内存并释放其余内存,而不是始终保留初始设置的内存spark.executor.memory=10G?

Spark 配置

也许您可以尝试 repartition(n) 在缓存之前将您的 RDD 分配到更少的 n < 100 分区。一个约 30GB 的 RDD 可能适合十个 10GB 执行器的存储内存。可以找到 Spark 内存管理的一个很好的概述 here。这样,只有那些持有缓存块的执行器才会被“固定”到您的应用程序,而其余的可以在 spark.dynamicAllocation.executorIdleTimeout(默认 60s)后通过 Spark 动态分配由 YARN 回收。

问:是否可以只保留每个执行器中缓存的RDD所需的内存并释放其余内存,而不是始终保留初始设置的内存spark.executor.memory=10G?

当 Spark 使用 YARN 作为其执行引擎时,YARN 分配指定(按应用程序)大小的容器——至少 spark.executor.memory+spark.executor.memoryOverhead,但在 pyspark 的情况下可能更大——用于所有执行人。 Spark 在内部 容器实际使用多少内存变得无关紧要,因为分配给容器的资源将被视为其他 YARN 应用程序的禁区。

Spark 假定您的数据在所有执行程序和任务 上平均分布。这就是为什么要为每个任务设置内存的原因。所以要让 Spark 消耗更少的内存,你的数据必须均匀分布:

  • 如果您正在读取 Parquet 文件或 CSV,请确保它们具有相似的大小。 运行 repartition() 导致混洗,如果执行者没有足够的资源,数据如此倾斜可能会导致其他问题
  • 缓存不会帮助释放执行程序上的内存,因为它不会重新分配数据
  • 您能否在舞台的“事件时间表”下看到“绿色条有多大?”通常这与数据分布有关,因此这是一种查看每个任务加载了多少数据(按比例)以及它们正在做什么的方法。由于所有任务都分配了相同的内存,因此您可以以图形方式查看资源是否被浪费(如果大部分是小条,大条很少)。可以在下图中看到浪费资源的示例

有多种方法可以为您的进程创建均匀分布的文件。我提到了一些可能性,但肯定还有更多:

  • 使用 Hive 和 DISTRIBUTE BY 子句:您需要使用一个均衡的字段来创建尽可能多的文件(并且具有适当的大小)
  • 如果创建这些文件的进程是从数据库读取的 Spark 进程,请尝试根据需要创建尽可能多的连接,并使用适当的字段来填充 Spark 分区。正如 here and here 使用 partitionColumn、lowerBound、upperBound 和 numPartitions 属性
  • 所解释的那样,这是实现的
  • 重新分区可能有效,但看看 coalesce 在您的过程中或在生成您正在读取的文件的前一个过程中是否也有意义