Spark Streaming应用
实验目的
深入理解和掌握Spark Stream中DStream无状态操作的方法;理解Spark Stream编程解决实际问题的方法。
实验要求
- 掌握基于Spark Stream的Scala和Spark SQL编程环境配置;
- 掌握Spark Stream中DStream无状态操作编程方法。
实验内容
- 参考实验二创建一个Spark项目
- 在Maven中配置Spark Streaming编程环境,pom.xml中添加:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.12</artifactId>
<version>3.0.1</version>
</dependency>
若自己安装的Spark不是3.0.1,则自己搜索适合的spark-streaming版本
- 将MyReceiver.scala添加到项目中
MyReceiver生成的流数据格式:每次生成num个元素(视构造方法传入的参数而定),每个元素均是为字符串,包含了3个100以内的随机数,每个随机数用空格隔开,例:
10 42 80
78 1 7
8 14 8
33 21 2
52 5 5
- 编写MyStreaming.scala中的main方法以实现流处理
(1) 创建SparkContext和StreamingContext,设置时间间隔为3秒(参见PPT第6章3.3)
val conf = new SparkConf()
conf.setAppName("名字")
val sc = new SparkContext(conf)
val ssc = new SteamingContext(sc, Seconds(3))
(2) 使用receiverStream方法定义输入源,采用自定义MyReceiver输入源:
//lines为输入源
val lines = ssc.receiverStream(new MyReceiver(5))
(3) 使用DStream的无状态转换算子,计算输入流lines中的数据;计算每个batch的所有数字的平均值
//对输入流lines应用DStream转换算子提示,ds为转换后的DStream
val ds = lines.map(x=>x.split(regx=" ").map(x=>x.toInt)).map(x=>x.sum/5)
(4) 使用foreachRDD存储输入流数据:
//遍历DStream的所有RDD
lines.foreachRDD(x => {
if(x.count() > 0) {
//使用RDD的saveAsTextFile存储RDD数据,存储目录以时间戳命名
x.saveAsTextFile("file:///root/rdds/rec" + new Date().getTime.toString)
}
})
(5) 使用foreachRDD存储计算后的流数据:参考第(4)步代码,存储目录设置为/root/result/rec……(省略号部分用时间戳代替))
(6) 设置运行过程中打印信息scc.print;使用scc.start启动spark streaming,并设置结束条件scc.awaitTermination
- 编译和执行:
按实验二中的方法编译打包并执行程序,Spark Streaming需要手动停止,执行一段时间后可按下ctrl+z强行停止 - 查看结果:
打开spark-shell,使用sc.textFile(“file:///root/rdds/") 读取所有保存的DSteam输入源数据并显示;使用sc.textFile("file:///root/result/”) 读取所有保存的计算结果数据并显示。(注意:路径后加*,表示提取所有子目录中的文件)
保存结果预览
代码
package cn.edu.swpu.scs
import java.util.Date
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Seconds, StreamingContext}
object Streaming{
//当Receiver启动时调用onStart方法
//一次启动写入到DStream的一个RDD的分区中
def main(args: Array[String]): Unit = {
// 创建SparkContext和StreamingContext,设置时间间隔为3秒
val conf = new SparkConf()
conf.setAppName("My Streaming")
val sc = new SparkContext(conf)
val ssc = new StreamingContext(sc, Seconds(3))
//使用receiverStream方法定义输入源
val lines = ssc.receiverStream(new MyReceiver(5))
// 计算每个batch的所有数字的平均值
val ds = lines.map(x=>x.split(" ").map(x=>x.toInt)).map(x=>x.sum/5)
// 使用foreachRDD存储输入流数据
lines.foreachRDD(x => {
if(x.count() > 0) {
// 使用RDD的saveAsTextFile存储RDD数据,存储目录以时间戳命名
x.saveAsTextFile("hdfs://主机名或ip地址:端口号/文件路径" + new Date().getTime.toString)
}
})
// 使用foreachRDD存储计算后的数据
ds.foreachRDD(x => {
if(x.count() > 0) {
// 使用RDD的saveAsTextFile存储RDD数据,存储目录以时间戳命名
x.saveAsTextFile("hdfs://主机名或ip地址:端口号/文件路径" + new Date().getTime.toString)
}
})
ds.print()
ssc.start()
ssc.awaitTermination()
}
}