我正在尝试加载存储在S3上的〜1M文件集。运行sc.binaryFiles("s3a://BUCKETNAME/*").count()
我得到了WARN TaskSetManager: Stage 0 contains a task of very large size (177 KB). The maximum recommended task size is 100 KB
。接下来是失败的任务
我看到它为这个阶段推断出128个分区,这个分区太低了,请注意,当在400K文件桶上运行相同的命令时,分区数量将会高得多(约2K分区)并且操作将成功。< / p>
设置较高的minPartitions
没有帮助;
设置较高的spark.default.parallelism
也无济于事。
唯一有效的方法是创建每个1000个文件的多个较小的RDD,并在它们上运行sc.union
,这种方法的问题在于它太慢了。
如何减轻这个问题?
更新:
继续看看BinaryFileRDD.getPartitions()
中的分区数是如何解决的,这让我得到了这段代码:
def setMinPartitions(sc: SparkContext, context: JobContext, minPartitions: Int) {
val defaultMaxSplitBytes = sc.getConf.get(config.FILES_MAX_PARTITION_BYTES)
val openCostInBytes = sc.getConf.get(config.FILES_OPEN_COST_IN_BYTES)
val defaultParallelism = sc.defaultParallelism
val files = listStatus(context).asScala
val totalBytes = files.filterNot(_.isDirectory).map(_.getLen + openCostInBytes).sum
val bytesPerCore = totalBytes / defaultParallelism
val maxSplitSize = Math.min(defaultMaxSplitBytes, Math.max(openCostInBytes, bytesPerCore))
super.setMaxSplitSize(maxSplitSize)
}
我跟着计算,它仍然没有意义,我应该得到一个更大的数字。
所以我试图减少config.FILES_MAX_PARTITION_BYTES
配置(spark.files.maxPartitionBytes
) - 这确实增加了分区的数量,并使工作完成,但是我仍然得到了原始警告(有点但是,分区的munber比在400K文件集上运行时要小。
答案 0 :(得分:0)
问题根源在于文件的大小:令我惊讶的是,s3中的文件没有正确上传,它们的大小比它们应该小了100倍。这导致setMinPartitions
计算包含大量小文件的拆分。每个拆分本质上是一个逗号分隔的文件路径字符串,因为每个拆分有很多文件,我们有一个非常长的指令字符串,应该传递给所有工作人员。这使网络负担沉重,导致整个流程失败。将spark.files.maxPartitionBytes
设置为较低的值可以解决问题。