一、DStream 的创建
1. 通过 RDD 队列
DStream 在内部实现上是一系列连续的 RDD 来表示。每个 RDD 包含有采集周期内的数据
/**
基本语法:StreamingContext.queueStream(queueOfRDDs: Queue, oneAtATime = false)
*/
object DStreamFromRddQueue {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[*]").setAppName("ds")
val ssc = new StreamingContext(conf, Seconds(3))
val queueOfRdds = mutable.Queue[RDD[Int]]()
val ds = ssc.queueStream(queueOfRdds, oneAtATime = false)
ds.print()
ssc.start()
// 向 RDD 队列中添加元素
for(i <- 1 to 5) {
queueOfRdds += ssc.sparkContext.makeRDD(1 to 300, 10)
Thread.sleep(2000)
}
ssc.awaitTermination()
}
}
2. 通过自定义数据源
通过继承 Receiver 抽象类,并实现 onStart、onStop 方法来自定义数据源采集
/**
实现步骤:
1.继承 Receiver[T]() 抽象类,定义泛型,并传递参数
1.1 泛型是采集的数据类型
1.2 传递的参数是存储级别,StorageLevel 中的枚举值
2.实现 onStart、onStop 方法
3.使用 receiverStream(receiver) 创建 DStream
*/
object DStreamFromDiy {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[*]").setAppName("ds")
val ssc = new StreamingContext(conf, Seconds(3))
// 使用自定义数据源采集数据
val ds: ReceiverInputDStream[String] = ssc.receiverStream(new MyReceiver())
ds.print()
ssc.start()
ssc.awaitTermination()
}
}
// 自定义数据源采集
class MyReceiver extends Receiver[String](StorageLevel.MEMORY_ONLY) {
private val flag = true
// 当 ssc.start() 调用后,启动一个独立的线程去采集数据
override def onStart(): Unit = {
new Thread(new Runnable(){
override def run() {
while(flag) {
val data = "数据为:" + new Random().nextInt(10)
// 将数据存储封装为 DStream
store(data)
Thread.sleep(500)
}
}
}, "receiver").start()
}
// 停止数据采集
override def onStop(): Unit = {
flag = false
}
}
3. 通过 Kafka 数据源
3.1 版本选型
- ReceiverAPI:需要一个专门的 Executor 去接收数据,然后发送给其他的 Executor 做计算。所以当接收数据的 Executor 和计算的 Executor 速度不同时,特别在接收数据的 Executor 速度大于计算的 Executor 速度时,会导致计算数据的节点内存溢出。(早期版本中提供此方式,当前版本不适用)
- DirectAPI:是由计算的 Executor 来主动接收消费 Kafka 的数据,速度由自身控制
3.2 实现
-
引入依赖
<dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming-kafka-0-10_2.12</artifactId> <version>3.0.0</version> </dependency>