为什么缓存小型 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()
导致混洗,如果执行者没有足够的资源,数据如此倾斜可能会导致其他问题
- 缓存不会帮助释放执行程序上的内存,因为它不会重新分配数据
- 您能否在舞台的“事件时间表”下看到“绿色条有多大?”通常这与数据分布有关,因此这是一种查看每个任务加载了多少数据(按比例)以及它们正在做什么的方法。由于所有任务都分配了相同的内存,因此您可以以图形方式查看资源是否被浪费(如果大部分是小条,大条很少)。可以在下图中看到浪费资源的示例
有多种方法可以为您的进程创建均匀分布的文件。我提到了一些可能性,但肯定还有更多:
缓存的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()
导致混洗,如果执行者没有足够的资源,数据如此倾斜可能会导致其他问题 - 缓存不会帮助释放执行程序上的内存,因为它不会重新分配数据
- 您能否在舞台的“事件时间表”下看到“绿色条有多大?”通常这与数据分布有关,因此这是一种查看每个任务加载了多少数据(按比例)以及它们正在做什么的方法。由于所有任务都分配了相同的内存,因此您可以以图形方式查看资源是否被浪费(如果大部分是小条,大条很少)。可以在下图中看到浪费资源的示例
有多种方法可以为您的进程创建均匀分布的文件。我提到了一些可能性,但肯定还有更多: