Spark分区(ing)如何处理HDFS中的文件?

时间:2015-03-12 13:48:43

标签: apache-spark hdfs

我正在使用HDFS在群集上使用Apache Spark。据我了解,HDFS正在数据节点上分发文件。因此,如果在文件系统上放置“file.txt”,它将被拆分为分区。 现在我正在打电话

rdd = SparkContext().textFile("hdfs://.../file.txt") 
来自Apache Spark的

rdd现在自动与文件系统上的“file.txt”分区相同吗? 当我打电话

时会发生什么
rdd.repartition(x)

其中x>然后是hdfs使用的分区? Spark会在物理上重新安排hdfs上的数据在本地工作吗?

实施例: 我在HDFS系统上放了一个30GB的文本文件,它将它分发到10个节点上。 威尔·斯帕克 a)使用相同的10个分区?和b)当我调用重新分区(1000)时,在群集中洗牌30GB?

4 个答案:

答案 0 :(得分:73)

当Spark从HDFS读取文件时,它会为单个输入拆分创建一个分区。输入拆分由用于读取此文件的Hadoop InputFormat设置。例如,如果您使用textFile(),它将在Hadoop中为TextInputFormat,这将为单个HDFS块返回单个分区(但分区之间的分割将在线路分割,而不是精确块拆分),除非你有一个压缩文本文件。如果是压缩文件,您将获得单个文件的单个分区(因为压缩文本文件不可拆分)。

当您致电rdd.repartition(x)时,它会执行您希望拥有的Nrdd个分区中x个分区的数据随机播放,分区将会完成以循环为基础。

如果你有一个30GB的未压缩文本文件存储在HDFS上,那么使用默认的HDFS块大小设置(128MB)它将存储在235个块中,这意味着你从这个文件读取的RDD将有235个分区。当您调用repartition(1000)时,您的RDD将被标记为以重新分区,但实际上只有在您将在此RDD之上执行操作时才会将其拖拽到1000个分区(延迟执行)概念)

答案 1 :(得分:10)

  

以下是" 如何将HDFS中的块作为分区加载到Spark worker中的快照"

在此图像中,4个HDFS块作为Spark分区加载到3个工作器内存中

Dataset in HDFS broken into partitions

  

示例:我在HDFS系统上放置了一个30GB的文本文件,它将它分发到10个节点上。

     

Will Spark

     

a)使用相同的10个分区?

     
    

Spark将相同的10个HDFS块作为分区加载到工作者内存中。我假设 30 GB文件的块大小应为3 GB 以获得10个分区/块(默认配置)

  
     

b)当我呼叫重新分区(1000)时,群集中是否有30GB的重播?

     
    

,Spark在工作节点之间对数据进行洗牌,以便在工作程序内存中创建1000个分区。

  

注意:

HDFS Block -> Spark partition   : One block can represent as One partition (by default)
Spark partition -> Workers      : Many/One partitions can present in One workers 

答案 2 :(得分:6)

除了@ 0x0FFF如果它从HDFS作为输入文件,它将像这个rdd = SparkContext().textFile("hdfs://.../file.txt")一样计算,当你rdd.getNumPatitions时,它将产生Max(2, Number of HDFS block)。我做了很多实验并发现了这个结果。再次明确地,您可以rdd = SparkContext().textFile("hdfs://.../file.txt", 400)将400作为分区,甚至可以按rdd.repartition重新分区,或者rdd.coalesce(10)减少到10

答案 3 :(得分:6)

使用spark-sql读取未存储的HDFS文件(例如镶木地板)时,DataFrame分区df.rdd.getNumPartitions的数量取决于以下因素:

  • spark.default.parallelism(大致可转换为该应用程序可用的#cores)
  • spark.sql.files.maxPartitionBytes(默认128MB)
  • spark.sql.files.openCostInBytes(默认4MB)

对分区数量的粗略估算是:

  • 如果您有足够多的内核来并行读取所有数据(即,每128MB数据至少有一个内核)

    AveragePartitionSize ≈ min(4MB, TotalDataSize/#cores) NumberOfPartitions ≈ TotalDataSize/AveragePartitionSize

  • 如果您没有足够多的内核

    AveragePartitionSize ≈ 128MB NumberOfPartitions ≈ TotalDataSize/AveragePartitionSize

确切的计算有些复杂,可以在FileSourceScanExec的代码库中找到,请参考here