一、 Spark Streaming的概念
Spark Streaming是专门用来处理实时数据的计算框架,而Spark Streaming处理实时数据主要借助于一个核心数据抽象DStream,DStream本质上是由时间片段组成的一个离散化流式数据
Spark Streaming的程序执行入口为StreamingContext
二、 Spark Streaming的创建
1、 创建方式
- 借助SparkConf对象创建 — 默认底层自动创建一个SparkContext
- 借助已经创建好的SparkContext对象来创建
object Demo01 {
def main(args: Array[String]): Unit = {
/**
* 1、 从sparkConf创建 这种创建方式底层会给我们自动创建一个sparkContext
* 需要传递两个值 sparkconf以及一个Durations时间
* seconds(long)
* milliseconds(long)
* minutes(long)
*/
val sparkConf = new SparkConf().setMaster("local").setAppName("demo01")
val context = new StreamingContext(sparkConf, Seconds(5))
/**
* 2、 自己手动创建SparkContext 同样也需要传入两个值,一个sparkconf 一个时间
*/
val sparkContext = new SparkContext(sparkConf)
val streamingContext = new StreamingContext(sparkContext, Seconds(5))
}
}
2、 注意
1、 Spark Streaming严格意义上属于准实时框架,因为Spark Streaming处理数据时是按照时间来封装一批数据来进行处理,按照固定的时间来处理一批批数据,而这个时间取决于StreamingContext中设定的时间
2、 创建StreamingContext时必须指定运行模式的CPU核数大于等于二,因为它在计算时,最少需要两个线程,一个用来接收数据源的数据,一个用来处理封装好的一批次的数据
3、 在源数据启动后,不能够在源数据中添加任何操作
3、 StreamingContext支持的数据源
- TCP网络端口(Socket)
object Demo02 {
def main(args: Array[String]): Unit = {
/**
* 读取网络端口数据
*/
val sparkConf = new SparkConf().setAppName("socket").setMaster("local[2]")
val context = new StreamingContext(sparkConf, Seconds(5))
/**
* 读取网络端口的数据成为Dstream
*/
val dstream = context.socketTextStream("node1", 44444, StorageLevel.MEMORY_ONLY)
dstream.print()
/**
* 实时计算的程序必须手动启动
*/
context.start()
context.awaitTermination()
}
}
- HDFS分布式文件系统
注意:如果在目录下有历史数据,这些数据不会参与运算
object Demo04 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("demo04").setMaster("local[2]")
val context = new StreamingContext(conf, Seconds(20))
val ds = context.textFileStream("hdfs://node1:9000/stream")
ds.print()
context.start()
context.awaitTermination()
}
}
- 整合Flume实现实时计算
1、 推送式:将Flume采集的数据主动推送给Spark程序,这样的话容易导致Spark程序接受数据出问题,推送式整合是基于avro端口下沉底方式完成
2、拉取式:将Flume采集的数据发送给sink了,sink并不是直接把数据立马给了Spark,而是先把数据缓冲,Spark接收器可以按照我的需求主动去sink中拉取数据,拉取式整合方式是基于Spark下沉地完成----建议大家使用
object Demo05 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("demo05").setMaster("local[2]")
val context = new StreamingContext(conf, Seconds(20))
val ds:DStream[SparkFlumeEvent] = FlumeUtils.createStream(context, "node1", 8888, StorageLevel.MEMORY_ONLY)
ds.print()
context.start()
context.awaitTermination()
}
}
- 整合Kafka实现实时计算
4、 相关算子操作
1、 转换算子
- RDD支持的转换算子,DStream大部分支持
- 特殊转换算子 —transform(允许我们对DStream中的RDD直接操作)
object Demo07 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("demo07").setMaster("local[2]")
val context = new StreamingContext(conf, Seconds(20))
val ds = context.socketTextStream("node1", 44444, StorageLevel.MEMORY_ONLY)
val rdd = ds.transform((rdd: RDD[String]) => {
val value = rdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
value
})
rdd.print()
context.start()
context.awaitTermination()
}
}
- 有状态的转换算子updateStateByKey
object Demo08 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("demo07").setMaster("local[2]")
val context = new StreamingContext(conf, Seconds(20))
//可以缓存中间计算结果的DStream,用来存储有状态算子的批次结果
context.checkpoint("hdfs://node1:9000/sparkstreaming")
val ds = context.socketTextStream("node1", 44444, StorageLevel.MEMORY_ONLY)
val rdd = ds.transform((rdd: RDD[String]) => {
val value = rdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
value
})
/**
* array:Seq[Int] 当前批次中相同key对应的value结果
* stat:Option[Int] 以前批次相同key对应的value结果
*/
val value = rdd.updateStateByKey((array: Seq[Int], stat: Option[Int]) => {
//以前积攒的状态值
var i = stat.getOrElse(0)
for (elem <- array) {
i += elem
}
Option(i)
})
}
}
- 窗口函数 window
countByWindow 对每个滑动窗口的数据执行count操作
reduceByWindow 对每个滑动窗口的数据执行reduce操作
reduceByKeyAndWindow 对每个滑动窗口的数据执行reduceByKey操作
countByValueAndWindow 对每个滑动窗口的数据执行countByValue操作
同时需要传入两个参数
windowDuration: Duration, 窗口时间长度--一般是batchSize(批次时间)的整数倍
slideDuration: Duration: 滑动时间长度----一般是batchSize(批次时间)的整数倍
2、 行动算子
- print(num) 显示DStream当前批次的前num条数据,如果num没有传递,那默认显示前十条
- saveAsTextFile(用来保存数据的)
- saveAsObjectFile(同样用来保存数据的)
- foreachRDD算子:我们可以在foreachRDD算子中,实现对DStream每一批次RDD数据保存操作,保存到数据库、保存到结构化文件中等等,通过还可以在foreachRDD算子中将RDD转换为DataFrame或者Dataset实现结构化数据SQL处理操作