Githup项目LearningSpark代码讲解(七)

package streaming

import org.apache.spark.rdd.RDD
import org.apache.spark.streaming._
import org.apache.spark.{SparkConf, SparkContext}

import scala.collection.mutable

/**
  * 这个类讲解了一个Spark实现分布式队列的例子
  * @param sc
  * @param ssc
  */
class QueueMaker(sc: SparkContext, ssc:StreamingContext) {

  // 创建一个本地队列
  private val rddQueue = new mutable.Queue[RDD[Int]]()


  /**
    * 这里有一个不好理解的地方,一个本地的队列如何保存的分布式RDD.
    *
    * def queueStream[T: ClassTag](
    *     queue: Queue[RDD[T]],
    *     oneAtATime: Boolean = true
    *   ): InputDStream[T] = {
    *     queueStream(queue, oneAtATime, sc.makeRDD(Seq.empty[T], 1))
    * }
    *
    * 从源码开始看,他makeRDD的时候写死了1个分区,所以没有分布式的问题,所以不存在分布式队列问题
    */
  val inputStream = ssc.queueStream(rddQueue)

  private var base = 1

  // 创建RDD
  private def makeRDD() : RDD[Int] = {
    val rdd = sc.parallelize(base to base + 99 , 4)
    base = base + 100
    rdd
  }


  def populateQueue() : Unit = {
    for (n <- 1 to 10) {
      // 在队列里加入10个RDD
      rddQueue.enqueue(makeRDD())
    }
  }
}

/**
  * 基于队列的流式处理为每个批发送单个队列条目的数据,即使许多条目已经提前排队。
  * 请注意,在本例中,队列已经预先填充了10个条目,并且每秒发出一个条目。
  */

object QueueBasedStreaming {
  def main (args: Array[String]) {
    val conf = new SparkConf().setAppName("QueueBasedStreaming").setMaster("local[4]")
    val sc = new SparkContext(conf)

    // streams will produce data every second
    val ssc = new StreamingContext(sc, Seconds(1))
    val qm = new QueueMaker(sc, ssc)

    // 创建一个stream
    val stream = qm.inputStream

    // 打印每个rdd的总数
    stream.foreachRDD(r => {
      println(r.count())
    })

    /**
      * 启动Spark Streaming,启动Spark Streaming时,在新线程中启动流调度程序,
      * 以便可以重置线程本地属性(如调用站点和作业组),而不影响当前线程的属性。
      *
      *
      */


    ssc.start()

    new Thread("Streaming Termination Monitor") {
      override def run() {
        try {
          /**
            * 一直运行,除非人为干预再停止,网上对这个方法基本没有什么讲解,都感觉是很顺其自然的需要写,
            * 这个是错误的,在例子中ssc.awaitTermination()有没有对系统其实毫无影响。
            * ssc.awaitTermination()的主要功能其实是给用户提供一个关闭sparkstream的方式
            *
            * streamingcontext.waittermination()-->当它接收到来自用户的信号(如ctrl+c或sigterm)时,它的流上下文将停止。
            * 它类似于java中的 shutdownhook
            *
            * streamingContext.stop他回立刻停止Spark,他可以控制是否停止streamingContext,设置可以只停止streamingContext
            *
            */
          ssc.awaitTermination()
        } catch {
          case e: Exception => {
            println("*** streaming exception caught in monitor thread")
            e.printStackTrace()
          }
        }
        println("*** streaming terminated")
      }
    }.start()

    println("*** started termination monitor")

    println("*** producing data")
    // start producing data
    qm.populateQueue()

    Thread.sleep(15000)

    println("*** stopping streaming")

    /**
      *  ssc.stop(false)只停止streamingContext而不停止sparkContext
      */
    ssc.stop()

    // wait a bit longer for the call to awaitTermination() to return
    Thread.sleep(5000)

    println("*** done")
  }
}

你可能感兴趣的:(Spark)