簡體   English   中英

將kafka的批處理流火花生成單個文件

[英]Spark batch-streaming of kafka into single file

我正在使用批處理流(maxRatePerPartition 10.000)從Kafka流數據。 因此,每批處理10.000 kafka消息。

在此批處理運行中,我通過從rdd中創建一個dataFrame來處理每條消息。 處理之后,我使用以下命令將每個處理的記錄保存到同一文件:dataFrame.write.mode(SaveMode.append)。 因此,它將所有消息附加到同一文件。

只要在一次批處理中運行就可以。 但是,在執行下一個批處理運行(處理了下10.000條消息)之后,它將為接下來的10.000條消息創建一個新文件。

現在的問題是:每個文件(塊)保留文件系統的50mb,但僅包含1mb(10.000條消息)。 我寧願不將每個批處理都創建新文件,而是將它們全部附加到一個文件中,只要它不超過50mb。

您知道如何執行此操作,或者為什么在我的示例中它不起作用? 您可以在這里查看我的編碼:

import kafka.serializer.{DefaultDecoder, StringDecoder}
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{SQLContext, SaveMode}
import org.apache.spark.streaming.kafka._
import org.apache.spark.streaming.{Seconds, StreamingContext, Time}
import org.apache.spark.{SparkConf, SparkContext}

import scala.collection.immutable.Set


object SparkStreaming extends Constants {


  def main(args: Array[String]) {

//create a new Spark configuration...
val conf = new SparkConf()
  .setMaster("local[2]") // ...using 2 cores
  .setAppName("Streaming")
  .set("spark.streaming.kafka.maxRatePerPartition", "10000")  //... processing max. 10000 messages per second

//create a streaming context for micro batch
val ssc = new StreamingContext(conf, Seconds(1)) //Note: processing max. 1*10000 messages (see config above.)

//Setup up Kafka DStream
val kafkaParams = Map("metadata.broker.list" -> "sandbox.hortonworks.com:6667",
  "auto.offset.reset" -> "smallest") //Start from the beginning
val kafkaTopics = Set(KAFKA_TOPIC_PARQUET)

val directKafkaStream = KafkaUtils.createDirectStream[String, Array[Byte], StringDecoder, DefaultDecoder](ssc,
  kafkaParams, kafkaTopics)

val records = directKafkaStream.map(Source => StreamingFunctions.transformAvroSource(Source))


records.foreachRDD((rdd: RDD[TimeseriesRddRecord], time: Time) => {
  val sqlContext = SQLContext.getOrCreate(rdd.sparkContext) // Worker node singleton
  import sqlContext.implicits._

  val dataFrame = rdd.toDF()

  dataFrame.write.mode(SaveMode.Append).partitionBy(PARQUET_PARTITIONBY_COLUMNS :_*).parquet(PARQUET_FILE_PATH_TIMESERIES_LOCAL)
  println(s"Written entries: ${dataFrame.count()}")
}
)


//start streaming until the process is killed
ssc.start()
ssc.awaitTermination()

  }


  /** Case class for converting RDD to DataFrame */
  case class DataFrameRecord(thingId: String, timestamp: Long, propertyName: String, propertyValue: Double)


  /** Lazily instantiated singleton instance of SQLContext */
  object SQLContextSingleton {

@transient private var instance: SQLContext = _

def getInstance(sparkContext: SparkContext): SQLContext = {
  if (instance == null) {
    instance = new SQLContext(sparkContext)
  }
  instance
    }
  }

}

我很高興得到您的想法。 謝謝,亞歷克斯

這可以通過使用coalesce功能然后覆蓋現有文件來完成。

但是,正如線程中所討論的那樣, 當程序中止時Spark合並會釋放文件,而當程序中斷時會出錯。

因此,暫時似乎不足以實現這種邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM