看完了这篇文章,让你对SparkStreaming再也不迷茫了

本文深入讲解SparkStreaming原理,包括实时计算需求、数据抽象DStream及其操作,如updateStateByKey和reduceByKeyAndWindow。通过实战案例,如WordCount、热门词汇TopN统计,详细演示SparkStreaming在实时数据处理中的应用。
摘要由CSDN通过智能技术生成

前言
大家好,我是DJ丶小哪吒,我又来跟你们分享知识了。小编对软件开发有着浓厚的兴趣。喜欢与人分享知识。做博客的目的就是为了能与 他 人知识共享。由于水平有限。博客中难免会有一些错误。如有 纰 漏之处,欢迎大家在留言区指正。小编也会及时改正。

你们阔耐,阳光,积极向上的DJ丶小哪吒又回来了,好像回顾之前,小编已经两个星期没有更新博客了呢。也是最近比较忙,由于跟进老师讲的项目,并吃透。每天都加班到10点半,小编心里苦啊。但是小编坚信,努力就会有希望。为两个月后的工作做准备,加油!!!

今天小编要分享的是SparkStreaming的篇章,带各位更深层次的了解SparkStreaming。准备好了吗,showtime~~~

第一章 Spark Streaming引入

1.1.新的场景需求

●集群监控
一般的大型集群和平台, 都需要对其进行监控的需求。要针对各种数据库, 包括 MySQL, HBase 等进行监控要针对应用进行监控, 例如 Tomcat, Nginx, Node.js 等。要针对硬件的一些指标进行监控, 例如 CPU, 内存, 磁盘 等
在这里插入图片描述
●还有很多很多
例如:
在这里插入图片描述
还有,
在这里插入图片描述
想这些可视化界面,后边都是需要SparkStreaming去进行实时的计算,最后将计算结果进行分析并展示。所以,SparkStreaming是不是很重要呢。

1.2. Spark Streaming介绍

●官网
http://spark.apache.org/streaming/
●概述
Spark Streaming是一个基于Spark Core之上的实时计算框架,可以从很多数据源消费数据并对数据进行实时的处理,具有高吞吐量和容错能力强等特点。
在这里插入图片描述
●Spark Streaming的特点
1.易用
可以像编写离线批处理一样去编写流式程序,支持java/scala/python语言。

2.容错
SparkStreaming在没有额外代码和配置的情况下可以恢复丢失的工作。

3.易整合到Spark体系
流式处理与批处理和交互式查询相结合。

1.3. 实时计算所处的位置

在这里插入图片描述

第二章 Spark Streaming原理

2.1. SparkStreaming原理
2.1.1. 整体流程

Spark Streaming中,会有一个接收器组件Receiver,作为一个长期运行的task跑在一个Executor上。Receiver接收外部的数据流形成input DStream

DStream会被按照时间间隔划分成一批一批的RDD,当批处理间隔缩短到秒级时,便可以用于处理实时数据流。时间间隔的大小可以由参数指定,一般设在500毫秒到几秒之间。
对DStream进行操作就是对RDD进行操作,计算处理的结果可以传给外部系统。
Spark Streaming的工作流程像下面的图所示一样,接收到实时数据后,给数据分批次,然后传给Spark Engine(引擎)处理最后生成该批次的结果。

在这里插入图片描述

2.1.2. 数据抽象

Spark Streaming的基础抽象是DStream(Discretized Stream,离散化数据流,连续不断的数据流),代表持续性的数据流和经过各种Spark算子操作后的结果数据流

●可以从以下多个角度深入理解DStream
1.DStream本质上就是一系列时间上连续的RDD

在这里插入图片描述
2.对DStream的数据的进行操作也是按照RDD为单位来进行的
在这里插入图片描述
3.容错性
底层RDD之间存在依赖关系,DStream直接也有依赖关系,RDD具有容错性,那么DStream也具有容错性
如图:每一个椭圆形表示一个RDD
椭圆形中的每个圆形代表一个RDD中的一个Partition分区
每一列的多个RDD表示一个DStream(图中有三列所以有三个DStream)
每一行最后一个RDD则表示每一个Batch Size所产生的中间结果RDD
在这里插入图片描述

4.准实时性/近实时性
Spark Streaming将流式计算分解成多个Spark Job,对于每一时间段数据的处理都会经过Spark DAG图分解以及Spark的任务集的调度过程。
对于目前版本的Spark Streaming而言,其最小的Batch Size的选取在0.5~5秒钟之间
所以Spark Streaming能够满足流式准实时计算场景,对实时性要求非常高的如高频实时交易场景则不太适合

2.1.3、总结

简单来说DStream就是对RDD的封装,你对DStream进行操作,就是对RDD进行操作
对于DataFrame/DataSet/DStream来说本质上都可以理解成RDD
在这里插入图片描述

2.2. DStream相关操作

DStream上的操作与RDD的类似,分为以下两种:
Transformations(转换)
Output Operations(输出)/Action

2.2.1. Transformations

●常见Transformation—无状态转换:每个批次的处理不依赖于之前批次的数据

TransformationsMeaning
map(func)对DStream中的各个元素进行func函数操作,然后返回一个新的DStream
flatMap(func)与map方法类似,只不过各个输入项可以被输出为零个或多个输出项
filter(func)过滤出所有函数func返回值为true的DStream元素并返回一个新的DStream
union(otherStream)将源DStream和输入参数为otherDStream的元素合并,并返回一个新的DStream.
reduceByKey(func, [numTasks])利用func函数对源DStream中的key进行聚合操作,然后返回新的(K,V)对构成的DStream
join(otherStream, [numTasks])输入为(K,V)、(K,W)类型的DStream,返回一个新的(K,(V,W)类型的DStream
transform(func)通过RDD-to-RDD函数作用于DStream中的各个RDD,可以是任意的RDD操作,从而返回一个新的RDD

●特殊的Transformations—有状态转换:当前批次的处理需要使用之前批次的数据或者中间结果。
有状态转换包括基于追踪状态变化的转换(updateStateByKey)和滑动窗口的转换

1.UpdateStateByKey(func)
2.Window Operations 窗口操作

2.2.2. Output/Action

Output Operations可以将DStream的数据输出到外部的数据库或文件系统
当某个Output Operations被调用时,spark streaming程序才会开始真正的计算过程(与RDD的Action类似)

Output OperationMeaning
print()打印到控制台
saveAsTextFiles(prefix, [suffix])保存流的内容为文本文件,文件名为"prefix-TIME_IN_MS[.suffix]".
saveAsObjectFiles(prefix,[suffix])保存流的内容为SequenceFile,文件名为 “prefix-TIME_IN_MS[.suffix]”.
saveAsHadoopFiles(prefix,[suffix])保存流的内容为hadoop文件,文件名为"prefix-TIME_IN_MS[.suffix]".
foreachRDD(func)对Dstream里面的每个RDD执行func
2.3、总结

在这里插入图片描述

第三章 Spark Streaming实战

3.1. WordCount
3.1.1. 需求&准备

●图解
在这里插入图片描述
●首先在linux服务器上安装nc工具
nc是netcat的简称,原本是用来设置路由器,我们可以利用它向某个端口发送数据
yum install -y nc
●启动一个服务端并开放9999端口,等一下往这个端口发数据
nc -lk 9999
●发送数据

3.1.2. 代码演示
package cn.itcast.streaming

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Seconds, StreamingContext}

object WordCount {
  def main(args: Array[String]): Unit = {
    //1.创建StreamingContext
    //spark.master should be set as local[n], n > 1
    val conf = new SparkConf().setAppName("wc").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    val ssc = new StreamingContext(sc,Seconds(5))//5表示5秒中对数据进行切分形成一个RDD
    //2.监听Socket接收数据
    //ReceiverInputDStream就是接收到的所有的数据组成的RDD,封装成了DStream,接下来对DStream进行操作就是对RDD进行操作
    val dataDStream: ReceiverInputDStream[String] = ssc.socketTextStream("node01",9999)
    //3.操作数据
    val wordDStream: DStream[String] = dataDStream.flatMap(_.split(" "))
    val wordAndOneDStream: DStream[(String, Int)] = wordDStream.map((_,1))
    val wordAndCount: DStream[(String, Int)] = wordAndOneDStream.reduceByKey(_+_)
    wordAndCount.print()
    ssc.start()//开启
    ssc.awaitTermination()//等待停止
  }
}
3.1.3. 执行

1.先执行nc -lk 9999

2.然后执行代码

3.不断的在中nc -lk 9999端口中输入不同的单词
hadoop spark sqoop hadoop spark hive hadoop

4.观察IDEA控制台输出
sparkStreaming每隔5s计算一次当前5s内的数据,然后将每个批次的数据输出

3.2. updateStateByKey
3.2.1. 问题

在上面的那个案例中存在这样一个问题:
每个批次的单词次数都被正确的统计出来,但是结果不能累加!
如果需要累加需要使用updateStateByKey(func)来更新状态.

3.2.2. 代码演示
package cn.itcast.streaming

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}


object WordCount2 {
  def main(args: Array[String]): Unit = {
    //1.创建StreamingContext
    //spark.master should be set as local[n], n > 1
    val conf = new SparkConf().setAppName("wc").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    val ssc = new StreamingContext(sc,Seconds(5))//5表示5秒中对数据进行切分形成一个RDD
    //requirement failed: ....Please set it by StreamingContext.checkpoint().
    //注意:我们在下面使用到了updateStateByKey对当前数据和历史数据进行累加
    //那么历史数据存在哪?我们需要给他设置一个checkpoint目录
    ssc.checkpoint("./wc")//开发中HDFS
    //2.监听Socket接收数据
    //ReceiverInputDStream就是接收到的所有的数据组成的RDD,封装成了DStream,接下来对DStream进行操作就是对RDD进行操作
    val dataDStream: ReceiverInputDStream[String] = ssc.socketTextStream("node01",9999)
    //3.操作数据
    val wordDStream: DStream[String] = dataDStream.flatMap(_.split(" "))
    val wordAndOneDStream: DStream[(String, Int)] = wordDStream.map((_,1))
    //val wordAndCount: DStream[(String, Int)] = wordAndOneDStream.reduceByKey(_+_)
    //====================使用updateStateByKey对当前数据和历史数据进行累加====================
    val wordAndCount: DStream[(String, Int)] =wordAndOneDStream.updateStateByKey(updateFunc)
    wordAndCount.print()
    ssc.start()//开启
    ssc.awaitTermination()//等待优雅停止
  }
  //currentValues:当前批次的value值,如:1,1,1 (以测试数据中的hadoop为例)
  //historyValue:之前累计的历史值,第一次没有值是0,第二次是3
  //目标是把当前数据+历史数据返回作为新的结果(下次的历史数据)
  def updateFunc(currentValues:Seq[Int], historyValue:Option[Int] ):Option[Int] ={
// currentValues当前值
// historyValue历史值
    val result: Int = currentValues.sum + historyValue.getOrElse(0)
    Some(result)
  }
}
3.2.3. 执行

1.先执行nc -lk 9999

2.然后执行以上代码

3.不断的在nc -lk 9999 中输入不同的单词,
hadoop spark sqoop hadoop spark hive hadoop

4.观察IDEA控制台输出
sparkStreaming每隔5s计算一次当前5s内的数据,然后将每个批次的结果数据累加输出。

3.3. reduceByKeyAndWindow
3.3.1. 图解

滑动窗口转换操作的计算过程如下图所示,
我们可以事先设定一个滑动窗口的长度(也就是窗口的持续时间),并且设定滑动窗口的时间间隔(每隔多长时间执行一次计算),
比如设置滑动窗口的长度(也就是窗口的持续时间)为24H,设置滑动窗口的时间间隔(每隔多长时间执行一次计算)为1H
那么意思就是:每隔1H计算最近24H的数据
在这里插入图片描述
在这里插入图片描述

3.3.2. 代码演示
package cn.itcast.streaming

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}

object WordCount3 {
  def main(args: Array[String]): Unit = {
    //1.创建StreamingContext
    //spark.master should be set as local[n], n > 1
    val conf = new SparkConf().setAppName("wc").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    val ssc = new StreamingContext(sc,Seconds(5))//5表示5秒中对数据进行切分形成一个RDD
    //2.监听Socket接收数据
    //ReceiverInputDStream就是接收到的所有的数据组成的RDD,封装成了DStream,接下来对DStream进行操作就是对RDD进行操作
    val dataDStream: ReceiverInputDStream[String] = ssc.socketTextStream("node01",9999)
    //3.操作数据
    val wordDStream: DStream[String] = dataDStream.flatMap(_.split(" "))
    val wordAndOneDStream: DStream[(String, Int)] = wordDStream.map((_,1))
 
    val wordAndCount: DStream[(String, Int)] = wordAndOneDStream.reduceByKeyAndWindow((a:Int,b:Int)=>a+b,Seconds(10),Seconds(5))
   //4.使用窗口函数进行WordCount计数
    //reduceFunc: (V, V) => V,集合函数
    //windowDuration: Duration,窗口长度/宽度
    //slideDuration: Duration,窗口滑动间隔
    //注意:windowDuration和slideDuration必须是batchDuration的倍数
    //windowDuration=slideDuration:数据不会丢失也不会重复计算==开发中会使用
    //windowDuration>slideDuration:数据会重复计算==开发中会使用
    //windowDuration<slideDuration:数据会丢失
    //代码表示:
    //windowDuration=10
    //slideDuration=5
    //那么执行结果就是每隔5s计算最近10s的数据
    //比如开发中让你统计最近1小时的数据,每隔1分钟计算一次,那么参数该如何设置?

    wordAndCount.print()
    ssc.start()//开启
    ssc.awaitTermination()//等待优雅停止
  }
}
3.3.3. 执行

1.先执行nc -lk 9999
2.然后执行以上代码
3.不断的在nc -lk 9999 中输入不同的单词
hadoop spark sqoop hadoop spark hive hadoop
4.观察IDEA控制台输出
现象:sparkStreaming每隔5s计算一次当前在窗口大小为10s内的数据,然后将结果数据输出。

3.4. 统计一定时间内的热门词汇TopN
3.4.1. 需求

模拟百度热搜排行榜
统计最近10s的热搜词Top3,每隔5秒计算一次
WindowDuration = 10s
SlideDuration = 5s
在这里插入图片描述

3.4.2. 代码演示
package cn.itcast.streaming

import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}

 /*
  * Desc 我们要模拟百度热搜排行榜统计最近10s的热搜词Top3,每隔5秒计算一次
  */
object WordCount4 {
  def main(args: Array[String]): Unit = {
    //1.创建StreamingContext
    //spark.master should be set as local[n], n > 1
    val conf = new SparkConf().setAppName("wc").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    val ssc = new StreamingContext(sc,Seconds(5))//5表示5秒中对数据进行切分形成一个RDD
    //2.监听Socket接收数据
    //ReceiverInputDStream就是接收到的所有的数据组成的RDD,封装成了DStream,接下来对DStream进行操作就是对RDD进行操作
    val dataDStream: ReceiverInputDStream[String] = ssc.socketTextStream("node01",9999)
    //3.操作数据
    val wordDStream: DStream[String] = dataDStream.flatMap(_.split(" "))
    val wordAndOneDStream: DStream[(String, Int)] = wordDStream.map((_,1))
    //4.使用窗口函数进行WordCount计数
    val wordAndCount: DStream[(String, Int)] = wordAndOneDStream.reduceByKeyAndWindow((a:Int,b:Int)=>a+b,Seconds(10),Seconds(5))
    val sorteDStream: DStream[(String, Int)] = wordAndCount.transform(rdd => {
      val sortedRDD: RDD[(String, Int)] = rdd.sortBy(_._2, false) //逆序/降序
      println("===============top3==============")
      sortedRDD.take(3).foreach(println)
      println("===============top3==============")
      sortedRDD
    }
    )
    //No output operations registered, so nothing to execute
    sorteDStream.print
    ssc.start()//开启
    ssc.awaitTermination()//等待优雅停止
  }
}
3.4.3. 执行

1.先执行nc -lk 9999
2.然后在执行以上代码
3.不断的在nc -lk 9999 中输入不同的单词
hadoop spark sqoop hadoop spark hive hadoop
4.观察IDEA控制台输出


好了,以上内容就到这里了。你学到了吗。 欢迎路过的朋友关注小编哦。各位朋友关注点赞是小编坚持下去的动力。小编会继续为大家分享更多的知识哦~~~。

我是DJ丶小哪吒。是一名互联网行业的工具人,小编的座右铭:“我不生产代码,我只做代码的搬运工”…哈哈哈,我们下期见哦,Bye~

如果你的内在一直成长,那么你早晚会破土而出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值