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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bingdianone/article/details/84848182

核心概念之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都包含来自某个时间间隔的数据,如下图所示。
在这里插入图片描述
应用于DStream的任何操作都转换为底层rdd上的操作。例如,在前面将行流转换为单词的示例中,flatMap映射操作应用于行DStream中的每个RDD,以生成words DStream的RDD。如下图所示。
在这里插入图片描述
这些底层的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处理socket数据

添加依赖

        <!-- Spark Streaming 依赖-->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>
        
        <!-- 没有此依赖会报找不到相关类的错误-->
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-scala_2.11</artifactId>
            <version>2.6.5</version>
        </dependency>
        
        <!-- 没有此依赖会报找不到相关类的错误-->
        <dependency>
            <groupId>net.jpountz.lz4</groupId>
            <artifactId>lz4</artifactId>
            <version>1.3.0</version>
        </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 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()
  }
}

猜你喜欢

转载自blog.csdn.net/bingdianone/article/details/84848182