Spark Streaming将S3附加为Parquet格式,过多的小分区

时间:2016-12-15 02:32:00

标签: apache-spark amazon-s3 streaming parquet

我正在构建一个使用Spark Streaming从AWS EMR上的Kinesis流接收数据的应用程序。其中一个目标是将数据保存到S3(EMRFS),为此我使用了2分钟不重叠的窗口。

我的方法:

Kinesis Stream - > Spark Streaming批处理持续时间约为60秒,使用120s的非重叠窗口,将流数据保存到S3中:

val rdd1 = kinesisStream.map( rdd => /* decode the data */)
rdd1.window(Seconds(120), Seconds(120).foreachRDD { rdd =>
        val spark = SparkSession...
        import spark.implicits._
        // convert rdd to df
        val df = rdd.toDF(columnNames: _*)
        df.write.parquet("s3://bucket/20161211.parquet")
}

以下是s3://bucket/20161211.parquet一段时间后的样子: Spark Streaming S3 Parquet

正如您所看到的,许多碎片化的小分区(读取性能非常糟糕)......问题是,当我将数据流式传输到这个S3镶木地板文件时,有没有办法控制小分区的数量? / p>

由于

我想做的是,每天都做这样的事情:

val df = spark.read.parquet("s3://bucket/20161211.parquet")
df.coalesce(4).write.parquet("s3://bucket/20161211_4parition.parquet")

我将数据帧重新分区为4个分区并将其保存回来....

它有效,我觉得每天这样做都不是优雅的解决方案......

1 个答案:

答案 0 :(得分:3)

这实际上非常接近您想要做的事情,每个分区都将作为Spark中的单个文件写出来。但是coalesce有点令人困惑,因为它可以(有效地)应用于调用coalesce的上游。 Scala文档的警告是:

However, if you're doing a drastic coalesce, e.g. to numPartitions = 1,
this may result in your computation taking place on fewer nodes than
you like (e.g. one node in the case of numPartitions = 1). To avoid this,
you can pass shuffle = true. This will add a shuffle step, but means the
current upstream partitions will be executed in parallel (per whatever
the current partitioning is).

在数据集中,persistcount更容易进行广泛评估,因为默认coalesce函数不会将repartition作为输入标志(尽管您可以手动构建Repartition的实例。

另一种选择是使用第二个定期批处理作业(甚至是第二个流作业)来清理/合并结果,但这可能有点复杂,因为它引入了第二个移动部件来跟踪。