Spark Streaming执行流程分析

为了探索Spark Streaming的完整执行流程,我们先看下Spark源码项目examples模块里面提供的Spark Streaming案例:

org.apache.spark.examples.streaming.DirectKafkaWordCount

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// scalastyle:off println
package org.apache.spark.examples.streaming

import org.apache.kafka.clients.consumer.ConsumerConfig
import org.apache.kafka.common.serialization.StringDeserializer

import org.apache.spark.SparkConf
import org.apache.spark.streaming._
import org.apache.spark.streaming.kafka010._

/**
 * Consumes messages from one or more topics in Kafka and does wordcount.
 * Usage: DirectKafkaWordCount <brokers> <topics>
 *   <brokers> is a list of one or more Kafka brokers
 *   <groupId> is a consumer group name to consume from topics
 *   <topics> is a list of one or more kafka topics to consume from
 *
 * Example:
 *    $ bin/run-example streaming.DirectKafkaWordCount broker1-host:port,broker2-host:port \
 *    consumer-group topic1,topic2
 */
object DirectKafkaWordCount {
  def main(args: Array[String]) {
    if (args.length < 3) {
      System.err.println(s"""
        |Usage: DirectKafkaWordCount <brokers> <groupId> <topics>
        |  <brokers> is a list of one or more Kafka brokers
        |  <groupId> is a consumer group name to consume from topics
        |  <topics> is a list of one or more kafka topics to consume from
        |
        """.stripMargin)
      System.exit(1)
    }

    StreamingExamples.setStreamingLogLevels()

    val Array(brokers, groupId, topics) = args

    // Create context with 2 second batch interval
    val sparkConf = new SparkConf().setAppName("DirectKafkaWordCount")
    val ssc = new StreamingContext(sparkConf, Seconds(2))

    // Create direct kafka stream with brokers and topics
    val topicsSet = topics.split(",").toSet
    val kafkaParams = Map[String, Object](
      ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG -> brokers,
      ConsumerConfig.GROUP_ID_CONFIG -> groupId,
      ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG -> classOf[StringDeserializer],
      ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG -> classOf[StringDeserializer])
    val messages = KafkaUtils.createDirectStream[String, String](
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](topicsSet, kafkaParams))

    // Get the lines, split them into words, count the words and print
    val lines = messages.map(_.value)
    val words = lines.flatMap(_.split(" "))
    val wordCounts = words.map(x => (x, 1L)).reduceByKey(_ + _)
    wordCounts.print()

    // Start the computation
    ssc.start()
    ssc.awaitTermination()
  }
}
// scalastyle:on println


分析这个案例,可以看到实现一个Spark Streaming流处理应用,一般有以下五个步骤:

  1.  初始化流处理上下文,即创建StreamingContext,作为流处理程序入口,这个过程中也在创建SparkContext这个Spark执行上下文;
  2.  创建输入流 Input DStreams;
  3. 对DStreams各种转换处理 Transformations,形成DStreams DAG;
  4. 执行Output Operations进行输出结果
  5. 启动StreamingContext,并等待终止

一、初始化StreamingContext

完整流程如下:

其中比较重要的是

  • SparkContext初始化,这个主要准备job执行的各种环境(网络通信、序列化反序列化、存储管理等等,需要专门去解读源码,这里暂时先不关心);
  • 构建JobScheduler对象,该对象使用JobGenerator对象生成jobs,然后将jobs调度执行;
  • 构建JobGenerator对象,该对象从DStreams中或者Checkpointing中生成jobs,同时负责清理DStreams元数据。

二、创建输入流InputDStreams

StreamingContext中提供了各种创建输入流的方法,包括创建ReceiverInputDStream、FileInputDStream等

 

InputDStream的相关方法进行说明,其重要的方法,包括继承于DStream的

1)`compute(validTime: Time): Option[RDD[T]]`

用于生成RDD

2)dependencies: List[DStream[_]]

DStream依赖,InputDStream作为输入,不存在依赖,因此重写了该方法,直接返回空集合:

`override def dependencies: List[DStream[_]] = List()`

3)generateJob(time: Time): Option[Job]

生成job,该方法主要调用getOrCompute生成RDD,然后创建job对象

4)getOrCompute(time: Time): Option[RDD[T]]

该方法调用compute方法生成RDD,并对RDD进行持久化和checkpoint操作

5)register
 

 /**
   * Register this streaming as an output stream. This would ensure that RDDs of this
   * DStream will be generated.
   */
  private[streaming] def register(): DStream[T] = {
    ssc.graph.addOutputStream(this)
    this
  }


将自己注册到DStreamGraph上,用于输出操作算子得到OutputDStream注册,比如ForEachDStream,其实就是放到DStreamGraph的outputStreams集合中

相应的InputDStream,在初始化创建的时候,就调用DStreamGraph的addInputStream方法将自己注册到DStreamGraph的inputStreams集合中


6)start()

启动接收数据的方法,InputDStream新增的抽象方法,由各个子类实现

/** Method called to start receiving data. Subclasses must implement this method. */
  def start(): Unit

7)stop()方法

停止接收数据方法

 /** Method called to stop receiving data. Subclasses must implement this method. */
  def stop(): Unit

三、DStreams Transformation

四、Output Operations On DStreams

 

五、启动StreamingContext并等待终止

以上四个步骤,主要是在初始化执行环境,然后构建DStreamGraph,并没有真正开始数据流处理,即使调用了输出操作。

Spark Streaming作业真正开始执行的地方是调用StreamingContext的start方法,所以我们需要重点解析该方法的源码:

 /**
   * Start the execution of the streams.
   *
   * @throws IllegalStateException if the StreamingContext is already stopped.
   */
  def start(): Unit = synchronized {
    state match {
      case INITIALIZED =>
        startSite.set(DStream.getCreationSite())
        StreamingContext.ACTIVATION_LOCK.synchronized {
          StreamingContext.assertNoOtherContextIsActive()
          try {
            validate()

            // Start the streaming scheduler in a new thread, so that thread local properties
            // like call sites and job groups can be reset without affecting those of the
            // current thread.
            ThreadUtils.runInNewThread("streaming-start") {
              sparkContext.setCallSite(startSite.get)
              sparkContext.clearJobGroup()
              sparkContext.setLocalProperty(SparkContext.SPARK_JOB_INTERRUPT_ON_CANCEL, "false")
              savedProperties.set(SerializationUtils.clone(sparkContext.localProperties.get()))
              scheduler.start()
            }
            state = StreamingContextState.ACTIVE
            scheduler.listenerBus.post(
              StreamingListenerStreamingStarted(System.currentTimeMillis()))
          } catch {
            case NonFatal(e) =>
              logError("Error starting the context, marking it as stopped", e)
              scheduler.stop(false)
              state = StreamingContextState.STOPPED
              throw e
          }
          StreamingContext.setActiveContext(this)
        }
        logDebug("Adding shutdown hook") // force eager creation of logger
        shutdownHookRef = ShutdownHookManager.addShutdownHook(
          StreamingContext.SHUTDOWN_HOOK_PRIORITY)(() => stopOnShutdown())
        // Registering Streaming Metrics at the start of the StreamingContext
        assert(env.metricsSystem != null)
        env.metricsSystem.registerSource(streamingSource)
        uiTab.foreach(_.attach())
        logInfo("StreamingContext started")
      case ACTIVE =>
        logWarning("StreamingContext has already been started")
      case STOPPED =>
        throw new IllegalStateException("StreamingContext has already been stopped")
    }
  }

整个流程如下:

StreamingContext --> JobScheduler --> JobGenerator --> DStreamGraph --> SparkContext.runJob

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Spark Streaming 执行流程如下: 1. 数据源输入:Spark Streaming 支持多种数据源输入,包括 Kafka、Flume、HDFS、Socket 等。 2. 数据切分:Spark Streaming 将输入的数据流按照时间间隔切分成一系列的小批次数据。 3. 数据处理:对每个小批次数据进行处理,可以使用 Spark 的各种 API 进行数据转换、过滤、聚合等操作。 4. 数据输出:将处理后的数据输出到各种存储系统,如 HDFS、数据库、Kafka 等。 5. 容错机制:Spark Streaming 具有容错机制,可以在节点故障时自动恢复。 6. 监控和管理:Spark Streaming 提供了丰富的监控和管理工具,可以实时监控应用程序的运行状态,进行调优和管理。 ### 回答2: Spark Streaming是一个实时处理框架,它可以从数据源中获取实时数据,并将其实时处理成有意义的结果。Spark Streaming框架的执行流程一般可以分为四个步骤,包括数据源接入、数据分析、数据处理和生成结果。 首先,Spark Streaming需要从数据源中获取实时数据,数据源可以是文件系统、Kafka、Flume、Twitter等不同的来源。当数据源接入之后,Spark Streaming会将数据流分成若干个批次,每个批次时间间隔由用户自定义。每个批次中的数据会被收集到一个RDD中。 接着,Spark Streaming将收集到的数据流转换成DStream,然后进行数据分析。这个步骤是执行实时数据处理任务的关键步骤。Spark Streaming提供了许多支持数据分析的API,例如map、filter、reduce、count等API,可以根据合适的API函数对DStream中的数据进行操作和处理。 接下来是数据处理的步骤,数据处理通常包括数据清洗、数据过滤、特征提取、模型训练等,Spark Streaming可以使用Spark的多个API实现这些数据处理任务。例如,可以使用Spark SQL通过Spark Streaming操作一个表来进行数据清洗和数据过滤。 最后一步是生成结果,Spark Streaming通过foreachRDD API将处理好的数据输出到指定的存储系统,如HDFS、Kafka等。此外,还可以使用Spark Streaming提供的一些可视化工具来监控处理结果。 综上所述,Spark Streaming执行流程具体如下:数据源接入、数据分析、数据处理和生成结果。这个流程可以帮助用户实现准实时、高性能的流式数据处理应用程序。 ### 回答3: Spark StreamingSpark 提供的一种对流式数据进行处理的框架,它提供了一种高级别抽象(Discretized Stream或DStream),使用户可以像处理静态数据一样轻松处理连续的数据流。Spark Streaming执行流程可以分为以下几个步骤: 1.数据输入:Spark Streaming 支持多种数据输入源,包括 Kafka、Flume、Twitter、Hadoop 文件系统等。Spark Streaming 的输入源机制提供了容错机制,保证了在数据流处理过程中的数据丢失的最小程度。输入的数据被 Spark Streaming 原始分散到多个节点上,这些节点构成了 StreamingContext。 2.数据转换:在原始数据被分散到各个节点上后,Spark Streaming 将它们按照一定时间间隔分成一个个小的批次(batch),并将这些批次转换成一个个 RDD。这个过程被称为 DStream 的生成。DStream 可以看做是一系列时间片(RDD)的集合。这个过程的用户代码通常是使用 Spark Streaming 提供的高级别接口(如map、flatMap 等)编写的。 3.数据处理:Spark Streaming 提供了一系列转换算子,如 map、window、reduceByKeyAndWindow、updateStateByKey 等,用来对 DStream 进行各种转换操作,进行数据处理并产生一个新的 DStream。数据处理这一步的用户代码通常是使用这些算子来实现的。 4.数据输出:经过转换后的结果 RDD 可以通过 Spark Streaming操作输出(直接存储到 Hadoop 文件系统、数据库等)、打印、对外部系统发送 HTTP 请求、写到 Kafka、发送邮件等多种方式输出。用户代码通常使用 Spark Streaming 内置的输出算子(如 saveAsTextFiles、foreachRDD 等)来实现。 这些步骤是在整个程序执行周期中不断重复的,直到接收数据源的数据结束。Spark Streaming 的程序执行过程是基于 Spark 引擎进行的,因此它拥有 Spark 处理批处理的所有优点,如高性能、易扩展、 容错性强,同时又可用于对流处理分析。 以上是 Spark Streaming 执行流程的简单介绍,通过以上几步 Spark Streaming 可以高效、稳定地处理海量实时数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值