以下是我的问题,我想聚合一些存储在S3上的数据。作为流水线的初始输入,我使用了一个文本文件,其中包含应聚合的所有S3文件的路径。
PCollection<String> readInputPipeline = p.apply("ReadLines", TextIO.read().from(options.getInputFile()));
readInputPipeline = readInputPipeline.apply(ParDo.of(new ReadFromS3Mapper()));
输入文件有346k行。当我将此代码部署到Spark集群时,即使有许多内核可用,也似乎仅在2个Spark任务中发生,这仅发生在S3中。我有什么办法可以增加此操作的并行性?
我正在使用具有以下选项的主服务器(m3.xlarge)和核心计算机(R3.4xlarge)在Amazon的EMR上运行此
"spark-submit"
"--driver-java-options='-Dspark.yarn.app.container.log.dir=/mnt/var/log/hadoop'",
"--master", "yarn",
"--executor-cores","16",
"--executor-memory","6g"
PS:也许解决方案可能是我不应该在这种情况下进行这种昂贵的IO操作?
答案 0 :(得分:0)
Spark决定如何分割输入,在这里决定一遍遍遍整个文件,因为它很小。
我在distcp application中做了类似的事情;它使用Spark的ParallelCollectionRDD类来明确告诉spark将清单一一拆分。
该类足以让您执行类似的操作-您可能必须在本地将初始文本文件读取到列表中,然后将列表传递给ParallelCollectionRDD
构造函数
答案 1 :(得分:0)
回复较晚,但我调查了Beam在2.16.0版本中的作用。
在第一个TextIO.read()
之后,您将获得2个任务-我怀疑您最初的34.6万行文件列表已被分成两个分区。此行为由TextIO内部的desiredBundleSize控制,该代码硬编码为64MB。
在Spark中,您的操作ReadFromS3Mapper
将“融合”到到达的记录中,并且您将始终停留在两个分区中。
如果要保留相同的代码,可以在两个转换之间强制重新分区:
PCollection<String> allContents = p.apply("ReadLines", TextIO.read().from(options.getInputFile()))
.apply("Repartition", Reshuffle.viaRandomKey())
.apply(ParDo.of(new ReadFromS3Mapper()));
作为替代,TextIO和FileIO实用程序中提供了许多有趣的模式。有一个与您的almost exactly相匹配的示例(暗含reshuffle
)。