我有一个关于火花的基本问题。我通常使用50个核心运行火花工作。在查看作业进度时,大多数时候它会显示并行运行的50个进程(正如它应该这样做),但有时它只显示并行运行的2个或4个spark进程。像这样:
[Stage 8:================================> (297 + 2) / 500]
正在处理的RDD在超过100个分区上repartitioned
。所以这不应成为一个问题。
我有一个观察结果。我已经看到大多数时候发生的模式,SparkUI中的数据位置显示NODE_LOCAL
,而有时所有50个进程都在运行,其中一些进程显示RACK_LOCAL
。
这让我怀疑,这可能是因为数据在同一节点中处理之前被缓存以避免网络开销,这会减慢进一步的处理速度。
如果是这种情况,那么避免它的方法是什么。如果不是这样的话,那么会发生什么?
答案 0 :(得分:3)
经过一周或更长时间的努力解决问题后,我想我已经找到导致问题的原因了。
如果您正在努力解决同样的问题,那么开始的好处是检查Spark实例是否配置正常。关于它有一个很棒的cloudera blog post。
但是,如果问题不在于配置(就像我的情况那样),那么问题就出在你的代码中。问题是,有时由于不同的原因(数据源中的连接偏斜,分区不均匀等),您正在处理的RDD在2-3个分区上获取大量数据,而其余分区的数据非常少。
为了减少网络中的数据混乱,Spark尝试每个执行程序处理驻留在该节点上的本地数据。因此,2-3个执行器正在工作很长时间,其余的执行器只是在几毫秒内完成了数据。这就是我遇到上述问题所描述的问题的原因。
调试此问题的方法首先是检查RDD的分区大小。如果一个或几个分区与其他分区相比非常大,那么下一步就是在大分区中查找记录,这样您就可以知道,特别是在偏移连接的情况下,哪个密钥变得偏斜。我写了一个小函数来调试它:
from itertools import islice
def check_skewness(df):
sampled_rdd = df.sample(False,0.01).rdd.cache() # Taking just 1% sample for fast processing
l = sampled_rdd.mapPartitionsWithIndex(lambda x,it: [(x,sum(1 for _ in it))]).collect()
max_part = max(l,key=lambda item:item[1])
min_part = min(l,key=lambda item:item[1])
if max_part[1]/min_part[1] > 5: #if difference is greater than 5 times
print 'Partitions Skewed: Largest Partition',max_part,'Smallest Partition',min_part,'\nSample Content of the largest Partition: \n'
print (sampled_rdd.mapPartitionsWithIndex(lambda i, it: islice(it, 0, 5) if i == max_part[0] else []).take(5))
else:
print 'No Skewness: Largest Partition',max_part,'Smallest Partition',min_part
它为我提供了最小和最大的分区大小,如果这两者之间的差异超过5倍,它会打印出最大分区的5个元素,这应该可以让您大致了解分析的内容。
一旦你发现问题是倾斜的分区,你就可以找到一种方法来摆脱那个偏斜的键,或者你可以重新划分你的数据帧,这将迫使它得到平均分配,你就是&#39 ;现在看到所有的执行者将在相同的时间内工作,你会看到更少的可怕的OOM错误,处理速度也会非常快。
这些只是我作为Spark新手的两分钱,我希望Spark专家可以在这个问题上添加更多内容,因为我认为Spark世界中很多新手经常遇到类似的问题。