Scala 用于databricks可扩展集群的Spark重新分区逻辑

Scala 用于databricks可扩展集群的Spark重新分区逻辑,scala,apache-spark,gzip,azure-databricks,Scala,Apache Spark,Gzip,Azure Databricks,Databricks spark cluster可根据负载进行更换 我正在spark中读取gzip文件,并对rdd进行重新分区,以获得并行性,因为gzip文件将在单核上读取并生成 根据理想的分区数是集群中我可以在重新分区期间设置的核心数,但是在自动缩放集群的情况下,这个数字将根据集群的状态和其中有多少执行器而变化 那么,对于一个可自动伸缩的spark集群,分区逻辑应该是什么呢 编辑1: 文件夹不断增长,gzip文件定期出现在其中,gzip文件大小约为10GB,未压缩大小约为150GB。我知道多个

Databricks spark cluster可根据负载进行更换

我正在spark中读取gzip文件,并对rdd进行重新分区,以获得并行性,因为gzip文件将在单核上读取并生成

根据理想的分区数是集群中我可以在重新分区期间设置的核心数,但是在自动缩放集群的情况下,这个数字将根据集群的状态和其中有多少执行器而变化

那么,对于一个可自动伸缩的spark集群,分区逻辑应该是什么呢

编辑1:

文件夹不断增长,gzip文件定期出现在其中,gzip文件大小约为10GB,未压缩大小约为150GB。我知道多个文件可以并行读取。但对于单个超大文件,databricks可能会尝试自动扩展集群,但即使在扩展集群中的核心后,我的数据帧的分区数会减少(基于集群以前的状态,它可能具有较少的核心)

即使我的集群将自动扩展(横向扩展),处理也将限于我所使用的分区数

num_partitions = <cluster cores before scaling>
df.repartition(num_partitions)
num\u分区=
重新分区(num_分区)

对于可拆分的文件/数据,分区将主要根据核心、操作范围窄或宽、文件大小等自动创建。分区也可以使用
合并
重新分区
进行编程控制。但是对于一个gzip/un可拆分文件,一个文件只有一个任务,它可以是尽可能多的并行内核(如您所说)

对于动态集群,您可以选择将作业指向包含大量gzip文件的文件夹/存储桶。假设你有1000个文件要处理,你有10个内核,那么10个将并行。当集群动态增加到20时,20将并行运行。这是自动发生的,您无需为此编写代码。唯一的问题是,您不能缩放比可用内核更少的文件。这是不可拆分文件的一个已知缺陷


另一个选项是根据可用文件的数量和大小定义作业的集群大小。您可以找到基于历史运行时间的时间公式。假设您有5个大文件和10个小文件(大小为大文件的一半),那么您可以分配20个内核(10+2*5)来高效地使用集群资源

对于可拆分的文件/数据,分区将主要根据核心、操作范围窄或宽、文件大小等自动创建。分区也可以使用
coalesce
repartition
进行编程控制。但是对于一个gzip/un可拆分文件,一个文件只有一个任务,它可以是尽可能多的并行内核(如您所说)

对于动态集群,您可以选择将作业指向包含大量gzip文件的文件夹/存储桶。假设你有1000个文件要处理,你有10个内核,那么10个将并行。当集群动态增加到20时,20将并行运行。这是自动发生的,您无需为此编写代码。唯一的问题是,您不能缩放比可用内核更少的文件。这是不可拆分文件的一个已知缺陷


另一个选项是根据可用文件的数量和大小定义作业的集群大小。您可以找到基于历史运行时间的时间公式。假设您有5个大文件和10个小文件(大小为大文件的一半),那么您可以分配20个内核(10+2*5)来高效地使用集群资源

标准gzip文件是不可拆分的,因此Spark将只使用一个内核、一个任务来处理gzip文件,无论您的设置是什么[从Spark 2.4.5/3.0起]。希望在创建大型文件时,世界将转向bzip2或其他可拆分压缩技术

如果您直接将数据写入拼花地板,您将得到一个可拆分的拼花地板文件。这将由一个核心写出。 如果坚持使用默认的gzip编解码器,最好在读取后重新分区,并写出多个拼花文件

from pyspark.sql.types import StructType, StructField, StringType, DoubleType, IntegerType
schema = StructType([
  StructField("a",IntegerType(),True),
  StructField("b",DoubleType(),True),
  StructField("c",DoubleType(),True)])

input_path = "s3a://mybucket/2G_large_csv_gzipped/onebillionrows.csv.gz"

spark.conf.set('spark.sql.files.maxPartitionBytes', 1000 * (1024 ** 2))
df_two = spark.read.format("csv").schema(schema).load(input_path)
df_two.repartition(32).write.format("parquet").mode("overwrite").save("dbfs:/tmp/spark_gunzip_default_remove_me")
我最近发现了一个可拆分的gzip编解码器,并且初步测试非常有希望。该编解码器实际上多次读取该文件,每个任务先扫描一定数量的字节(不进行解压缩),然后开始解压缩。 当需要将数据框作为拼花文件写入时,这种方法的好处就会得到回报。您将得到多个并行写入的文件,以获得更高的吞吐量和更短的挂钟时间(您的CPU时间将更高)

参考:

我的测试用例:

from pyspark.sql.types import StructType, StructField, StringType, DoubleType, IntegerType
schema = StructType([
  StructField("a",IntegerType(),True),
  StructField("b",DoubleType(),True),
  StructField("c",DoubleType(),True)])

input_path = "s3a://mybucket/2G_large_csv_gzipped/onebillionrows.csv.gz"

spark.conf.set('spark.sql.files.maxPartitionBytes', 1000 * (1024 ** 2))
df_gz_codec = (spark.read
               .option('io.compression.codecs', 'nl.basjes.hadoop.io.compress.SplittableGzipCodec')
               .schema(schema)
               .csv(input_path)
               )
df_gz_codec.write.format("parquet").save("dbfs:/tmp/gunzip_to_parquet_remove_me")

标准的gzip文件是不可拆分的,因此Spark将只使用一个内核、一个任务来处理gzip文件,无论您的设置是什么[从Spark 2.4.5/3.0起]。希望在创建大型文件时,世界将转向bzip2或其他可拆分压缩技术

如果您直接将数据写入拼花地板,您将得到一个可拆分的拼花地板文件。这将由一个核心写出。 如果坚持使用默认的gzip编解码器,最好在读取后重新分区,并写出多个拼花文件

from pyspark.sql.types import StructType, StructField, StringType, DoubleType, IntegerType
schema = StructType([
  StructField("a",IntegerType(),True),
  StructField("b",DoubleType(),True),
  StructField("c",DoubleType(),True)])

input_path = "s3a://mybucket/2G_large_csv_gzipped/onebillionrows.csv.gz"

spark.conf.set('spark.sql.files.maxPartitionBytes', 1000 * (1024 ** 2))
df_two = spark.read.format("csv").schema(schema).load(input_path)
df_two.repartition(32).write.format("parquet").mode("overwrite").save("dbfs:/tmp/spark_gunzip_default_remove_me")
我最近发现了一个可拆分的gzip编解码器,并且初步测试非常有希望。该编解码器实际上多次读取该文件,每个任务先扫描一定数量的字节(不进行解压缩),然后开始解压缩。 当需要将数据框作为拼花文件写入时,这种方法的好处就会得到回报。您将得到多个并行写入的文件,以获得更高的吞吐量和更短的挂钟时间(您的CPU时间将更高)

参考:

我的测试用例:

from pyspark.sql.types import StructType, StructField, StringType, DoubleType, IntegerType
schema = StructType([
  StructField("a",IntegerType(),True),
  StructField("b",DoubleType(),True),
  StructField("c",DoubleType(),True)])

input_path = "s3a://mybucket/2G_large_csv_gzipped/onebillionrows.csv.gz"

spark.conf.set('spark.sql.files.maxPartitionBytes', 1000 * (1024 ** 2))
df_gz_codec = (spark.read
               .option('io.compression.codecs', 'nl.basjes.hadoop.io.compress.SplittableGzipCodec')
               .schema(schema)
               .csv(input_path)
               )
df_gz_codec.write.format("parquet").save("dbfs:/tmp/gunzip_to_parquet_remove_me")

当你否决投票时,请留下评论。请看我的回答是否有帮助。我没有投反对票,我投赞成票