Spark Streaming学习笔记

Spark Streaming 

简介:

sparksql

sparkStreaming

Mlib

GraphX

SparkCore

Spark Streaming, 其实就是一种Spark提供的, 对于大数据, 进行实时计算的一种框架。 它的底层, 其实, 也是基于Spark Core的。

 基本的计算模型, 还是基于内存的大数据实时计算模型。 

而且, 它的底层的组件或者叫做概念,其实还是最核心的RDD

针对实时计算的特点, RDD之上, 进行了一层封装, 叫做DStream

它针对数据查询这种应用, 提供了一种基于RDD之上的全新概念, DataFrame, 但是,其底层还是基于RDD的。 所以, RDD是整个Spark技术生态中的核心。

基本工作原理

Spark StreamingSpark Core API的一种扩展, 它可以用于进行大规模、 高吞吐量、容错的实时数据流的处理。 它支持从很多种数据源中读取数据, 比如KafkaFlumeTwitterZeroMQKinesis或者是TCP Socket。 并且能够使用类似高阶函数的复杂算法来进行数据处理, 比如mapreducejoinwindow。 处理后的数据可以被保存到文件系统、 数据库、 Dashboard等存储中.

Spark Streaming内部的基本工作原理如下: 接收实时输入数据流 然后将数据拆分成多个batch()比如每收集1秒的数据封装为一个batch, 然后将每个batch交给Spark的计算引擎进行处理, 最后会生产出一个结果数据流, 其中的数据, 也是由一个一个的batch所组成的。

DStream

(Discretized Stream)离散流.代表一个持续不断的数据流.

DStream可以通过输入数据源来创建, 比如KafkaFlumeKinesis; 也可以通过对其他DStream应用高阶函数来创建, 比如mapreducejoinwindow

DStream的内部, 其实一系列持续不断产生的RDD RDDSpark Core的核心抽象,即不可变的, 分布式的数据集。 DStream中的每个RDD都包含了一个时间段内的数据

DStream应用的算子, 比如map, 其实在底层会被翻译为对DStream中每个RDD的操作。比如对一个DStream执行一个map操作, 会产生一个新的DStream 但是, 在底层, 其原理为, 对输入DStream中每个时间段的RDD, 都应用一遍map操作, 然后生成的新的RDD,即作为新的DStream中的那个时间段的一个RDD 底层的RDDtransformation操作, 其实,还是由Spark Core的计算引擎来实现的。 Spark StreamingSpark Core进行了一层封装, 隐藏了细节, 然后对开发人员提供了方便易用的高层次的API

案例:

yum install nc

【扩展】:http://blog.csdn.net/xifeijian/article/details/9348277

nc -lk 9999

[不断的输入数据就好....停止的时候ctrl+c]

package Demo01

import org.apache.spark.SparkConf

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

/**

  * Created by yxy on 2/6/17.

  * 基于socket 的实时流处理

  */

object wordcountbysocket {

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

    /**

      * sparkstreaming 至少需要两个线程,一个线程用于接受输入的数据流,一个用来处理数据流.

      */

    val conf=new SparkConf().setAppName("wordcount").setMaster("local[2]")

    val ssc=new StreamingContext(conf,Seconds(5))

    //创建StreamingContext仍然离不开sparkContext,因为他是用户与spark集群进行交互的唯一接口.

    //在源码中,创建StreamingContext对象时,Spark自动创建了一个SparkContext对象

    val lines=ssc.socketTextStream("hadoop01",9999) //nc服务器获取数据

    val resulet=lines.flatMap(_.split(" ")) //wordcount for stream

      .map(word=>(word,1))

      .reduceByKey(_+_)

    //此处的result是一个DStream,不是RDD.

    resulet.print()   //input

    

    ssc.start() //start

    ssc.awaitTermination() //wait kill

  }

}

Spark Streaming 相关核心类

1. DStreamdiscretized stream

Spark Streaming 提供了对数据流的抽象, 它就是 DStream, 它可以通过前述的Kafka, Flume 等数据源创建, DStream 本质上是由一系列的 RDD 构成。 各个 RDD中的数据为对应时间间隔(interval) 中流入的数据,

DStream 的所有操作最终都要转换为对 RDD 的操作

2.StreamingContext

Spark Streaming 当中, StreamingContext 是整个程序的入口 其创建方式有多
种, 最常用的是通过 SparkConf 来创建 

也就是说 StreamingContext 是对 SparkContext 的封装, 

创建 StreamingContext 时会指定 batchDuration 它用于设定批处理时间间隔, 需要根据应用程序和集群资源情况去设定。

[额...一些版本来说,时间间隔最小是0.5s,新的版本可能改善了]

当创建完成 StreamingContext 之后, 再按下列步骤进行:

Ø 通过输入源创建 InputDStreaim

Ø  DStreaming 进行 transformation 和 output 操作, 这样操作构成了后期流式计算的逻辑

Ø 通过 StreamingContext.start()方法启动接收和处理数据的流程

Ø 使用 streamingContext.awaitTermination()方法等待程序处理结束( 手动停止或出错停)

 

也可以调用 streamingContext.stop()方法结束程序的运行

关于 StreamingContext 注意点:

 

1.StreamingContext 启动后,增加新的操作将不起作用。 也就是说在StreamingContext 启动之前, 要定义好所有的计算逻辑.

2.StreamingContext 停止后不能重新启动 也就是说要重新计算的话,需要重新运行整个程序。

3.在单个 JVM 中,一段时间内不能出现两个active 状态的 StreamingContext

4.调用 StreamingContext 的stop方法时SparkContext 也将被 stop 掉,如果希望StreamingContext 关闭时,保留 SparkContext,则需要在 stop 方法中传入参数

5.SparkContext 对象可以被多个 StreamingContexts 重复使用,但需要前一个StreamingContexts 停止后再创建下一个 StreamingContext 对象。

 

 

3.InputDStreams Receivers

 

InputDStream 指的是从数据流的源头接受的输入数据流 在前面的StreamingWordCount 程序当中, val lines = ssc.textFileStream(args(0)) 就是一种InputDStream。 除文件流外, 每个 input DStream 都关联一个 Receiver 对象 Receiver 对象接收数据源传来的数据并将其保存在内存中以便后期 Spark 处理。

Spark Streaimg 提供两种原生支持的流数据源:

1.Basic sources( 基础流数据源)  直接通过 StreamingContext API 创建, 例如文件

系统( 本地文件系统及分布式文件系统) Socket 连接及 Akka 的 Actor。

2.文件流( File Streams) 的创建方式:

i. streamingContext.fileStreamKeyClass, ValueClass, InputFormatClass

ii. streamingContext.textFileStream(dataDirectory)

 

 

基础核心概念详细

1.StreamingContext创建:

有两种创建StreamingContext的方式:

val conf = new SparkConf().setAppName(appName).setMaster(master);

val ssc = new StreamingContext(conf, Seconds(1));

StreamingContext还可以使用已有的SparkContext来创建

val sc = new SparkContext(conf)

val ssc = new StreamingContext(sc, Seconds(1))

appName, 是用来在Spark UI上显示的应用名称。 master, 是一个SparkMesos或者Yarn集群

URL 或者是local[*]

 

 

 

一个StreamingContext定义之后, 必须做以下几件事情

1、 通过创建输入DStream来创建输入数据源。

2、 通过对DStream定义transformationoutput算子操作, 来定义实时计算逻辑。

3、 调用StreamingContextstart()方法, 来开始实时处理数据。

4、 调用StreamingContextawaitTermination()方法, 来等待应用程序的终止。 可以使用CTRL+C手动停止,

或者就是让它持续不断的运行进行计算。

5、 也可以通过调用StreamingContextstop()方法, 来停止应用程序。

需要注意的要点:

1、 只要一个StreamingContext启动之后, 就不能再往其中添加任何计算逻辑了。 比如执行start()方法之后, 还

给某个DStream执行一个算子。

2、 一个StreamingContext停止之后, 是肯定不能够重启的。 调用stop()之后, 不能再调用start()

3、 一个JVM同时只能有一个StreamingContext启动。 在你的应用程序中, 不能创建两个StreamingContext

4、 调用stop()方法时,会同时停止内部的SparkContext, 如果不希望如此,还希望后面继续使用SparkContext

创建其他类型的Context 比如SQLContext那么就用stop(false)

5、 一个SparkContext可以创建多个StreamingContext, 只要上一个先用stop(false)停止, 再创建下一个即可。

 

2.输入DStreamReceiver:

输入DStream代表了来自数据源的输入数据流。 在之前的wordcount例子中, lines就是一个输入DStreamJavaReceiverInputDStream) , 代表了从netcatnc) 服务接收到的数据流。 除了文件数据流之外, 所有的输入DStream都会绑定一个Receiver象, 该对象是一个关键的组件,用来从数据源接收数据 并将其存储在Spark的内存中, 以供后续处理

Spark Streaming提供了三种内置的数据源支持

1基础数据源 StreamingContext API中直接提供了对这些数据源的支持, 比如文件、 socketAkka Actor等。

2高级数据源: 诸如KafkaFlumeKinesisTwitter等数据源, 通过第三方工具类提供支持。这些数据源的使用, 需要引用其依赖。

3 自定义数据源 我们可以自己定义数据源, 来决定如何接受和存储数据。

 

 

如果你想要在实时计算应用中并行接收多条数据流, 可以创建多个输入DStream。 这样就会创建多个

Receiver, 从而并行地接收多个数据流。 但是要注意的是, 一个Spark Streaming ApplicationExecutor, 是一个长时间运行的任务, 因此, 它会独占分配给Spark Streaming Applicationcpu core。从而只要Spark Streaming运行起来以后, 这个节点上的cpu core, 就没法给其他应用使用了。

 

使用本地模式, 运行程序时, 绝对不能用local或者local[1], 因为那样的话, 只会给执行输入DStream

executor分配一个线程。 而Spark Streaming底层的原理是, 至少要有两条线程, 一条线程用来分配给

Receiver接收数据, 一条线程用来处理接收到的数据。 因此必须使用local[n]n>=2的模式。

 

如果不设置Master, 也就是直接将Spark Streaming应用提交到集群上运行, 那么首先, 必须要求集群节点上, 有>1cpu core, 其次, 给Spark Streaming的每个executor分配的core, 必须>1, 这样, 才能保证分配到executor上运行的输入DStream, 两条线程并行, 一条运行Receiver, 接收数据; 一条处理数据。 否则的话, 只会接收数据, 不会处理数据。

 

HDFS实时流处理案例

DStreamtransformation

Transformation

Meaning

map(func)

对 DStream 中的各个元素进行 func 函数操作, 然后返回一个新的 DStream.

flatMap(func)

与 map 方法类似, 只不过各个输入项可以被输出为零个或多个输出项

filter(func)

过滤出所有函数 func 返回值为 true 的 DStream 元素并返回一个新的 DStream

repartition(numPartitions)

增加或减少 DStream 中的分区数, 从而改变 DStream 的并行度

union(otherStream)

将源 DStream 和输入参数为 otherDStream 的元素合并,
并返回一个新的 DStream.

count()

通过对 DStreaim 中的各个 RDD 中的元素进行计数, 然后返回只有一个元素
的 RDD 构成的 DStream

reduce(func)

对源 DStream 中的各个 RDD 中的元素利用 func 进行聚合操作,
然后返回只有一个元素的 RDD 构成的新的 DStream.

countByValue()

对于元素类型为 K 的 DStream, 返回一个元素为( K,Long) 键值对形式的
新的 DStream, Long 对应的值为源 DStream 中各个 RDD 的 key 出现的次数

reduceByKey(func,
[numTasks])

利用 func 函数对源 DStream 中的 key 进行聚合操作, 然后返回新的( K, V) 对
构成的 DStream

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,可以是任意的 RDD 操作, 从而返回一个新的 RDD

updateStateByKey(func)

根据于 key 的前置状态和 key 的新值, 对 key 进行更新,
返回一个新状态的 DStream

window

对滑动窗口数据执行操作

案例:updateStateBykey

updateStateByKey操作, 可以让我们为每个key维护一份state, 并持续不断的更新该state

1、 首先, 要定义一个state, 可以是任意的数据类型;

2、 其次, 要定义state更新函数——指定一个函数如何使用之前的state和新值来更新state

对于每个batch Spark都会为每个之前已经存在的key去应用一次state更新函数,无论这个keybatch中是否有新的数据。 如果state更新函数返回none, 那么key对应的state就会被删除。

当然, 对于每个新出现的key, 也会执行state更新函数。

updateStateByKey操作, 要求必须开启Checkpoint机制。

ransform操作, 应用在DStream上时, 可以用于执行任意的RDDRDD的转换操作。 它

可以用于实现, DStream API中所没有提供的操作。 比如说, DStream API中, 并没有提

供将一个DStream中的每个batch, 与一个特定的RDD进行join的操作。 但是我们自己就

可以使用transform操作来实现该功能。

DStream.join(), 只能join其他DStream。 在DStream每个batchRDD计算出来之后, 会

去跟其他DStreamRDD进行join

案例: 广告计费日志实时黑名单过滤

package Demo01

import org.apache.spark.SparkConf

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

/**

  * Created by yxy on 2/6/17.

  */

object adFilter {

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

    val conf=new SparkConf().setAppName("AdFilterDEmo").setMaster("local[2]")

    val ssc=new StreamingContext(conf,Seconds(10))

    //设置黑名单数据

    val blackRDD=ssc.sparkContext.parallelize(Array(("Tom",true)))

    val linesDStream=ssc.socketTextStream("hadoop01",9999)

    //nc服务器获取数据,数据格式如下:

    //编号 姓名

    val mapDStream=linesDStream.map(line=>{

      val info=line.split(" ")

      (info(1),info) //(name,id name)

    })

    //使用transform算子进行转换操作

   val result=mapDStream.transform(dataRDD=>{

      val joinRDD=dataRDD.leftOuterJoin(blackRDD)

      val filterRDD=joinRDD.filter(m=>{

        if(m._2._2.getOrElse(false)) false else true

      })

      filterRDD.map(m=>{

        m._2._1

      })

    }) //显示输出不是黑名单的用户信息

    result.print()

    ssc.start()

    ssc.awaitTermination()

  }

}

猜你喜欢

转载自blog.csdn.net/qq_30901367/article/details/54915151