目录
核心概念
SparkStreaming可以简单的理解为 StreamingContext将数据按照时间分为很多小的RDD,然后再交给Spark处理这一个个的RDD。
DStream
对DStream做操作,其实质就是对一系列的RDD做相同的操作。
Receiver
每一个inputDStream【除了文件流】 关联一个 Receiver对象【负责接受源头的数据并存储在spark的内存中】
注意:Receiver启动会占用一个线程,所以这时候不能使用master("local[1]")
Transformation
map(func)、filter(func)、flatMap(func)、reductByKey(func, [numTasks])
注意:流式计算中,reduce(func)、count()都是Transformation,统计出source DStream中的每个微批RDD的聚合结果和个数。
Output Operation
IDEA搭建SparkStreaming环境的pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kylin.sparkstreaming</groupId>
<artifactId>sparkstreaming</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spark.version>2.2.3</spark.version>
<scala.version>2.11</scala.version>
<hadoop.version>2.7.6</hadoop.version>
<hbase.version>1.4.8</hbase.version>
<kafka.version>1.1.1</kafka.version>
</properties>
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.12</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>${hbase.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>${hbase.version}</version>
</dependency>
<!-- 从此文档获取:http://spark.apache.org/docs/2.2.3/streaming-programming-guide.html -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-8_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.apache.spark</groupId>-->
<!--<artifactId>spark-mllib_${scala.version}</artifactId>-->
<!--<version>${spark.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<version>${kafka.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<!-- maven官方 http://repo1.maven.org/maven2/ 或 http://repo2.maven.org/maven2/ (延迟低一些) -->
<repositories>
<repository>
<id>central</id>
<name>Maven Repository Switchboard</name>
<layout>default</layout>
<url>http://repo2.maven.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<!--maven scala插件-->
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- MAVEN 编译使用的JDK版本 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
测试代码如下:
object FileWordCount {
def main(args: Array[String]): Unit = {
// 必须使用流的形式,才能读取到文件内容,如果windows下直接拷贝粘贴是不行的
// cp 123.txt data/ 而且对同一个文件修改也是不会再次被读取到的
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("file_word_count")
val ssc = new StreamingContext(sparkConf, Seconds(5))
val lines = ssc.textFileStream("file:///G:\\data\\")
val result = lines.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
result.print()
ssc.start()
ssc.awaitTermination()
}
}
带状态的算子:UpdateStateByKey
需求:统计到目前为止累计出现的单词数量。
注意:
- updateStateByKey算子需要传入一个函数【输入:当前值、以前值 】
- 以前的状态必须存放在checkpoint指定的路径。
object StatefulFileWordCount {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("file_word_count")
val ssc = new StreamingContext(sparkConf, Seconds(5))
// 如果使用了带状态的算子,必须设置checkpoint存放以前的状态
ssc.checkpoint(".")
val lines = ssc.textFileStream("file:///G:/data")
val result = lines.flatMap(_.split(" ")).map((_, 1))
val state = result.updateStateByKey(updateFunction _) // 隐式转换
state.print()
ssc.start()
ssc.awaitTermination()
}
def updateFunction(currentValues: Seq[Int], preValues: Option[Int]):Option[Int] = {
val current = currentValues.sum
val pre = preValues.getOrElse(0)
Some(current + pre)
}
}
进阶:将单词数量统计写入MySQL中
思路:使用 foreachRDD算子,
基于window的统计
window:进行一个时间段内的数据处理。 与 window length和sliding interval2个参数有关。
举例:每个10秒计算前10分钟的wordcount,此处sliding interval是10秒,window length是10分钟。
RDD和DStream进行join
通过 DStream的transform(rdd=>{ rdd.leftjoin(RDD) })
举例:黑名单过滤,一般黑名单存在数据库中,通过外部数据源可以得到一个静态的RDD,此处我们直接存到内存中,方便试验。blacksRDD通过map将里面的每个记录后面添加一个true,每次通过DStream中的rdd和blacksRDD进行左外连接,通过过滤出是false,即可过滤掉黑名单,只显示除了黑名单之外的人。
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
object TransformApp {
// 测试是必须通过cp命令或mv命令才可以,往文件中追加内容是不行的
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("transform")
val ssc = new StreamingContext(sparkConf, Seconds(5))
// 构建黑名单 一般是从数据库得到 此处简化为存在内存中
// blacksRDD : [<"zs" :true>, <"ls" :true>]
val blacks = List("zs", "ls")
val blacksRDD = ssc.sparkContext.parallelize(blacks).map(x => (x, true))
val lines = ssc.textFileStream("file:///G:/data/test")
// 每一行数据格式:20180502,zs,20 --> <zs: 20180502,zs,20>
val clicklog = lines.map(x => (x.split(",")(1), x))
.transform(rdd => {
rdd.leftOuterJoin(blacksRDD)
.filter(x => x._2._2.getOrElse(false) != true)
.map(x => x._2._1)
})
clicklog.print()
ssc.start()
ssc.awaitTermination()
}
}
Sparkstreaming整合SparkSQL
foreachRDD算子中func的入参是一个一个小的rdd,每个rdd即可转换为DataFrame