Spark学习(玖)- Spark Streaming核心概念与编程

文章目录

    • Spark streaming以及基本工作原理
    • 核心概念之StreamingContext
    • 核心概念之DStream
    • 核心概念之Input DStreams和Receivers
      • 基本资源
      • 高级资源
    • 核心概念之Transformation和Output Operations
    • spark streaming中有状态转化操作?
      • 介绍
      • 无状态转换的例子:
      • 有状态转换
      • 基于窗口的转化操作
      • 检查点机制
      • 驱动器程序容错
      • 并行度
    • 案例实战之Spark Streaming处理socket数据
    • 案例实战之Spark Streaming处理文件系统数据

Spark streaming以及基本工作原理

接收实时输入数据流,然后将数据拆分成多个batch,比如每收集1秒的数据封装为一个batch,然后将每个batch交给Spark的计算引擎进行处理,最后会生产出一个结果数据流,其中的数据,也是由一个一个的batch所组成的。
Spark学习(玖)- Spark Streaming核心概念与编程_第1张图片

核心概念之StreamingContext

要初始化一个Spark流程序,必须创建一个StreamingContext对象,它是所有Spark流功能的主要入口点。

可以从SparkConf对象创建StreamingContext对象。

import org.apache.spark._
import org.apache.spark.streaming._

val conf = new SparkConf().setAppName(appName).setMaster(master)
val ssc = new StreamingContext(conf, Seconds(1))

batch interval可以根据你的应用程序需求的延迟要求以及集群可用的资源情况来设置;具体可以参考官网
http://spark.apache.org/docs/2.2.0/streaming-programming-guide.html#initializing-streamingcontext

定义上下文之后,您必须执行以下操作

1、通过创建输入DStreams定义输入源。
2、通过对DStreams应用转换和输出操作来定义流计算。
3、开始接收数据并使用streamingContext.start()进行处理。
4、使用streamingContext.awaitTermination()等待进程停止(手动或由于任何错误)。
5、可以使用streamingContext.stop()手动停止处理。

注意

  • 一旦Context启动,就不能设置或添加新的流计算。
  • Context一旦停止,就不能重新启动。【start()不能再stop()之后】
  • 在同一时段一个StreamingContext只能存活在一个JVM。
  • StreamingContext上的stop()也会停止SparkContext。若要仅停止StreamingContext,请将名为stopSparkContext的stop()的可选参数设置为false。
  • 可以重用SparkContext来创建多个StreamingContext,只要在创建下一个StreamingContext之前停止前一个StreamingContext(不停止SparkContext)。

核心概念之DStream

http://spark.apache.org/docs/2.2.0/streaming-programming-guide.html#discretized-streams-dstreams
Discretized Stream或DStream是Sparkstreaming提供的基本抽象。它表示连续的数据流,要么是从源接收到的输入数据流,要么是通过转换输入流生成的经过处理的数据流。在内部,DStream由一系列连续的rdd表示,rdd是Spark对不可变的分布式数据集的抽象(有关更多细节,请参阅Spark编程指南)。DStream中的每个RDD都包含来自某个时间间隔的数据,如下图所示。
Spark学习(玖)- Spark Streaming核心概念与编程_第2张图片
应用于DStream的任何操作都转换为底层rdd上的操作。例如,在前面将行流转换为单词的示例中,flatMap映射操作应用于行DStream中的每个RDD,以生成words DStream的RDD。如下图所示。
Spark学习(玖)- Spark Streaming核心概念与编程_第3张图片
这些底层的RDD转换由Spark引擎计算。DStream操作隐藏了大部分细节,并为开发人员提供了一个更高级的API,以便于使用。这些操作将在后面几节中详细讨论。

个人总结:对DStream操作算子,比如map/flatMap,其实底层会被翻译为对DStream中的每个RDD都做相同的操作;
因为一个DStream是由不同批次的RDD所构成的。

核心概念之Input DStreams和Receivers

Input DStreams是表示从流源头接收的输入数据流的DStreams。

在这个上个spark学习笔记八的例子中,lines是一个输入DStream,因为它表示从netcat服务器接收到的数据流。

每个输入DStream(除了文件系统;文件系统已经存在直接就可以处理不需要接受)都与一个Receiver(Scala doc、Java doc)对象相关联,该对象从源接收数据并将其存储在Spark内存中进行处理。

Spark流提供了两类内置流源
基本资源:StreamingContext API中直接可用的资源。示例:file systems, socket 连接。
高级资源:可以通过额外的实用程序类获得Kafka、Flume、Kinesis等资源。如链接一节中所讨论的,这些需要针对额外依赖项进行链接。

注意
1、在本地运行Spark流程序时,不要使用“local”或“local[1]”作为主URL。这两种方法都意味着只使用一个线程在本地运行任务。如果您正在使用基于接收器的输入DStream(例如socket、Kafka、Flume等),那么将使用单个线程来运行接收器,没有线程来处理接收到的数据。因此,在本地运行时,始终使用“local[n]”作为主URL,其中要运行的接收方数量为n >(有关如何设置主URL的信息,请参阅Spark属性)。
2、将逻辑扩展到在集群上运行时,分配给Spark流应用程序的内核数量必须大于接收器的数量。否则系统将接收数据,但无法处理它。

基本资源

我们已经在快速示例中查看了ssl . sockettextstream(…),它从通过TCP套接字连接接收到的文本数据创建DStream。除了套接字,StreamingContext API还提供了从文件创建DStreams作为输入源的方法

File Streams:对于从与HDFS API(即HDFS、S3、NFS等)兼容的任何文件系统上的文件读取数据,可以将DStream创建为:

 streamingContext.fileStream[KeyClass, ValueClass, InputFormatClass](dataDirectory)

Spark流将监视目录dataDirectory并处理在该目录中创建的任何文件(不支持在嵌套目录中编写的文件)。请注意:

  • 文件必须具有相同的数据格式。
  • 必须在dataDirectory中创建文件,方法是将文件原子地移动或重命名到数据目录中。
  • 一旦移动,文件就不能更改。因此,如果文件是连续追加的,则不会读取新数据。

对于简单的文本文件,有一个更简单的方法streamingContext.textFileStream(dataDirectory)。文件流不需要运行接收器,因此不需要分配核心。
Python API文件流不可用,只有textfilestream可用。

高级资源

http://spark.apache.org/docs/2.2.0/streaming-programming-guide.html#advanced-sources

核心概念之Transformation和Output Operations

与RDD类似,转换允许修改来自输入DStream的数据。DStreams支持普通Spark RDD上可用的许多转换。一些常见的如下:

Transformation Meaning
map(func) 通过将源DStream的每个元素传递给函数func来返回一个新的DStream 。
flatMap(func) 与map类似,但每个输入项可以映射到0个或更多输出项。
filter(func) 通过只选择func返回true的源DStream的记录来返回一个新的DStream。
repartition(numPartitions) 通过创建更多或更少的分区来更改此DStream中的并行度级别。
union(otherStream) 返回一个新的DStream,它包含源DStream和otherDStream中元素的并集。
count() 通过计算源DStream的每个RDD中的元素数量,返回单元素RDD的新DStream。
reduce(func) 通过使用函数func(它接受两个参数并返回一个)聚合源DStream的每个RDD中的元素,返回单元素RDD的新DStream 。该函数应该是关联的和可交换的,以便可以并行计算。
countByValue() 当在类型K的元素的DStream上调用时,返回(K,Long)对的新DStream,其中每个键的值是其在源DStream的每个RDD中的频率。
reduceByKey(func, [numTasks]) 当在(K,V)对的DStream上调用时,返回(K,V)对的新DStream,其中使用给定的reduce函数聚合每个键的值。注意:默认情况下,这使用Spark的默认并行任务数(本地模式为2,在群集模式下,数量由config属性确定spark.default.parallelism)进行分组。您可以传递可选numTasks参数来设置不同数量的任务。
join(otherStream, [numTasks]) 当在(K,V)和(K,W)对的两个DStream上调用时,返回(K,(V,W))对的新DStream与每个键的所有元素对。
cogroup(otherStream, [numTasks]) 当在(K,V)和(K,W)对的DStream上调用时,返回(K,Seq [V],Seq [W])元组的新DStream。
transform(func) 通过将RDD-to-RDD函数应用于源DStream的每个RDD来返回新的DStream。这可以用于在DStream上执行任意RDD操作。
updateStateByKey(func) 返回一个新的“状态”DStream,其中通过在键的先前状态和键的新值上应用给定函数来更新每个键的状态。这可用于维护每个密钥的任意状态数据。

输出操作允许将DStream的数据推送到外部系统,如数据库或文件系统。由于输出操作实际上允许外部系统使用转换后的数据,因此它们会触发所有DStream转换的实际执行(类似于RDD的操作)。目前,定义了以下输出操作:

Output Operation Meaning
print() 在运行流应用程序的驱动程序节点上打印DStream中每批数据的前十个元素。这对开发和调试很有用。 Python API这在Python API中称为 pprint()。
saveAsTextFiles(prefix, [suffix]) 将此DStream的内容保存为文本文件。每个批处理间隔的文件名是基于前缀和后缀生成的:“prefix-TIME_IN_MS [.suffix]”。
saveAsObjectFiles(prefix, [suffix]) 将此DStream的内容保存为SequenceFiles序列化Java对象。每个批处理间隔的文件名是基于前缀和 后缀生成的:“prefix-TIME_IN_MS [.suffix]”。Python API这在Python API中不可用。
saveAsHadoopFiles(prefix, [suffix]) 将此DStream的内容保存为Hadoop文件。每个批处理间隔的文件名是基于前缀和后缀生成的:“prefix-TIME_IN_MS [.suffix]”。 Python API这在Python API中不可用。
foreachRDD(func) 最通用的输出运算符,它将函数func应用于从流生成的每个RDD。此函数应将每个RDD中的数据推送到外部系统,例如将RDD保存到文件,或通过网络将其写入数据库。请注意,函数func在运行流应用程序的驱动程序进程中执行,并且通常会在其中执行RDD操作,这将强制计算流式RDD。

spark streaming中有状态转化操作?

介绍

许多应用需要处理及时收到的数据,Spark Streaming是Spark为这些应用而设计的模型。它允许用户使用一套和批处理非常接近的 API 来编写流式计算应用,这样就可以大量重用批处理应用的技术甚至代码。
和Spark基于RDD的概念很相似,Spark Streaming使用离散化流(discretized stream)作为抽象表示,叫作 DStream。DStream 是随时间推移而收到的数据的序列。在内部,每个时间区间收到的数据都作为 RDD 存在,而 DStream 是由这些 RDD 所组成的序列(因此得名“离散化”)。DStream 可以从各种输入源创建,比如 Flume、Kafka 或者 HDFS。创建出来的 DStream 支持两种操作,一种是转化操作(transformation),会生成一个新的DStream,另一种是输出操作(output operation),可以把数据写入外部系统中。DStream提供了许多与 RDD 所支持的操作相类似的操作支持,还增加了与时间相关的新操作,比如滑动窗口。

无状态转换的例子:

• map
• flatmap
• filter
• repartition
• reducebykey
• groupbykey
无状态转化操作也能在多个 DStream 间整合数据,不过也是在各个时间区间内。例如,键值对 DStream 拥有和 RDD 一样的与连接相关的转化操作,也就cogroup()、join()、leftOuterJoin() 等
Transform(): 可以让你直接操作其内部的rdd。

有状态转换

DStream 的有状态转化操作是跨时间区间跟踪数据的操作;也就是说,一些先前批次的数据也被用来在新的批次中计算结果。主要的两种类型是滑动窗口和 updateStateByKey(),前者以一个时间阶段为滑动窗口进行操作,后者则用来跟踪每个键的状态变化(例如构建一个代表用户会话的对象)。

基于窗口的转化操作

所有基于窗口的操作都需要两个参数,分别为窗口时长以及滑动步长,两者都必须是StreamContext 的批次间隔的整数倍。窗口时长控制每次计算最近的多少个批次的数据,其实就是最近的 windowDuration/batchInterval 个批次。如果有一个以 10 秒为批次间隔的源DStream,要创建一个最近 30 秒的时间窗口(即最近 3 个批次),就应当把 windowDuration设为 30 秒。而滑动步长的默认值与批次间隔相等,用来控制对新的 DStream 进行计算的间隔。如果源 DStream 批次间隔为 10 秒,并且我们只希望每两个批次计算一次窗口结果,就应该把滑动步长设置为 20 秒。

尽管可以使用window()写出所有的窗口操作,Spark Streaming还是提供了一些其他的窗口操作,让用户可以高效而方便地使用。首先,reduceByWindow() 和 reduceByKeyAndWindow()让我们可以对每个窗口更高效地进行归约操作。
输出操作
输出操作指定了对流数据经转化操作得到的数据所要执行的操作(例如把结果推入外部数据库或输出到屏幕上)。

  1. print

  2. ipAddressRequestCount.saveAsTextFiles(“outputDir”, “txt”)

  3. saveashadoopfiles

  4. Sequence file

  5. foreachrdd
    24*7不间断运行

检查点机制

检查点机制是我们在Spark Streaming中用来保障容错性的主要机制。它可以使SparkStreaming阶段性地把应用数据存储到诸如HDFS或Amazon S3这样的可靠存储系统中,以供恢复时使用。具体来说,检查点机制主要为以下两个目的服务。
• 控制发生失败时需要重算的状态数。SparkStreaming可以通过转化图的谱系图来重算状态,检查点机制则可以控制需要在转化图中回溯多远。
• 提供驱动器程序容错。如果流计算应用中的驱动器程序崩溃了,你可以重启驱动器程序并让驱动器程序从检查点恢复,这样Spark Streaming就可以读取之前运行的程序处理数据的进度,并从那里继续。

驱动器程序容错

驱动器程序的容错要求我们以特殊的方式创建 StreamingContext。我们需要把检查点目录提供给 StreamingContext。与直接调用 new StreamingContext 不同,应该使用StreamingContext.getOrCreate() 函数。
性能考量
批次和窗口大小(500ms)

并行度

• 增加接收器数目有时如果记录太多导致单台机器来不及读入并分发的话,接收器会成为系统瓶颈。这时你就需要通过创建多个输入 DStream(这样会创建多个接收器)来增加接收器数目,然后使用 union 来把数据合并为一个数据源。
• 将收到的数据显式地重新分区
如果接收器数目无法再增加,你可以通过使用 DStream.repartition 来显式重新分区输
入流(或者合并多个流得到的数据流)来重新分配收到的数据。
• 提高聚合计算的并行度
对于像 reduceByKey() 这样的操作,你可以在第二个参数中指定并行度。

案例实战之Spark Streaming处理socket数据

添加依赖

        
        <dependency>
            <groupId>org.apache.sparkgroupId>
            <artifactId>spark-streaming_2.11artifactId>
            <version>${spark.version}version>
        dependency>
        
        
        <dependency>
            <groupId>com.fasterxml.jackson.modulegroupId>
            <artifactId>jackson-module-scala_2.11artifactId>
            <version>2.6.5version>
        dependency>
        
        
        <dependency>
            <groupId>net.jpountz.lz4groupId>
            <artifactId>lz4artifactId>
            <version>1.3.0version>
        dependency>

编写NetworkWordcount

package com.imooc.spark

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}

/**
  * Spark Streaming处理Socket数据
  *
  * 本地测试: nc -lk 6789
  */
object NetworkWordCount {


  def main(args: Array[String]): Unit = {

    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")

    /**
      * 创建StreamingContext需要两个参数:SparkConf和batch interval
      */
    val ssc = new StreamingContext(sparkConf, Seconds(5))

    val lines = ssc.socketTextStream("localhost", 6789)

    val result = lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)

    result.print()
    
    ssc.start()
    ssc.awaitTermination()
  }
}

Spark学习(玖)- Spark Streaming核心概念与编程_第4张图片

案例实战之Spark Streaming处理文件系统数据

package com.imooc.spark

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}

/**
  * 使用Spark Streaming处理文件系统(local/hdfs)的数据
  */
object FileWordCount {

  def main(args: Array[String]): Unit = {
    //local;文件系统是本地的不用receive接受;本地测试的时候不需要2个core
    val sparkConf = new SparkConf().setMaster("local").setAppName("FileWordCount")
    val ssc = new StreamingContext(sparkConf, Seconds(5))

    val lines = ssc.textFileStream("file:///Users/rocky/data/imooc/ss/")

    val result = lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
    result.print()

    ssc.start()
    ssc.awaitTermination()
  }
}

你可能感兴趣的:(Spark学习笔记)