如何优化 Apache Spark 应用程序中的 shuffle 溢出

Posted

技术标签:

【中文标题】如何优化 Apache Spark 应用程序中的 shuffle 溢出【英文标题】:How to optimize shuffle spill in Apache Spark application 【发布时间】:2015-08-28 03:33:20 【问题描述】:

我正在运行一个包含 2 个工作人员的 Spark 流应用程序。 应用程序具有连接和联合操作。

所有批次都成功完成,但注意到 shuffle 溢出指标与输入数据大小或输出数据大小不一致(溢出内存超过 20 次)。

请在下图中找到火花阶段的详细信息:

研究了一下,发现

当没有足够的内存用于随机播放数据时,会发生随机播放溢出。

Shuffle spill (memory) - 溢出时内存中数据的反序列化形式的大小

shuffle spill (disk) - 溢出后磁盘上数据的序列化形式的大小

由于反序列化数据比序列化数据占用更多空间。所以,Shuffle 溢出(内存)更多。

注意到这个溢出内存大小对于大量输入数据来说非常大

我的查询是:

这种溢出是否会显着影响性能?

如何优化这种内存和磁盘溢出?

是否有任何 Spark 属性可以减少/控制这种巨大的溢出?

【问题讨论】:

@mitchus 部分是的,我只是增加了任务的数量并为随机播放分配了更多的内存。另外,我已经优化了我的代码以压缩数据结构大小...... 【参考方案1】:

学习调整 Spark 的性能需要大量的调查和学习。有一些很好的资源,包括this video。 Spark 1.4 在界面中有一些更好的诊断和可视化功能,可以为您提供帮助。

总而言之,当阶段结束时 RDD 分区的大小超过 shuffle 缓冲区可用的内存量时,就会发生溢出。

你可以:

    手动repartition()您的前一个阶段,以便您从输入中获得更小的分区。 通过增加执行程序进程中的内存来增加随机缓冲区 (spark.executor.memory) 通过增加分配给它的执行程序内存的比例 (spark.shuffle.memoryFraction) 从默认值 0.2 增加随机缓冲区。你需要回馈spark.storage.memoryFraction。 通过降低工作线程 (SPARK_WORKER_CORES) 与执行程序内存的比率来增加每个线程的 shuffle 缓冲区

如果有专家在听,我很想了解更多关于 memoryFraction 设置如何相互作用及其合理范围的信息。

【讨论】:

重新分区可以洗牌不必要的数据,内部使用合并它使用组合器,所以尽量减少洗牌。 @VenuAPositive 我认为他建议重新分区到更多分区而不是更少。如果他要减少分区,那么合并将是有意义的。 spark.shuffle.memoryFraction 自 spark 1.5 起不再使用,除非您启用旧模式。见:spark.apache.org/docs/latest/configuration.html 这个答案(虽然有用)并没有真正解决为什么洗牌溢出比洗牌读取大得多的问题。【参考方案2】:

要添加到上述答案,您还可以考虑将分区的默认数量 (spark.sql.shuffle.partitions) 从 200(发生随机播放时)增加到将导致大小接近 hdfs 块大小的分区(即 128mb 到 256mb)

如果您的数据有偏差,请尝试对键加盐等技巧以增加并行度。

阅读本文以了解 Spark 内存管理:

https://0x0fff.com/spark-memory-management/

https://www.tutorialdocs.com/article/spark-memory-management.html

【讨论】:

以上是关于如何优化 Apache Spark 应用程序中的 shuffle 溢出的主要内容,如果未能解决你的问题,请参考以下文章

Apache Spark在海致大数据平台中的优化实践

Spark改进|Apache Spark 3.0中的SQL性能改进概览

如何解决 Spark 中的“aggregateByKey 不是 org.apache.spark.sql.Dataset 的成员”?

spark-kafka-es交互 优化

Apache Spark优化

如何在 Apache Spark 中的 Group By Operation 形成的每个子集上应用用户定义函数?