超过`spark.driver.maxResultSize`而不向驱动程序提供任何数据

时间:2017-03-13 22:49:10

标签: scala apache-spark memory apache-spark-sql

我有一个执行大型连接的Spark应用程序

val joined = uniqueDates.join(df, $"start_date" <= $"date" && $"date" <= $"end_date")

然后将生成的DataFrame聚合为一行,可能有13k行。在连接过程中,作业失败并显示以下错误消息:

Caused by: org.apache.spark.SparkException: Job aborted due to stage failure: Total size of serialized results of 78021 tasks is bigger than spark.driver.maxResultSize (2.0 GB)

这是在没有设置spark.driver.maxResultSize的情况下发生的,因此我设置了spark.driver.maxResultSize=2G。然后,我对连接条件稍作修改,错误重新出现。

修改:在调整群集大小时,我还将DataFrame假设的分区数量增加了一倍.coalesce(256)增加到.coalesce(512),所以我不能确定它不是因为那个。

我的问题是,既然我没有向司机收集任何东西,为什么spark.driver.maxResultSize在这里一直很重要?驱动程序的内存是否用于我不知道的联接中的某些内容?

2 个答案:

答案 0 :(得分:5)

仅仅因为您没有明确收集任何东西,并不意味着什么也没有收集到。由于问题是在联接期间发生的,因此最可能的解释是执行计划使用广播联接。在这种情况下,Spark将首先收集数据,然后广播它。

取决于配置和管道:

  • 确保spark.sql.autoBroadcastJoinThreshold小于spark.driver.maxResultSize
  • 确保您不会force broadcast join使用未知大小的数据。
  • 虽然什么都没有说明这是问题所在,但在使用Spark ML实用程序时要小心。其中一些(最著名的是索引器)可以为驱动程序带来大量数据。

要确定广播是否确实存在问题,请检查执行计划,如果需要,请删除广播提示并禁用自动广播:

spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)

答案 1 :(得分:3)

从理论上讲,异常并不总是与客户数据相关。

有关任务执行结果的技术信息以序列化形式发送到驱动程序节点,并且此信息可能占用更多的内存,而不是阈值。

证明: 位于org.apache.spark.scheduler.TaskSetManager#canFetchMoreResults

中的错误消息
val msg = s"Total size of serialized results of ${calculatedTasks} tasks " +

在org.apache.spark.scheduler.TaskResultGetter#enqueueSuccessfulTask​​中调用的方法

        val (result, size) = serializer.get().deserialize[TaskResult[_]](serializedData) match {
        case directResult: DirectTaskResult[_] =>
          if (!taskSetManager.canFetchMoreResults(serializedData.limit())) {
            return
          }

如果任务数量巨大,则可能发生上述异常。