如何优化Apache Spark应用程序中的Shuffle Spill

57

我正在运行一个带有两个工作节点的Spark流式应用程序。该应用包含联接和合并操作。

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

请在下面的图片中查找Spark阶段详细信息: enter image description here

经过调查,发现:

当Shuffle数据没有足够的内存时,就会发生Shuffle溢出。

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

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

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

注意到这个溢出内存大小在有大量输入数据时非常大

我的问题是:

这种溢出会显著影响性能吗?

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

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


@mitchus 部分是的,我只是增加了任务数量并为洗牌分配了更多的内存。此外,我还优化了我的代码以压缩数据结构大小... - Vijay Innamuri
2个回答

62

学习性能调优 Spark 需要进行大量的调查和学习。有一些很不错的资源,包括这个视频。Spark 1.4 版本在界面中具有更好的诊断和可视化功能,可以帮助您。

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

您可以:

  1. 手动 repartition() 您之前的阶段,以便从输入中获得更小的分区。
  2. 通过增加执行器进程的内存(spark.executor.memory)来增加洗牌缓冲区的大小。
  3. 通过将分配给它的执行器内存的比例(spark.shuffle.memoryFraction)从默认值 0.2 增加到更大的值来增加洗牌缓冲区的大小。您需要归还spark.storage.memoryFraction
  4. 通过降低工作线程(SPARK_WORKER_CORES)与执行器内存的比率来减少每个线程的洗牌缓冲区大小。

如果有专家在听,请告诉我更多关于 memoryFraction 设置如何交互以及它们的合理范围。


重新分区可能会洗牌不必要的数据,使用内部的coalesce函数可以使用combiner来最小化洗牌。 - Venu A Positive
11
@VenuAPositive认为他建议将分区重新划分到更多的分区,而不是减少分区。如果要减少分区,则使用coalesce操作会更合适。 - Carlos Bribiescas
4
自Spark 1.5起,除非启用遗留模式,否则不再使用spark.shuffle.memoryFraction。请参阅:https://spark.apache.org/docs/latest/configuration.html。 - y.selivonchyk
6
这个回答(虽然有用)实际上并没有解答为什么洗牌溢写比洗牌读取要大得多的问题。 - abeboparebop

7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接