为什么使用saveAsTextFile时,在Google Dataproc中运行的Spark会在外部存储(GCS)上存储临时文件而不是本地磁盘或HDFS?

时间:2016-12-15 18:25:34

标签: apache-spark pyspark google-cloud-dataproc

我运行了以下PySpark代码:

from pyspark import SparkContext

sc = SparkContext()

data = sc.textFile('gs://bucket-name/input_blob_path')
sorted_data = data.sortBy(lambda x: sort_criteria(x))
sorted_data.saveAsTextFile(
    'gs://bucket-name/output_blob_path',
    compressionCodecClass="org.apache.hadoop.io.compress.GzipCodec"
)

作业成功完成。但是,在作业执行期间,Spark在以下路径gs://bucket-name/output_blob_path/_temporary/0/中创建了许多临时blob。我意识到在最后删除所有这些临时blob占用了一半的作业执行时间,并且在此期间CPU利用率为1%(浪费大量资源)。

有没有办法将临时文件存储在本地驱动器(或HDFS)而不是GCP上?我仍然希望将最终结果(已排序的数据集)保存到GCP。

我们正在使用带有10个工作节点的Dataproc Spark集群(VM类型16核,60GM)。输入数据的量为10TB。

2 个答案:

答案 0 :(得分:2)

您看到的_temporary个文件可能是引擎盖下使用的FileOutputCommitter的工件。重要的是,这些临时blob不是严格的“临时”数据,但实际上是完成的输出数据,只有在作业完成时才“重命名”到最终目的地。通过重命名“提交”这些文件实际上很快,因为源和目标都在GCS上;由于这个原因,没有办法用临时文件放在HDFS上然后“提交”到GCS中来替换工作流的那一部分,因为这样提交就需要将整个输出数据集重新管理从HDFS返回到GCS。具体而言,底层的Hadoop FileOutputFormat类不支持这样的习惯用法。

GCS本身不是一个真正的文件系统,而是一个“对象存储”,Dataproc中的GCS连接器只能最大限度地模仿HDFS。一个结果是删除文件的目录填充实际上需要GCS删除引擎盖下的单个对象,而不是仅仅取消链接inode的真实文件系统。

在实践中,如果您正在进行此操作,则可能意味着您的输出无论如何都会被拆分为太多文件,因为清理确实一次批量生成~1000个文件。因此,通常不应该显着减慢数万个输出文件。拥有太多文件也会使这些文件的未来工作变得更慢。最简单的修复方法通常是尽可能减少输出文件的数量,例如使用repartition()

from pyspark import SparkContext

sc = SparkContext()

data = sc.textFile('gs://bucket-name/input_blob_path')
sorted_data = data.sortBy(lambda x: sort_criteria(x))
sorted_data.repartition(1000).saveAsTextFile(
    'gs://bucket-name/output_blob_path',
    compressionCodecClass="org.apache.hadoop.io.compress.GzipCodec"
)

答案 1 :(得分:0)

我和你以前有相同的问题。 My blog: spark speedup write file to cloud storage。然后我找到了这篇文章Spark 2.0.0 Cluster Takes a Longer Time to Append Data

  

如果发现使用Spark 2.0.0版本的集群将数据追加到现有数据集所需的时间更长,尤其是所有Spark作业均已完成,但您的命令尚未完成,这是因为驱动程序节点已完成将任务的输出文件从作业临时目录一个接一个地移到最终目标,这对于云存储来说很慢。要解决此问题,请将mapreduce.fileoutputcommitter.algorithm.version设置为2。请注意,此问题不会影响覆盖数据集或将数据写入新位置。

当我们使用GCS作为tmp存储时,此问题将在云环境中放大。

如何解决?

您只需添加此参数即可解决此问题,这意味着在将文件保存到GCS时不会创建tmp文件。

write.option("mapreduce.fileoutputcommitter.algorithm.version", "2")

警告!

  

DirectParquetOutputCommitter已从Spark 2.0中删除,因为可能会丢失数据。