如何在耗尽内存之前让PySpark将中间结果写入磁盘?

时间:2017-03-17 05:06:26

标签: python hadoop apache-spark pyspark

背景:在Hadoop Streaming中,每个reduce作业都会在完成后写入hdfs,从而为Hadoop集群清除执行下一次reduce的方式。

我无法将此范例映射到(Py)Spark。

举个例子,

df = spark.read.load('path')
df.rdd.reduceByKey(my_func).toDF().write.save('output_path')

当我运行它时,群集会在将任何内容写入磁盘之前收集数据帧中的所有数据。至少这是我看到工作进展时的情况。

我的问题是我的数据比我的群集内存大得多,所以在写入任何数据之前我的内存不足。在Hadoop Streaming中,我们没有这个问题,因为输出数据被流式传输到磁盘,为后续批量数据腾出空间。

我考虑过这样的事情:

for i in range(100):
    (df.filter(df.loop_index==i)
        .rdd
        .reduceByKey(my_func)
        .toDF()
        .write.mode('append')
        .save('output_path'))

我只在每次迭代中处理我的数据子集。但这似乎很麻烦,主要是因为我必须坚持df,这是因为内存限制而无法实现的,或者我必须在每次迭代中从输入hdfs源重新读取。

使循环工作的一种方法是按天或者数据的其他一些子集对源文件夹进行分区。但是为了这个问题,让我们假设这是不可能的。

问题:如何在PySpark中运行这样的工作?我只需拥有一个更大的集群吗?如果是这样,在处理数据之前调整集群大小的常见做法是什么?

1 个答案:

答案 0 :(得分:0)

在大量分区中重新分区数据可能会有所帮助。下面的示例与您的for循环类似,但您可能希望先尝试使用较少的分区

df = spark.read.load('path').repartition(100)

您还应该查看当前使用的执行程序数量(--num-executors)。减少这个数字也应该减少你的内存占用。