web-dev-qa-db-ja.com

Sparkを使用してs3a経由で寄木細工のファイルをs3に書き込むのは非常に遅い

Amazon S3を使用して、parquetファイルをSpark 1.6.1に書き込もうとしています。私が生成している小さなparquetは、一度書き込まれた~2GBなので、それほど多くのデータではありません。 Spark outを使用できるプラットフォームとして証明しようとしています。

基本的には、dataframesstar schemaを設定し、それらのテーブルを寄木細工に書きます。データはベンダーから提供されたcsvファイルから取得し、Spark=としてETLプラットフォームとして使用しています。現在、ec2(r3.2xlarge)に3ノードのクラスターがありますしたがって、エグゼキュータと合計16コアのメモリの120GB

入力ファイルの合計は約22GBで、今のところ約2GBのデータを抽出しています。最終的に、完全なデータセットのロードを開始すると、これは数テラバイトになります。

これが私のスパーク/スカラpseudocodeです:

  def loadStage(): Unit = {
    sc.hadoopConfiguration.set("fs.s3a.buffer.dir", "/tmp/tempData")
    sc.hadoopConfiguration.set("spark.sql.parquet.output.committer.class","org.Apache.spark.sql.parquet.DirectParquetOutputCommitter")
    sc.hadoopConfiguration.set("spark.sql.Hive.convertMetastoreParquet","false")
    var sqlCtx = new SQLContext(sc)


    val DataFile = sc.textFile("s3a://my-bucket/archive/*/file*.gz")

    //Setup header table/df
    val header_rec = DataFile.map(_.split("\\|")).filter(x=> x(0) == "1")
    val headerSchemaDef = "market_no,rel_date,field1, field2, field3....."
    val headerSchema = StructType(headerSchemaDef.split(",").map(fieldName => StructField(fieldName, StringType,false)))
    val headerRecords = header_rec.map(p => Row(p(3), p(8), p(1), p(2), p(4), p(5), p(6) ))
    val header = sqlCtx.createDataFrame(headerRecords, headerSchema)
    header.registerTempTable("header")
    sqlCtx.cacheTable("header")


    //Setup fact table/df
    val fact_recs = DataFile.map(_.split("\\|")).filter(x=> x(0) == "2")
    val factSchemaDef = "market_no,rel_date,field1, field2, field3....."
    val factSchema = StructType(factSchemaDef.split(",").map(fieldName => StructField(fieldName, StringType,false)))
    val records = fact_recs.map(p => Row(p(11), p(12), p(1), p(2), p(3), p(4), p(5), p(6), p(7), p(8), p(9), p(10)))
    val df = sqlCtx.createDataFrame(records, factSchema)
    df.registerTempTable("fact")

    val results = sqlCtx.sql("select fact.* from header inner join fact on fact.market_no = header.market_no and fact.rel_date = header.rel_date")


    println(results.count())



    results.coalesce(1).write.mode(SaveMode.Overwrite).parquet("s3a://my-bucket/a/joined_data.parquet")


  }

465884512行のカウントには約2分かかります。寄せ木張りへの書き込みには8分かかります

coalesceが書き込みを行うドライバーに対してシャッフルを行うことを理解しています...しかし、それが取っている時間の長さは、私が何か重大な間違いをしていると思うようにしています。 coalesceがない場合、これにはまだ15分かかりますが、IMOはまだ長すぎて、大量のparquetファイルを生成します。私が持っているデータの1日あたり1つの大きなファイルが欲しいです。同様に、フィールド値によってパーティション分割を行うコードがあります。また、これをcsvに出力しようとしましたが、1時間ほどかかります。

また、ジョブを送信するときに、実行時の小道具を実際に設定していません。 1つのジョブのコンソール統計は次のとおりです。

  • 生きている労働者:2
  • 使用中のコア:合計16、使用16
  • 使用中のメモリ:合計117.5 GB、使用済み107.5 GB
  • アプリケーション:1実行中、5完了
  • ドライバー:0実行中、0完了
  • ステータス:生きている
17
Brutus35

Sparkのデフォルトは、特にS3への書き込み時に、I/O操作中に大量の(おそらく)不要なオーバーヘッドを引き起こします。 この記事 これについてさらに詳しく説明しますが、変更を検討したい設定が2つあります。

  • DirectParquetOutputCommitterを使用します。デフォルトでは、Sparkはすべてのデータを一時フォルダーに保存し、それらのファイルを後で移動します。DirectParquetOutputCommitterを使用すると、S3出力パスに直接書き込むことで時間を節約できます

    • Spark 2.0 + では使用できなくなりました。)
      • Jiraチケットで述べられているように、現在の解決策はです。
        1. S3aとHadoop 2.7.2+を使用するようにコードを切り替えます。すべてのラウンドでより良く、Hadoop 2.8でより良くなり、s3guardの基礎となります
        2. Hadoop FileOutputCommitterを使用して、mapreduce.fileoutputcommitter.algorithm.versionを2に設定します

    -スキーマのマージは Spark 1.5 の時点でデフォルトでオフになっています スキーマのマージをオフにします。スキーママージがオンの場合、ドライバーノードはすべてのファイルをスキャンして、スキーマの一貫性を確保します。これは分散操作ではないため、特にコストがかかります。を実行して、これがオフになっていることを確認します

    val file = sqx.read.option("mergeSchema", "false").parquet(path)

18
David

直接出力コミッターはspark codebaseから削除されています。削除したコードを独自のJARに記述/復活させる必要があります。問題が「無効なデータ」である場合、他の障害も問題を引き起こす可能性があること。

より明るい注意として、Hadoop 2.8は、S3から最適化されたバイナリ形式(ORC、Parquet)を読み取るためのS3Aの高速化をいくつか追加します。詳細については、 HADOOP-11694 を参照してください。また、作業の最後に堅牢なO(1)コミットを行うことができるはずの一貫したメタデータストアにAmazon Dynamoを使用している人もいます。

4
Steve Loughran

Spark S3への書き込みを高速化するための即時アプローチの1つは、 EMRFS S3-optimized Committer を使用することです。

ただし、s3aを使用する場合、このコミッター 使用不可

EMRFS S3に最適化されたコミッターが使用されない場合

コミッターは、次の状況では使用されません。

When writing to HDFS

-> When using the S3A file system

When using an output format other than Parquet, such as ORC or text

When using MapReduce or Spark's RDD API

AWS EMR 5.26でこの違いをテストしましたが、s3://の使用はs3a://よりも15%〜30%高速でした(ただし、依然として低速です)。

0
jmng

私もこの問題を抱えていました。残りの発言から追加されたものは、AWSからの完全な説明です: https://aws.Amazon.com/blogs/big-data/improve-Apache-spark-write-performance-on-Apache-parquet -formats-with-the-emrfs-s3-optimized-committer /

実験中にFileOutCommiter v2(v1から)に変更しただけで、書き込みが3〜4倍に改善されました。

self.sc._jsc.hadoopConfiguration().set("mapreduce.fileoutputcommitter.algorithm.version", "2")
0