【问题标题】:Optimizing Spark resources to avoid memory and space usage优化 Spark 资源以避免内存和空间使用
【发布时间】:2021-04-28 04:26:36
【问题描述】:

我有一个大约 190GB 的数据集,被划分为 1000 个分区。

我的 EMR 集群最多允许 10 个r5a.2xlarge TASK 节点和 2 个 CORE 节点。每个节点有 64GB 内存和 128GB EBS 存储。

在我的 spark 作业执行中,我已将其设置为使用 executor-cores 5driver cores 5executor-memory 40gdriver-memory 50gspark.yarn.executor.memoryOverhead=10gspark.sql.shuffle.partitions=500spark.dynamicAllocation.enabled=true

但我的工作总是因错误而失败,例如

spark.shuffle.MetadataFetchFailedException
spark.shuffle.FetchFailedException
java.io.IOException: No space left on device
Container Lost
etc...

我在网上找到的很多这类问题的答案都说要增加 memoryOverhead。我做到了,从 2G 到 10G。我的总executor memorymemoryOverhead 是50G。 40G 分配给执行者,10G 分配给开销。但我认为我已经达到了极限,因为我无法超过 56。

我认为我已尽一切可能优化我的 Spark 工作:

  1. 增加分区
  2. 增加 spark.sql.shuffle.partitions
  3. 增加执行器和开销内存

但我的工作仍然失败。还有什么我可以尝试的吗?我应该更多地增加我的开销,以便我的执行程序内存/开销内存为 50/50? 我在 ganglia 工作的内存配置文件如下所示:

(急剧下降是当集群由于它们死亡而刷新所有执行器节点时)

任何见解将不胜感激

谢谢

编辑:[解决方案]

感谢Debuggerrr 根据他在回答中的建议,我在帖子中附上了解决我问题的确切解决方案。

  • 我有一个大型数据框,我在执行了很多操作后正在重新使用它 其他数据帧的计算。通过使用persist() 方法 (由 Debuggerrr 建议),我能够将其保存到 MEMORY 和 DISC 并简单地调用它而不用清理它的一部分 GC。
  • 我还按照他的回答中提到的最佳实践博客 Debuggerrr 计算了正确的执行程序内存、执行程序数量等。但我没有做的是禁用 spark.dynamicAllocation.enabled。该博客指出,如果我们手动计算资源,最好将该属性设置为 false,因为如果您的计算与它不一致,spark 往往会错误分配资源。一旦我将它设置为 false,并设置了正确的 executor 和 spark 属性,它就像一个魅力!

[编辑 2]: 特别适合我的工作的参数是:

--executor-cores 5 --driver-cores 5 --executor-memory 44g --driver-memory 44g --num-executors 9 --conf spark.default.parallelism=100 --conf spark.sql.shuffle.partitions=300 --conf spark.yarn.executor.memoryOverhead=11g --conf spark.shuffle.io.retryWait=180s --conf spark.network.timeout=800s --conf spark.serializer=org.apache.spark.serializer.KryoSerializer --conf spark.dynamicAllocation.enabled=false

【问题讨论】:

    标签: apache-spark pyspark amazon-emr


    【解决方案1】:

    您可以尝试以下任一步骤:

    1. Memory overhead 应该是 Executor 内存的 10%328 MB。不要将其增加到任何值。
    2. 移除驱动核心。
    3. 如果您有 10 个节点,则指定 number of executors。您必须以为 YARN 和后台进程留出一些空间的方式计算它。此外,您可以尝试再增加 1 或 2 个内核。
    4. cluster 模式下运行它,无论您分配给执行器的编号如何,都为其添加 +1,因为在集群模式下,1 个执行器将被视为驱动程序执行器。
    5. 此外,最后一件事就是您为提交/处理该 190GB 文件而编写的代码。浏览您的代码并找到优化它的方法。寻找收集方法,或不必要地使用连接、合并/重新分区。如果不需要,请寻找一些替代方案。
    6. 对您在代码中经常使用的数据帧使用持久化(仅限内存和磁盘)选项。
    7. 此外,我尝试的最后一件事是在 spark-shell on EMR 上手动执行这些步骤,然后您就会知道代码的哪一部分需要很长时间才能运行。

    您也可以参考此official blog 了解一些提示。

    【讨论】:

    • 感谢您的这些见解!。我正在使用spark.dynamicAllocation.enabled=true,所以我没有指定执行者的数量,因为它将由纱线处理。我已经看到执行器的数量增加到 11。我只在集群模式下运行它,并且我的代码中没有任何收集方法。所以我想我已经在做你提到的第 3,4 和 5 点了。我经常使用数据框,我可以尝试持久选项。
    • (继续上面的评论)对于第 7 点,我在 jupiterlab notebook 的一个非常小的子集上测试了我的代码,它运行良好。但是我认为我的数据集高度倾斜。有没有办法检查偏度?
    • 提到num-executors参数的重点是,即使你离开Spark去处理执行者,你可以观察到即使你已经分配了@,它最多也有11个执行者。每个执行程序 987654330@ ram,你有 10 个节点。关键是内存没有被充分利用,也会影响并行性。执行者越多,并行性越多。假设 40GB 的 ram 分配给 1 个执行程序,最大 5GB(通常不占用)用于 YARN 开销和其他后台进程。您仍然为每个节点保留了 19GB RAM。
    • 如果您对 20 不满意,可以尝试使用 15。关键是如果您有 9 个执行器,具有 10 个节点和 40GB 内存,假设 1 个执行器将在 1 个节点上,那么您仍然有 1空闲的节点(内存未充分利用)。如果您分配 15,那么每个节点将至少有 1 个执行程序,并且并行度也会增加,这也会导致更快的处理。我很高兴知道它对你有用?
    • 太棒了!是的,正如我在回答中所说,在集群模式下,1 个执行程序被视为驱动程序线程,这就是为什么我要求您 +1 个执行程序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 2013-04-20
    • 2011-06-17
    • 1970-01-01
    • 2014-07-17
    • 1970-01-01
    • 2014-05-08
    相关资源
    最近更新 更多