09 DStream 的创建

DStream 的创建

1. 文件输入源

1.1 注意事项

  1. 监控的⽂件夹内的所有⽂件必须有相同的数据集格式 。
  2. 监控的⽬录下创建的⽂件必须是移动或者重命名得到的,如果修改已经存在的⽂件的内容则⽆法被监控到。
  3. ⼀旦⽂件创建成功, 则不能去更改,所以, 如果在⽂件内追加内容, 追加的数据是不能被 Spark Streaming 读到的。
  4. streamingContext.textFileStream(dataDirectory) 可以专⻔⽤来读取⽂本⽂件。

1.2 读取 HDFS 目录下的文件

  1. HDFS 上创建目录 /DStreamInput

  2. 在该目录下创建多个文本文件,在文件内添加一些文本内容。

  3. 编写代码:

    import org.apache.spark.SparkConf
    import org.apache.spark.streaming.dstream.DStream
    import org.apache.spark.streaming.{Seconds, StreamingContext}
    
    object HDFSFile {
      def main(args: Array[String]): Unit = {
        val conf = new SparkConf().setMaster("local[*]").setAppName("HDFSFile")
        // 1.创建 SparkStreaming 的入口对象
        val streamingContext = new StreamingContext(conf, Seconds(3))
        // 2.获取 HDFS 上的数据
        val input: DStream[String] = streamingContext.textFileStream("hdfs://hadoop101:9000/DStreamInput/")
        // 3.WordCount
        val output: DStream[(String, Int)] = input.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
        // 4.输出结果
        output.print()
        // 5.启动:开始接收数据并计算
        streamingContext.start()
        // 6.等待程序结束(手动退出 OR 出现异常)后退出主程序
        streamingContext.awaitTermination()
      }
    }
    

2. RDD 队列

  1. 可以通过使用 streamingContext.queueStream(queueOfRDDs) 创建 DStream ,每一个推送到这个队列中的 RDD ,都会作为一个 DStream 处理。

  2. 编写代码:

    import org.apache.spark.rdd.RDD
    import scala.collection.mutable
    import org.apache.spark.streaming.dstream.InputDStream
    import org.apache.spark.{SparkConf, SparkContext}
    import org.apache.spark.streaming.{Seconds, StreamingContext}
    
    
    object RDD2DStream {
      def main(args: Array[String]): Unit = {
        val conf: SparkConf = new SparkConf().setAppName("RDD2DStream").setMaster("local[*]")
        // 1.创建 streamingContext 的入口对象
        val streamingContext = new StreamingContext(conf, Seconds(3))
        // 2.获取 sparkContext,为后续创建 RDD 做准备
        val sparkContext: SparkContext = streamingContext.sparkContext
        // 3.创建可变队列
        val RDDQueue: mutable.Queue[RDD[Int]] = mutable.Queue[RDD[Int]]()
        // 4.获取DStream
        val input: InputDStream[Int] = streamingContext.queueStream(RDDQueue, false)
        // 5.输出结果
        input.print()
        // 6.启动
        streamingContext.start()
        // 7.创建 RDD 并入队
        for (i <- 1 to 5) {
          val rdd: RDD[Int] = sparkContext.makeRDD(Array(i))
          RDDQueue.enqueue(rdd)
        }
        // 8.等待程序结束(手动退出 OR 出现异常)后退出主程序
        streamingContext.awaitTermination()
      }
    }
    

3. 自定义数据源

  1. 需要继承 Receiver,并实现 onStart、onStop 方法来自定义数据源采集。

  2. 需求:自定义数据源,实现监控某个端口号,获取该端口号的内容。

  3. 编写代码:

    3.1 自定义数据源

    import java.io.{BufferedReader, InputStreamReader}
    import java.net.Socket
    import java.nio.charset.StandardCharsets
    import org.apache.spark.storage.StorageLevel
    import org.apache.spark.streaming.receiver.Receiver
    
    object MySource {
      def apply(host: String, port: Int): MySource = new MySource(host, port)
    }
    
    class MySource(host: String, port: Int) extends Receiver[String](StorageLevel.MEMORY_ONLY) {
    
      /*接收器启动的时候调⽤该⽅法,
      这个函数内部必须初始化⼀些读取数据必须的资源
      该⽅法不能阻塞,
      所以,读取数据要在⼀个新的线程中进⾏. */
      override def onStart(): Unit = {
    
        // 启动一个新的线程来接收数据
        new Thread("Socket Receiver") {
          override def run(): Unit = {
            receive()
          }
        }.start()
    
        // 此方法用来接收数据
        def receive() = {
          val socket = new Socket(host, port)
          val reader = new BufferedReader(new InputStreamReader(socket.getInputStream, StandardCharsets.UTF_8))
          var line: String = null
          // 当 receiver 没有关闭,且 reader 读到了数据则循环发送给 spark
          while (!isStopped() && (line = reader.readLine()) != null) {
            // 发送给 spark
            store(line)
          }
          // 循环结束,则关闭资源
          reader.close()
          socket.close()
    
          // 重启任务
          restart("trying to connect again")
        }
      }
    
      override def onStop(): Unit = {}
    }
    

    3.2 使用自定义数据源

    import org.apache.spark.SparkConf
    import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
    import org.apache.spark.streaming.{Seconds, StreamingContext}
    
    object MySourceDemo {
      def main(args: Array[String]): Unit = {
        val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("MySourceDemo")
        val streamingContext = new StreamingContext(conf, Seconds(5))
        val input: ReceiverInputDStream[String] = streamingContext.receiverStream(MySource("localhost", 9999))
        val output: DStream[(String, Int)] = input.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
        output.print()
        streamingContext.start()
        streamingContext.awaitTermination()
      }
    }
    

4. Kafka 数据源

  1. 需求:通过 Spark StreamingKafka 读取数据,并将读取到的数据做简单计算,最终打印结果。

  2. 导入依赖

    <dependency> 
      <groupId>org.apache.spark</groupId> 
      <artifactId>spark-streaming-kafka-0-8_2.11</artifactId> 
      <version>2.1.1</version> 
    </dependency>
    
  3. 编写代码

    import org.apache.spark.SparkConf
    import org.apache.spark.streaming.kafka.KafkaUtils
    import org.apache.spark.streaming.{Seconds, StreamingContext}
    import org.apache.spark.storage.StorageLevel
    import org.apache.spark.streaming.dstream.ReceiverInputDStream
    
    object Kafka2DStream {
      def main(args: Array[String]): Unit = {
    
        // 1. 连接kafka需要的⽤到的⼀些参数
        val zookeeper = "hadoop101:2181,hadoop102:2181,hadoop103:2181"
        val group = "spark"
        val topic = "first"
        val numThreads = 3
    
        // 2. 创建 StreamingContext
        val conf: SparkConf = new SparkConf().setAppName("Kafka2DStream").setMaster("local[*]")
        val streamingContext = new StreamingContext(conf, Seconds(5))
    
        // 3. 创建 DStream
        val input: ReceiverInputDStream[(String, String)] = KafkaUtils.createStream(streamingContext, zookeeper, group, Map(topic -> numThreads), StorageLevel.MEMORY_ONLY)
    
        // 4. 对 KafkaStream操作
        input.print()
    
        // 5. 启动
        streamingContext.start()
        streamingContext.awaitTermination()
      }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值