Spark Streaming
Spark Streaming 概述
Spark Streaming 是什么
Spark Streaming 使得构建可扩展的容错流应用程序变得更加容易
Spark Streaming 无法实现真正的流式数据处理。使用了微批次数据处理。
Spark Streaming 是一个准实时数据处理引擎。
-
实时:数据处理的延迟在毫秒级进行响应
-
离线:数据处理的延迟在小时,天,月,年进行响应
-
批处理:数据处理的方式
-
流式:数据处理的方式
Spark Streaming 支持的数据输入源很多,例如:Kafka,Flume,Twitter,ZeroMQ和简单的TCP Socket等等。
数据输入后,可以用Spark的高度抽象原语进行运算,如map,reduce,join,window。
结果也能保存在很多地方,如HDFS,数据库等。
和Spark基于RDD的概念很相似,Spark Streaming使用离散化流(discretized stream)作为抽象表示,叫做DStream。
DStream是随时间推移而收到的数据的序列。在内部,每个时间区间收到的数据都作为RDD存在,而DStream是由这些RDD所组成的序列(因此得名"散列化")。所以简单来讲,DStream就是对RDD在实时数据处理场景的一种封装。
Spark Streaming 架构
架构图
-
整体架构图
-
Spark Streaming 架构图
背压机制
Spark 1.5以前版本,用户如果要限制Receiver的数据接收速率,可以通过设置静态配制参数“spark.streaming.receiver.maxRate”的值来实现,此举虽然可以通过限制接收速率,来适配当前的处理能力,防止内存溢出,但也会引入其它问题。比如:producer数据生产高于maxRate,当前集群处理能力也高于maxRate,这就会造成资源利用率下降等问题。
为了更好的协调数据接收速率与资源处理能力,1.5版本开始Spark Streaming可以动态控制数据接收速率来适配集群数据处理能力。背压机制(即Spark Streaming
Backpressure): 根据JobScheduler反馈作业的执行信息来动态调整Receiver数据接收率。
通过属性“spark.streaming.backpressure.enabled”来控制是否启用backpressure机制,默认值false,即不启用。
DStream 入门
WordCount案例实操
需求:使用netcat工具向9999端口不断的发送数据,通过SparkStreaming读取端口数据并统计不同单词出现的次数。
-
添加依赖
-
编写代码
def main(args: Array[String]): Unit = {
// 1.初始化Spark配置信息
// SparkStreaming使用核数最少是两个:driver,receiver
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkStreaming WordCount")
// 2.初始化SparkStreamingContext
// conf: SparkConf, batchDuration: Duration - 采集周期
val ssc = new StreamingContext(conf, Seconds(3))
// 3.通过监控端口创建DStream,读进来的数据为一行行
val lineStreams: ReceiverInputDStream[String] = ssc.socketTextStream("localhost", 9999)
// 将每一行数据做切分,形成一个个单词
val wordStreams: DStream[String] = lineStreams.flatMap(_.split(" "))
// 将单词映射成元组(word, 1)
val wordToOneStreams: DStream[(String, Int)] = wordStreams.map((_, 1))
// 将相同的单词次数做统计
val wordToCountStreams: DStream[(String, Int)] = wordToOneStreams.reduceByKey(_+_)
// 打印
wordToCountStreams.print()
// 启动SparkStreamingContext
ssc.start() // 启动采集器
ssc.awaitTermination() // 等待采集器的结束
}
- 启动程序并通过netcat发送数据
E:\DeveloperTools\netcat-win32-1.12>nc -lp 9999
dsy sarah dongsaiyuan
hello word
-------------------------------------------
Time: 1592056995000 ms
-------------------------------------------
(dongsaiyuan,1)
(dsy,1)
(sarah,1)
-------------------------------------------
Time: 1592056998000 ms
-------------------------------------------
(word,1)
(hello,1)
WordCount 解析
Discretized Stream 是 Spark Streaming 的基础抽象,代表持续性的数据流和经过各种Spark原语操作后的结果数据流。在内部实现上,DStream是一系列连续的RDD来表示。每个RDD含有一段时间间隔内的数据。
对数据的操作也是按照RDD为单位来进行的
计算过程由 Spark Engine 来完成
DStream 创建
RDD 队列
用法及说明
测试过程中,可以通过使用ssc.queueStream(queueOfRDDs)来创建DStream。
案例实操
- 需求:循环创建几个RDD,将RDD放入队列。通过Spark Streaming创建DStream,计算WordCount。
def main(args: Array[String]): Unit = {
// 1.初始化 Spark 配置信息
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD Stream")
// 2.初始化 SparkStreamingContext
val ssc = new StreamingContext(conf, Seconds(3))
// 3.创建 RDD 队列
val rddQueue = new mutable.Queue[RDD[Int]]()
// 4.创建 QueueInputDStream
val inputStream: InputDStream[Int] = ssc.queueStream(rddQueue, oneAtATime = false)
// 5.处理队列中的 RDD 数据
val mappedStream: DStream[(Int, Int)] = inputStream.map((_, 1))
val reducedStream: DStream[(Int, Int)] = mappedStream.reduceByKey(_+_)
// 6.打印结果
reducedStream.print()
// 7.启动任务
ssc.start()
// 8.循环创建并向 RDD 队列中放入 RDD
for(i <- 1 to 5) {
rddQueue += ssc.sparkContext.makeRDD(List(i))
Thread.sleep(1000)
}
ssc.awaitTermination()
}
-------------------------------------------
Time: 1592094957000 ms
-------------------------------------------
(1,1)
(2,1)
(3,1)
-------------------------------------------
Time: 1592094960000 ms
-------------------------------------------
(4,1)
(5,1)
自定义数据源
用法及说明
需要继承 Receiver,并实现 onStart,onStop 方法来自定义数据源采集
案例实操
需求:自定义数据源,实现监控某个端口号,获取该端口号内容
def main(args: Array[String]): Unit = {
// 1.初始化 Spark 配置信息
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("custom receiver")
// 2.初始化 SparkStreamingContext
val ssc = new StreamingContext(conf, Seconds(3))
// 3.创建自定义 receiver 的 Streaming
val lineStream: ReceiverInputDStream[String] = ssc.receiverStream(new CustomReceiver("localhost", 9999))
/