Как уменьшить время обработки каждой партии с помощью Spark Streaming? - PullRequest
0 голосов
/ 26 сентября 2018

Моя цель - извлечь данные из Kafka с помощью Spark Streaming, преобразовать данные и сохранить их в корзину S3 в виде файлов Parquet, а также использовать папки на основе даты (Распределение данных для более быстрых запросов вAthena). Моя основная проблема заключается в том, что в процессе увеличивается количество активных пакетов, и я просто хочу иметь только одну активную партию.У меня проблема с задержкой, я пробовал разные конфигурации и размеры кластеров, чтобы решить каждую ванну за меньшее время, чем общая продолжительность ванны.Например, если у меня есть партия в 5 минут, я хочу разрешить эту партию менее чем за 5 минут и иметь такое поведение для всех партий в течение времени.Другими словами, я хочу:

1) Решать каждую партию быстрее, чем общее время.

2) Сохранять поведение предыдущего пункта для всех партий в течение времени и без ошибок.

3) Использовать как можно меньше ресурсов для расходования меньшего количества денег.

Что у меня есть?

В Kafka у нас есть почти 200 000 сообщений в секунду , и каждое сообщение имеет около 45 полей в Protobuffer, и я конвертирую каждое полев строку.Что касается вывода, я генерирую около 1 терабайт файлов Parquet в час в Amazon S3.В нашей теме Кафки есть 60 разделов .

Что я пробовал?

  • Различный интервал между партиями.(1 секунда, 10 секунд, 1 минута, 5 минут, 10 минут и т. Д.)
  • Увеличение кластера по вертикали и горизонтали.(Я использую Amazon EMR)
  • Различные конфигурации отправки с поддержкой искры (Макс. Скорость на раздел, противодавление, количество исполнителей и т. Д.)

Наконец, кто-то может порекомендуйте мне конфигурацию кластера для решения этой проблемы?С точки зрения количества узлов и вида машин.Кроме того, spark-submit конфигурация в соответствии с этим кластером.Кроме того, я не знаю, могу ли я выполнить оптимизацию в Scala-коде (я вставил приведенный ниже код) или как найти причину этой проблемы.


Дополнительная информация:

Это одна из команд, которые я попробовал:

spark-submit --deploy-mode cluster --master yarn

- conf spark.dynamicAllocation.enabled = false

- число исполнителей 30

- ядро ​​исполнителя 2

- память исполнителя 3G

- conf "spark.sql.parquet.mergeSchema = false"

- conf "spark.debug.maxToStringFields = 100"

- пакеты org.apache.spark: spark-sql-kafka-0-10_2.11: 2.3.0

- класс "RequestsDstream" RequestsDataLake-assembly-0.1.jar

Это код:

import java.io.{File, FileWriter, PrintWriter}
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Calendar
import com.tap.proto.ProtoMessages
import org.apache.spark._
import org.apache.spark.streaming._
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.SaveMode
import org.apache.spark.sql.functions.{col, date_format}


object SQLContextSingleton {
  @transient private var instance: SQLContext = null
  def getInstance(sparkContext: SparkContext): SQLContext = synchronized {
    if (instance == null) {
      instance = new SQLContext(sparkContext)
    }
    instance
  }
}

object RequestsDstream {

  def message_proto(value:Array[Byte]): Map[String, String] = {
    try {
      val dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
      val requests_proto = ProtoMessages.SspRequest.parseFrom(value)    
      val json = Map(
        "version" -> (requests_proto.getVersion().toString),
        "adunit" -> (requests_proto.getAdunit().toString),
        "adunit_original" -> (requests_proto.getAdunitOriginal().toString),
        "brand" -> (requests_proto.getBrand().toString),
        "country" -> (requests_proto.getCountry().toString),
        "device_connection_type" -> (requests_proto.getDeviceConnectionType().toString),
        "device_density" -> (requests_proto.getDeviceDensity().toString),
        "device_height" -> (requests_proto.getDeviceHeight().toString),
        "device_id" -> (requests_proto.getDeviceId().toString),
        "device_type" -> (requests_proto.getDeviceType().toString),
        "device_width" -> (requests_proto.getDeviceWidth().toString),
        "domain" -> (requests_proto.getDomain().toString),
        "endpoint" -> (requests_proto.getEndpoint().toString),
        "endpoint_type" -> (requests_proto.getEndpointType().toString),
        "endpoint_version" -> (requests_proto.getEndpointVersion().toString),
        "external_dfp_id" -> (requests_proto.getExternalDfpId().toString),
        "id_req" -> (requests_proto.getIdReq().toString),
        "ip" -> (requests_proto.getIp().toString),
        "lang" -> (requests_proto.getLang().toString),
        "lat" -> (requests_proto.getLat().toString),
        "lon" -> (requests_proto.getLon().toString),
        "model" -> (requests_proto.getModel().toString),
        "ncc" -> (requests_proto.getNcc().toString),
        "noc" -> (requests_proto.getNoc().toString),
        "non" -> (requests_proto.getNon().toString),
        "os" -> (requests_proto.getOs().toString),
        "osv" -> (requests_proto.getOsv().toString),
        "scc" -> (requests_proto.getScc().toString),
        "sim_operator_code" -> (requests_proto.getSimOperatorCode().toString),
        "size" -> (requests_proto.getSize().toString),
        "soc" -> (requests_proto.getSoc().toString),
        "son" -> (requests_proto.getSon().toString),
        "source" -> (requests_proto.getSource().toString),
        "ts" ->  (dateFormat.format(new Date(requests_proto.getTs()))).toString,
        "user_agent" -> (requests_proto.getUserAgent().toString),
        "status" -> (requests_proto.getStatus().toString),
        "delivery_network" -> (requests_proto.getDeliveryNetwork().toString),
        "delivery_time" -> (requests_proto.getDeliveryTime().toString),
        "delivery_status" -> (requests_proto.getDeliveryStatus().toString),
        "delivery_network_key" -> (requests_proto.getDeliveryNetworkKey().toString),
        "delivery_price" -> (requests_proto.getDeliveryPrice().toString),
        "device_id_original" -> (requests_proto.getDeviceIdOriginal().toString),
        "tracking_limited" -> (requests_proto.getTrackingLimited().toString),
        "from_cache" -> (requests_proto.getFromCache().toString)
      )

      return json

    }catch{
      case e:Exception=>            
        print(e)          

        return Map("error" -> "error")
    }
  }

  def main(args: Array[String]){    

    val conf = new SparkConf().setAppName("Requests DStream EMR 10 minutes")
    val ssc = new StreamingContext(conf, Seconds(60*10))
    val sc = ssc.sparkContext
    ssc.checkpoint("/home/data/checkpoint")
    val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    val date = format.format(Calendar.getInstance().getTime())
    val group_id = "Request DStream EMR " + date
    val kafkaParams = Map[String, Object](
      "bootstrap.servers" -> "ip.internal:9092",
      "key.deserializer" -> "org.apache.kafka.common.serialization.StringDeserializer",
      "value.deserializer" -> "org.apache.kafka.common.serialization.ByteArrayDeserializer",
      "group.id" -> group_id,
      "auto.offset.reset" -> "latest",
      "enable.auto.commit" -> (false: java.lang.Boolean)    
    )

    val topics = Array("ssp.requests")
    val stream = KafkaUtils.createDirectStream[String, Array[Byte]](
      ssc,
      PreferConsistent,
      Subscribe[String, Array[Byte]](topics, kafkaParams)
    )

    val events = stream
    val sqlContext = SQLContextSingleton.getInstance(sc)
    import sqlContext.implicits._

    events.foreachRDD(rdd=>{
      val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
      //val rdd2 = rdd.repartition(2)
      val current =   rdd.map(record => (record.key, message_proto(record.value)))

      val myDataFrame = current.toDF()    
      val query = myDataFrame.select(col("_2").as("value_udf"))
        .select(col("value_udf")("version").as("version"), col("value_udf")("adunit").as("adunit"), col("value_udf")("adunit_original").as("adunit_original"),
          col("value_udf")("brand").as("brand"), col("value_udf")("country").as("country"), col("value_udf")("device_connection_type").as("device_connection_type"),
          col("value_udf")("device_density").as("device_density"), col("value_udf")("device_height").as("device_height"),
          col("value_udf")("device_id").as("device_id"),  col("value_udf")("device_type").as("device_type"),  col("value_udf")("device_width").as("device_width"),
          col("value_udf")("domain").as("domain"),  col("value_udf")("endpoint").as("endpoint"), col("value_udf")("endpoint_type").as("endpoint_type"),
          col("value_udf")("endpoint_version").as("endpoint_version"),  col("value_udf")("external_dfp_id").as("external_dfp_id"),
          col("value_udf")("id_req").as("id_req"),  col("value_udf")("ip").as("ip"), col("value_udf")("lang").as("lang"),  col("value_udf")("lat").as("lat"),
          col("value_udf")("lon").as("lon"),  col("value_udf")("model").as("model"),  col("value_udf")("ncc").as("ncc"),  col("value_udf")("noc").as("noc"),
          col("value_udf")("non").as("non"), col("value_udf")("os").as("os"), col("value_udf")("osv").as("osv"), col("value_udf")("scc").as("scc"),
          col("value_udf")("sim_operator_code").as("sim_operator_code"),  col("value_udf")("size").as("size"),  col("value_udf")("soc").as("soc"),
          col("value_udf")("son").as("son"),  col("value_udf")("source").as("source"),  col("value_udf")("ts").as("ts").cast("timestamp"), col("value_udf")("user_agent").as("user_agent"),
          col("value_udf")("status").as("status"), col("value_udf")("delivery_network").as("delivery_network"),  col("value_udf")("delivery_time").as("delivery_time"),
          col("value_udf")("delivery_status").as("delivery_status"),  col("value_udf")("delivery_network_key").as("delivery_network_key"),
          col("value_udf")("delivery_price").as("delivery_price"),  col("value_udf")("device_id_original").as("device_id_original"),
          col("value_udf")("tracking_limited").as("tracking_limited"),  col("value_udf")("from_cache").as("from_cache"),
          date_format(col("value_udf")("ts"), "yyyy").as("date").as("year"),
          date_format(col("value_udf")("ts"), "MM").as("date").as("month"),
          date_format(col("value_udf")("ts"), "dd").as("date").as("day"),
          date_format(col("value_udf")("ts"), "HH").as("date").as("hour"))

      try {
        query.write.partitionBy("year", "month", "day", "hour")
          .mode(SaveMode.Append).parquet("s3a://tap-datalake/ssp.requests")
        events.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges)
      }catch{
        case e:Exception=>              
          print(e)
      }
    })

    ssc.start()

    ssc.awaitTermination()

    ssc.stop()

  }
}

Streaming Statistics

Completed Batches

Details for query

Executors

Environment

enter image description here

enter image description here

enter image description here

...