4 Spark Streaming

server/2025/2/4 11:45:21/

4 Spark Streaming

  • 一级目录
  • 1. 整体流程
  • 2. 数据抽象
  • 3. DStream 相关操作
  • 4. Spark Streaming 完成实时需求
    • 1) WordCount
    • 2) updateStateByKey
    • 3) reduceByKeyAndWindow

一级目录

Spark Streaming 是一个基于 Spark Core 之上的实时计算框架,可以从很多数据源消费数据并对数据进行实时的处理,具有高吞吐量和容错能力强等特点。
在这里插入图片描述

Spark Streaming 的特点:
1.易用
可以像编写离线批处理一样去编写流式程序,支持 java/scala/python 语言。
2.容错
SparkStreaming 在没有额外代码和配置的情况下可以恢复丢失的工作。
3.易整合到 Spark 体系
流式处理与批处理和交互式查询相结合。

1. 整体流程

Spark Streaming 中,会有一个接收器组件 Receiver,作为一个长期运行的 task 跑在一个 Executor 上。Receiver 接收外部的数据流形成 input DStream。
DStream 会被按照时间间隔划分成一批一批的 RDD,当批处理间隔缩短到秒级时,便可以用于处理实时数据流。时间间隔的大小可以由参数指定,一般设在 500 毫秒到几秒之间。
对 DStream 进行操作就是对 RDD 进行操作,计算处理的结果可以传给外部系统。
Spark Streaming 的工作流程像下面的图所示一样,接受到实时数据后,给数据分批次,然后传给 Spark Engine 处理最后生成该批次的结果。

2. 数据抽象

Spark Streaming 的基础抽象是 DStream(Discretized Stream,离散化数据流,连续不断的数据流),代表持续性的数据流和经过各种 Spark 算子操作后的结果数据流。
可以从以下多个角度深入理解 DStream:
1.DStream 本质上就是一系列时间上连续的 RDD
在这里插入图片描述
2.对 DStream 的数据的进行操作也是按照 RDD 为单位来进行的
在这里插入图片描述
3.容错性,底层 RDD 之间存在依赖关系,DStream 直接也有依赖关系,RDD 具有容错性,那么 DStream 也具有容错性
4.准实时性/近实时性
Spark Streaming 将流式计算分解成多个 Spark Job,对于每一时间段数据的处理都会经过 Spark DAG 图分解以及 Spark 的任务集的调度过程。
对于目前版本的 Spark Streaming 而言,其最小的 Batch Size 的选取在 0.5~5 秒钟之间。
所以 Spark Streaming 能够满足流式准实时计算场景,对实时性要求非常高的如高频实时交易场景则不太适合。
-总结
简单来说 DStream 就是对 RDD 的封装,你对 DStream 进行操作,就是对 RDD 进行操作。
对于 DataFrame/DataSet/DStream 来说本质上都可以理解成 RDD。

3. DStream 相关操作

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

  1. Transformations
    以下是常见 Transformation—都是无状态转换:即每个批次的处理不依赖于之前批次的数据:
    在这里插入图片描述
    除此之外还有一类特殊的 Transformations—有状态转换:当前批次的处理需要使用之前批次的数据或者中间结果。
    有状态转换包括基于追踪状态变化的转换(updateStateByKey)和滑动窗口的转换:
    1.UpdateStateByKey(func)
    2.Window Operations 窗口操作

  2. Output/Action
    Output Operations 可以将 DStream 的数据输出到外部的数据库或文件系统。
    当某个 Output Operations 被调用时,spark streaming 程序才会开始真正的计算过程(与 RDD 的 Action 类似)。
    在这里插入图片描述

4. Spark Streaming 完成实时需求

1) WordCount

-首先在 linux 服务器上安装 nc 工具
nc 是 netcat 的简称,原本是用来设置路由器,我们可以利用它向某个端口发送数据 yum install -y nc
-启动一个服务端并开放 9999 端口,等一下往这个端口发数据
nc -lk 9999
-发送数据
-接收数据,代码示例:

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 > 1val 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()//等待停止}
}

2) updateStateByKey

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

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 > 1val 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] ={val result: Int = currentValues.sum + historyValue.getOrElse(0)Some(result)}
}

3) reduceByKeyAndWindow

使用上面的代码已经能够完成对所有历史数据的聚合,但是实际中可能会有一些需求,需要对指定时间范围的数据进行统计。
比如:
百度/微博的热搜排行榜 统计最近 24 小时的热搜词,每隔 5 分钟更新一次,所以面对这样的需求我们需要使用窗口操作 Window Operations。
图解:
我们先提出一个问题:统计经过某红绿灯的汽车数量之和?
假设在一个红绿灯处,我们每隔 15 秒统计一次通过此红绿灯的汽车数量,如下图:
在这里插入图片描述

可以把汽车的经过看成一个流,无穷的流,不断有汽车经过此红绿灯,因此无法统计总共的汽车数量。但是,我们可以换一种思路,每隔 15 秒,我们都将与上一次的结果进行 sum 操作(滑动聚合, 但是这个结果似乎还是无法回答我们的问题,根本原因在于流是无界的,我们不能限制流,但可以在有一个有界的范围内处理无界的流数据。
在这里插入图片描述

因此,我们需要换一个问题的提法:每分钟经过某红绿灯的汽车数量之和?
这个问题,就相当于一个定义了一个 Window(窗口),window 的界限是 1 分钟,且每分钟内的数据互不干扰,因此也可以称为翻滚(不重合)窗口,如下图:
第一分钟的数量为 8,第二分钟是 22,第三分钟是 27。。。这样,1 个小时内会有 60 个 window。
再考虑一种情况,每 30 秒统计一次过去 1 分钟的汽车数量之和:
在这里插入图片描述
此时,window 出现了重合。这样,1 个小时内会有 120 个 window。
滑动窗口转换操作的计算过程如下图所示:
在这里插入图片描述

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

代码示例:

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 > 1val 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计数//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分钟计算一次,那么参数该如何设置?//windowDuration=Minutes(60)//slideDuration=Minutes(1)val wordAndCount: DStream[(String, Int)] = wordAndOneDStream.reduceByKeyAndWindow((a:Int,b:Int)=>a+b,Seconds(10),Seconds(5))wordAndCount.print()ssc.start()//开启ssc.awaitTermination()//等待优雅停止}
}

http://www.ppmy.cn/server/164876.html

相关文章

【Go - 小顶堆/大顶堆】

在 Go 语言中&#xff0c;标准库 container/heap 提供了堆&#xff08;Heap&#xff09;的实现。可以使用 container/heap 包来实现自己的大顶堆或小顶堆。 小顶堆示例 以下是一个使用 container/heap 包实现的小顶堆示例&#xff1a; package mainimport ("container/…

HTML 符号详解

HTML 符号详解 引言 HTML(超文本标记语言)符号是HTML文档中用来表示特殊字符的标记。这些符号在日常网页设计和开发中扮演着重要角色,特别是在需要显示版权、商标、货币符号等特殊字符时。本文将详细介绍HTML符号的用法、类型以及如何在HTML文档中插入这些符号。 HTML符号…

新鲜速递:DeepSeek-R1开源大模型本地部署实战—Ollama + MaxKB 搭建RAG检索增强生成应用

在AI技术快速发展的今天&#xff0c;开源大模型的本地化部署正在成为开发者们的热门实践方向。最火的莫过于吊打OpenAI过亿成本的纯国产DeepSeek开源大模型&#xff0c;就在刚刚&#xff0c;凭一己之力让英伟达大跌18%&#xff0c;纳斯达克大跌3.7%&#xff0c;足足是给中国AI产…

DDD - 领域事件_解耦微服务的关键

文章目录 Pre领域事件的核心概念领域事件的作用领域事件的识别领域事件的技术实现领域事件的运行机制案例领域事件驱动的优势 Pre DDD - 微服务设计与领域驱动设计实战(中)_ 解决微服务拆分难题 EDA - Spring Boot构建基于事件驱动的消息系统 领域事件的核心概念 领域事件&a…

数据库 - Sqlserver - SQLEXPRESS、由Windows认证改为SQL Server Express认证进行连接 (sa登录)

本文讲SqlServer Express版本在登录的时候&#xff0c; 如何由Windows认证&#xff0c;修改为Sql Server Express认证。 目录 1&#xff0c;SqlServer Express的Windows认证 2&#xff0c;修改为混合认证 3&#xff0c;启用sa 用户 4&#xff0c;用sa 用户登录 下面是详细…

K8S中数据存储之配置存储

配置存储 在Kubernetes中&#xff0c;ConfigMap和Secret是两种核心资源&#xff0c;用于存储和管理应用程序的配置数据和敏感信息。理解它们的功能和最佳实践对于提高Kubernetes应用程序的安全性和配置管理的效率至关重要。 ConfigMap ConfigMap是一种API对象&#xff0c;允许…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.27 线性代数王国:矩阵分解实战指南

1.27 线性代数王国&#xff1a;矩阵分解实战指南 #mermaid-svg-JWrp2JAP9qkdS2A7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JWrp2JAP9qkdS2A7 .error-icon{fill:#552222;}#mermaid-svg-JWrp2JAP9qkdS2A7 .erro…

Java开发vscode环境搭建

1 几个名词 JDK Java Development Kit JRE Java Runtion Environment JVM JDK 包括 Compiler,debugger,JRE等。JRE包括JVM和Runtime Library。 2 配置环境 2.1 安装JDK 类比 C/C的 g工具 官网&#xff1a;https://www.oracle.com/java/technologies/downloads/ 根据自己使…