Spark Streaming DStream 创建方式

1、通过RDD队列创建DStream

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

创建方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def main(args: Array[String]): Unit = {
  val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkStreaing")
  //StreamingContext 两个参数 sparkConf 配置文件 Seconds(3) 微批采集周期
  val ssc = new StreamingContext(sparkConf, Seconds(3))
  //声明队列
  val rddQueue = new mutable.Queue[RDD[Int]]()
  //ssc.queueStream(rddQueue, oneAtATime = false) oneAtATime 一个采集周期只出现一次,默认 true
  val inputSream: InputDStream[Int] = ssc.queueStream(rddQueue, oneAtATime = false)
  val mapStream: DStream[(Int, Int)] = inputSream.map((_, 1))
  val reduceStream: DStream[(Int, Int)] = mapStream.reduceByKey(_ + _)
  reduceStream.print()
 
  // 启动采集器
  ssc.start()
  for (i <- 1 to 5) {
    // 放数据到 队列
    rddQueue += ssc.sparkContext.makeRDD(seq = 1 to 5, numSlices = 10)
    Thread.sleep(2000)
  }
  //等待采集器关闭
  ssc.awaitTermination()
}

执行效果

复制代码
-------------------------------------------
Time: 1650099129000 ms
-------------------------------------------
(4,2)
(1,2)
(5,2)
(2,2)
(3,2)

-------------------------------------------
Time: 1650099132000 ms
-------------------------------------------
(4,1)
(1,1)
(5,1)
(2,1)
(3,1)

-------------------------------------------
Time: 1650099135000 ms
-------------------------------------------
(4,2)
(1,2)
(5,2)
(2,2)
(3,2)
复制代码

2、自定义数据源

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

实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def main(args: Array[String]): Unit = {
  val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkStreaing")
  //StreamingContext 两个参数 sparkConf 配置文件 Seconds(3) 微批采集周期
  val ssc = new StreamingContext(sparkConf, Seconds(3))
 
  val line: ReceiverInputDStream[String] = ssc.receiverStream(new myReceiver("hadoop103", 9999))
  line
    .flatMap(_.split(" "))
    .map((_, 1))
    .reduceByKey(_ + _)
    .print()
  // 启动采集器
  ssc.start()
 
  //等待采集器关闭
  ssc.awaitTermination()
}
 
/**
 * 自定义数据采集器
 * 1、继承 Receiver,定义泛型,传参数
 *
 */
private class myReceiver(host: String, port: Int) extends Receiver[String](StorageLevel.MEMORY_ONLY) {
  private var socket: Socket = _
 
  override def onStart(): Unit = {
    new Thread("socket Receiver") {
      setDaemon(true)
 
      override def run() {
        receiver()
      }
    }.start()
  }
 
  def receiver(): Unit = {
    try {
      //读取端口数据
      socket = new Socket(host, port)
      val bf: BufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream, StandardCharsets.UTF_8))
      //定义变量存储读取的数据
      var line: String = null
      while ((line = bf.readLine()) != null) {
        //缓存到内存 store() 是 Receiver 提供的方法
        store(line)
      }
    } catch {
      case e: ConnectException =>
        restart(s"Error connecting to $host:$port...", e)
        return
    }
  }
 
  override def onStop(): Unit = {
    synchronized {
      if (socket != null) {
        socket.close()
        socket = null
      }
    }
  }
}

3、Kafka 数据源

ReceiverAPI:需要一个专门的Executor去接收数据,然后发送给其他的Executor做计算。存在的问题,接收数据的Executor和计算的Executor速度会有所不同,特别在接收数据的Executor速度大于计算的Executor速度,会导致计算数据的节点内存溢出。DirectAPI:是由计算的Executor来主动消费Kafka的数据,速度由自身控制

实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def main(args: Array[String]): Unit = {
  val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkStreaing")
  //StreamingContext 两个参数 sparkConf 配置文件 Seconds(3) 微批采集周期
  val ssc: StreamingContext = new StreamingContext(sparkConf, Seconds(3))
 
  val kafkaPara: Map[String, Object] = Map[String, Object](
    ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG -> "hadoop103:9092,hadoop104:9092,hadoop105:9092", //kafka所在集群主机端口信息
    ConsumerConfig.GROUP_ID_CONFIG -> "hui", "key.deserializer" -> "org.apache.kafka.common.serialization.StringDeserializer", "value.deserializer" -> "org.apache.kafka.common.serialization.StringDeserializer")
  //从 kafka 读取数据
  val kfkDataDS: InputDStream[ConsumerRecord[String, String]] = KafkaUtils.createDirectStream[String, String](
    ssc, //ssc 上下文环境对象
    LocationStrategies.PreferConsistent, //LocationStrategies 位置策略 PreferConsistent 采集节点和计算节点自己控制
    ConsumerStrategies.Subscribe[String, String](Set("tbg"), //ConsumerStrategies 消费策略  tbg kafka topic
      kafkaPara //kafka主题 kafkaPara kafka配置
    ))
  kfkDataDS
    .flatMap(_.value().split(" "))
    .map((_, 1))
    .reduceByKey(_ + _)
    .print()
 
 
  /**
   bin/kafka-topics.sh --bootstrap-server hadoop103:9092 --list
   bin/kafka-console-producer.sh --bootstrap-server hadoop103:9092 --topic tbg
   **/
  // 启动采集器
  ssc.start()
 
  //等待采集器关闭
  ssc.awaitTermination()
}
posted @   晓枫的春天  阅读(129)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示