Apache spark 试图理解火花流

Apache spark 试图理解火花流,apache-spark,Apache Spark,我有一段代码: val lines: org.apache.spark.streaming.dstream.InputDStream[(String, String)] = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder]( ssc, kafkaParams, topics) lines.foreachRDD { rdd => val df = cassan

我有一段代码:

val lines: org.apache.spark.streaming.dstream.InputDStream[(String, String)] = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](
      ssc, kafkaParams, topics)
    lines.foreachRDD { rdd =>
      val df = cassandraSQLContext.read.json(rdd.map(x => x._2))
      sparkStreamingService.run(df)
    }
    ssc.start()
    ssc.awaitTermination()
据我所知,foreachRDD是在驱动程序级别发生的?所以基本上所有的代码块:

lines.foreachRDD { rdd =>
  val df = cassandraSQLContext.read.json(rdd.map(x => x._2))
  sparkStreamingService.run(df)
}
是在驾驶员级别发生的吗?sparkStreamingService.run(df)方法基本上对当前数据帧进行一些转换,以生成一个新的数据帧,然后调用另一个方法(在另一个jar上),该方法将数据帧存储到cassandra。 因此,如果这一切都发生在驱动程序级别,那么我们没有使用spark执行器,我如何才能使执行器被并行使用来并行处理RDD的每个分区

我的spark流媒体服务运行方法:

    var metadataDataframe = df.select("customer", "tableName", "messageContent", "initialLoadRunning").collect()
 metadataDataframe.foreach(rowD => {
      metaData = populateMetaDataService.populateSiteMetaData(rowD)
      val headers = (rowD.getString(2).split(recordDelimiter)(0))

      val fields = headers.split("\u0001").map(
        fieldName => StructField(fieldName, StringType, nullable = true))
      val schema = StructType(fields)

      val listOfRawData = rowD.getString(2).indexOf(recordDelimiter)
      val dataWithoutHeaders = rowD.getString(2).substring(listOfRawData + 1)

      val rawData = sparkContext.parallelize(dataWithoutHeaders.split(recordDelimiter))
//      val rawData = dataWithoutHeaders.split(recordDelimiter)
      val rowRDD = rawData
        .map(_.split("\u0001"))
        .map(attributes => Row(attributes: _*))

      val newDF = cassandraSQLContext.createDataFrame(rowRDD, schema)
      dataFrameFilterService.processBasedOnOpType(metaData, newDF)
    })

foreachRDD
可以在本地运行,但这仅仅意味着设置。RDD本身是一个分布式集合,因此实际工作是分布式的

要直接对文档中的代码进行注释:

dstream.foreachRDD { rdd =>
  val connection = createNewConnection()  // executed at the driver
  rdd.foreach { record =>
    connection.send(record) // executed at the worker
  }
}
注意,代码中不基于RDD的部分是在驱动程序中执行的。它是使用RDD构建的代码,分发给工作人员

您的代码注释如下:

   //df.select will be distributed, but collect will pull it all back in
   var metadataDataframe = df.select("customer", "tableName", "messageContent", "initialLoadRunning").collect()
 //Since collect created a local collection then this is done on the driver
 metadataDataframe.foreach(rowD => {
      metaData = populateMetaDataService.populateSiteMetaData(rowD)
      val headers = (rowD.getString(2).split(recordDelimiter)(0))

      val fields = headers.split("\u0001").map(
        fieldName => StructField(fieldName, StringType, nullable = true))
      val schema = StructType(fields)

      val listOfRawData = rowD.getString(2).indexOf(recordDelimiter)
      val dataWithoutHeaders = rowD.getString(2).substring(listOfRawData + 1)

      //This will run locally, creating a distributed record
      val rawData = sparkContext.parallelize(dataWithoutHeaders.split(recordDelimiter))
//      val rawData = dataWithoutHeaders.split(recordDelimiter)
      //This will redistribute the work
      val rowRDD = rawData
        .map(_.split("\u0001"))
        .map(attributes => Row(attributes: _*))
      //again, setting this up locally, to be run distributed
      val newDF = cassandraSQLContext.createDataFrame(rowRDD, schema)
      dataFrameFilterService.processBasedOnOpType(metaData, newDF)
    })

最终,您可能可以将其重写为不需要collect并将其全部分发,但这对于您来说不是StackOverflow,
foreachRDD
可以在本地运行,但这只意味着安装。RDD本身是一个分布式集合,因此实际工作是分布式的

要直接对文档中的代码进行注释:

dstream.foreachRDD { rdd =>
  val connection = createNewConnection()  // executed at the driver
  rdd.foreach { record =>
    connection.send(record) // executed at the worker
  }
}
注意,代码中不基于RDD的部分是在驱动程序中执行的。它是使用RDD构建的代码,分发给工作人员

您的代码注释如下:

   //df.select will be distributed, but collect will pull it all back in
   var metadataDataframe = df.select("customer", "tableName", "messageContent", "initialLoadRunning").collect()
 //Since collect created a local collection then this is done on the driver
 metadataDataframe.foreach(rowD => {
      metaData = populateMetaDataService.populateSiteMetaData(rowD)
      val headers = (rowD.getString(2).split(recordDelimiter)(0))

      val fields = headers.split("\u0001").map(
        fieldName => StructField(fieldName, StringType, nullable = true))
      val schema = StructType(fields)

      val listOfRawData = rowD.getString(2).indexOf(recordDelimiter)
      val dataWithoutHeaders = rowD.getString(2).substring(listOfRawData + 1)

      //This will run locally, creating a distributed record
      val rawData = sparkContext.parallelize(dataWithoutHeaders.split(recordDelimiter))
//      val rawData = dataWithoutHeaders.split(recordDelimiter)
      //This will redistribute the work
      val rowRDD = rawData
        .map(_.split("\u0001"))
        .map(attributes => Row(attributes: _*))
      //again, setting this up locally, to be run distributed
      val newDF = cassandraSQLContext.createDataFrame(rowRDD, schema)
      dataFrameFilterService.processBasedOnOpType(metaData, newDF)
    })

最终,您可能可以将其重写为不需要collect并将其全部分发,但对于您来说,这不是StackOverflow,
foreachRDD的调用确实发生在驱动程序节点上。但是,由于我们是在RDD级别上运行的,因此它上的任何转换都是分布式的。在您的示例中,
rdd.map
将导致每个分区被发送到特定的工作节点进行计算


由于我们不知道您的
sparkStreamingService.run
方法在做什么,我们无法告诉您其执行的位置

foreachRDD的调用确实发生在驱动程序节点上。但是,由于我们是在RDD级别上运行的,因此它上的任何转换都是分布式的。在您的示例中,
rdd.map
将导致每个分区被发送到特定的工作节点进行计算


由于我们不知道您的
sparkStreamingService.run
方法在做什么,我们无法告诉您其执行的位置

但是在这里:,如果你向下滚动到他们使用forEachRdd的地方,他们会有一条评论说某个特定的语句正在执行driver@Ahmed我编辑它是为了直接解决这个问题,添加了比文档更明确的内容,所以这就是我的问题,关于收集。到目前为止,由于我正在收集,记录会按顺序处理,然后将每个记录分发给执行人?然后删除collect,所有的记录都是并行处理而不是顺序处理的,对吗?还有一个问题Justin,这基本上是一个数据帧中的数据帧,我在这里做的。第二个数据帧是否也分布在执行者之间?我知道第一个数据帧是在执行器之间进行分区的,然后从数据帧的这些分区中,我正在创建另一个数据帧,只有创建内部数据帧的执行器才会拥有该数据帧,或者也会对其进行分区,他们有一条评论说,某个特定的语句正在执行driver@Ahmed我编辑它是为了直接解决这个问题,添加了比文档更明确的内容,所以这就是我的问题,关于收集。到目前为止,由于我正在收集,记录会按顺序处理,然后将每个记录分发给执行人?然后删除collect,所有的记录都是并行处理而不是顺序处理的,对吗?还有一个问题Justin,这基本上是一个数据帧中的数据帧,我在这里做的。第二个数据帧是否也分布在执行者之间?我知道第一个数据帧是在执行器之间进行分区的,然后从数据帧的这些分区中,我正在创建另一个数据帧,只有创建内部数据帧的执行器才会拥有该数据帧,或者也会对其进行分区。我为run方法添加了代码。这是最有效的方法吗?这个方法被并行化了:dataFrameFilterService.processBasedOnOpType(元数据,newDF)。我的理解是,我可以避免使用collect来加速进程,从而并行处理记录?我为run方法添加了代码。这是最有效的方法吗?这个方法被并行化了:dataFrameFilterService.processBasedOnOpType(元数据,newDF)。我的理解是,我可以避免使用collect来加快处理过程,以便并行处理记录?