如何优化 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 溢出的主要内容,如果未能解决你的问题,请参考以下文章
Spark改进|Apache Spark 3.0中的SQL性能改进概览
如何解决 Spark 中的“aggregateByKey 不是 org.apache.spark.sql.Dataset 的成员”?