我有一个包含2个工作节点和1个驱动程序节点的小型Spark(v 2.1.1)集群。硬件配置如下: 主/驱动节点 - 4核,8GB RAM 工人 - 4核,16GB RAM
spark提交作业的Spark属性在这里 - Spark properties screenshot。这项工作很简单 - 对于给定的搜索参数,从Elasticsearch集群中提取文档,并计算数据的某些指标。从Es文档创建spark数据帧。数据框有15列,而没有。行的范围可以从50万到10M +行。数据帧被缓存,因为它是所有度量计算的源。计算涉及总计数,总和,平均值等。这是其中一个计算的代码片段 -
''' Start & End journey pages '''
df_frag = df.select('visit_id', 'hit_seq_nbr', 'concategory')
df_frag = df_frag.withColumn('hit_seq_nbr',
df_frag['hit_seq_nbr'].cast(ShortType()))
grpd = df_frag.groupby('visit_id').agg(min('hit_seq_nbr').alias('hit_min'), max('hit_seq_nbr').alias('hit_max'))
df_frag2 = df_frag.join(grpd, on='visit_id', how='left')
first_pages_df = df_frag2.select('concategory').filter('hit_seq_nbr == hit_min')\
.groupby('concategory')\
.agg(count('concategory').alias('page_count'))
# total = first_pages_df.select('page_count').groupBy().sum('page_count').withColumnRenamed('sum(page_count)', 'total_page_count')
# first_pages_df = first_pages_df.crossJoin(total)
# first_pages_df = first_pages_df.select('concategory',
# round(100. * col('page_count') / col('total_page_count'), scale=2).alias('perc'))\
# .orderBy('perc', ascending=False)
total = first_pages_df.select('page_count').groupBy().sum('page_count').withColumnRenamed('sum(page_count)', 'total_page_count')
total = total.collect()[0]['total_page_count']
perc = udf(lambda r: 100. * r / total)
first_pages_df = first_pages_df.withColumn('perc', round(perc('page_count'), scale=2)).orderBy('perc', ascending=False)
# first_pages_df.show()
# print total
# print '======================='
top3_rows = first_pages_df.take(3)
the_metrics['journey_start'] = [(r.concategory, r.perc) for r in top3_rows]
dispose_dataframe([first_pages_df, grpd, total, df_frag])
对于10M +行的数据集,缓存的数据帧消耗大约300MB的可用存储内存(Spark Executors screenshot)。
这个火花作业遇到的问题是最后一次计算中的随机OOM错误,它有一个类似于上面代码片段的.collect()。我说是随机的,因为有一些已经成功完成的运行,但大多数运行都与OOM有关。使用< 10M行的数据集可以正常运行作业。此外,一旦遇到OOM,则后续10M +作业会重复该错误。在这一点上,我只是重新运行停止/启动主和&奴隶脚本。我正在寻找这些问题的答案 -
OOM随机发生的原因是什么?
.collect()应用于最后一次转换,这是一个聚合数据帧。根据我的理解,这应该限制调用collect()的数据帧的大小 - 在大多数情况下它是一个单行列数据帧 - 但此时OOM发生。无论转换如何,只要遇到collect(),整个数据集就会被加载到驱动程序内存中吗?
我并不完全相信这是一个硬件短缺,因为偶尔的成功运行。或者它是大型数据集的驱动程序硬件缺点?