Spark join总是停留在同一个任务上,我该怎么调试?

时间:2016-02-25 21:25:05

标签: apache-spark pyspark

我正在使用pyspark来运行此类联接:

rdd1=sc.textFile(hdfs_dir1).map(lambda row: (getKey1(row),getData1(row)))
rdd2=sc.textFile(hdfs_dir2).map(lambda row: (getKey2(row),getData2(row)))
result=rdd1.join(rdd2).collect()

作业执行第一个300任务的速度非常快(每个约为几秒),并在到达任务301/308时挂起,即使我让它运行了好几天。

我尝试使用不同的配置(工作人员数,内存数,cpus数,核心数,随机播放率)运行pyspark shell,结果总是一样。

可能是什么原因?以及如何调试它?

3 个答案:

答案 0 :(得分:1)

Collect将尝试在应用程序驱动程序节点中获取您的联接结果,并且您将遇到内存问题。

连接操作将导致大量的随机操作,但您可以通过使用布隆过滤器(Bloom filter)来减少此操作。您为一个分区中的键构建了一个bloom过滤器,广播并filter另一个分区。应用此操作后,您应该期望更小的RDD(如果您在这两个操作中没有完全相同的键),并且join操作应该更快。

可以有效地收集布隆过滤器,因为您可以将由一个元素设置的位与由另一个元素设置的位组合为OR,这是关联和可交换的。

答案 1 :(得分:1)

您可以通过调用count来缩小这是否是collect()调用的问题,而不是将结果拉入驱动程序是否存在问题:

result=rdd1.join(rdd2).count()

如果计数有效,最好添加样本或限制,如果您尝试查看结果,请调用collect()。

您还可以查看Spark UI中的任务,以查看是否已将任务分配给特定执行程序,并再次使用UI查看执行程序日志。在executors选项卡中,您可以执行正在处理任务的执行程序的线程转储。如果您进行一些线程转储并进行比较,请检查是否有线程挂起。

查看驱动程序log4j日志,stdout / stderr日志中的任何其他错误。

答案 2 :(得分:1)

有没有人能够解决这个问题?我的猜测是问题是由于执行程序之间的数据混乱。我荒谬地使用了两个小数据集(10条记录),没有丢失密钥,但仍然存在连接操作。我不得不最终杀死这个实例。在我的情况下唯一可以帮助的是cache()。

如果我们采取上述例子

rdd1=sc.textFile(hdfs_dir1).map(lambda row: (getKey1(row),getData1(row)))
rdd2=sc.textFile(hdfs_dir2).map(lambda row: (getKey2(row),getData2(row)))
# cache it
rdd1.cache()
rdd2.cache()
# I also tried rdd1.collect() and rdd2.collect() to get data cached
# then try the joins 
result=rdd1.join(rdd2)
# I would get the answer 
result.collect() # it works

我无法找到为什么缓存工作(显然,它应该也有其他工作,即没有缓存())。