我有一个执行大型连接的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
在这里一直很重要?驱动程序的内存是否用于我不知道的联接中的某些内容?
答案 0 :(得分:5)
仅仅因为您没有明确收集任何东西,并不意味着什么也没有收集到。由于问题是在联接期间发生的,因此最可能的解释是执行计划使用广播联接。在这种情况下,Spark将首先收集数据,然后广播它。
取决于配置和管道:
spark.sql.autoBroadcastJoinThreshold
小于spark.driver.maxResultSize
。要确定广播是否确实存在问题,请检查执行计划,如果需要,请删除广播提示并禁用自动广播:
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
}
如果任务数量巨大,则可能发生上述异常。