大数据——SparkStreaming学习笔记

Spark

一、SparkStreaming

​ Spark Streaming 用于流式数据的处理(准实时,微序列)。Spark Streaming 支持的数据输入源很多,例如:Kafka、 Flume、Twitter、ZeroMQ 和简单的 TCP 套接字等等。数据输入后可以用 Spark 的高度抽象原语,如:map、reduce、join、window 等进行运算。而结果也能保存在很多地方,如 HDFS,数据库等。
在这里插入图片描述

  • DStream 离散化流,discretized stream是随时间推移而收到的数据的序列。在内部,每个时间区间收到的数据都作为 RDD 存在,而 DStream 是由这些 RDD 所组成的序列(因此得名“离散化”)。所以 简单来将,DStream 就是对 RDD 在实时数据处理场景的一种封装。
  • 背压机制(即 Spark Streaming Backpressure),根据 JobScheduler 反馈作业的执行信息来动态调整 Receiver 数据接收率。即协调处理数据与接收数据的速率。
  • 处理流程

​ Discretized Stream 是 Spark Streaming 的基础抽象,代表持续性的数据流和经过各种 Spark 原语操作后的结果数据流。在内部实现上,DStream 是一系列连续的 RDD 来表示。每个 RDD 含有 一段时间间隔内的数据。
在这里插入图片描述

二、DStream创建

——RDD队列创建

测试过程中,可以通过使用 ssc.queueStream(queueOfRDDs)来创建 DStream,每一个推送到 这个队列中的 RDD,都会作为一个 DStream 处理。

//1.初始化 Spark 配置信息
val conf = new SparkConf().setMaster("local[*]").setAppName("RDDStream")
//2.初始化 SparkStreamingContext
val ssc = new StreamingContext(conf, Seconds(4))
//3.创建 RDD 队列
val rddQueue = new mutable.Queue[RDD[Int]]()
//4.创建 QueueInputDStream
val inputStream = ssc.queueStream(rddQueue,oneAtATime = false)
//5.处理队列中的 RDD 数据
val mappedStream = inputStream.map((_,1))
val reducedStream = mappedStream.reduceByKey(_ + _)
//6.打印结果
reducedStream.print()
//7.启动任务
ssc.start()
//8.循环创建并向 RDD 队列中放入 RDD
for (i <- 1 to 5) {
    rddQueue += ssc.sparkContext.makeRDD(1 to 300, 10)
    Thread.sleep(2000)
}
ssc.awaitTermination()

——自定义数据源

​ 需要继承 Receiver,并实现 onStart、onStop 方法来自定义数据源采集。

/**
自定义数据源
*/
class MyReceiver() extends Receiver[String](StorageLevel.MEMORY_ONLY) {
      private var flage = true
      //最初启动的时候,调用该方法,作用为:读数据并将数据发送给 Spark
      override def onStart(): Unit = {
        new Thread(new Runnable {
          override def run(): Unit = {
            while (flage) {
              val message = "采集的数据为:" + new Random().nextInt(10).toString()
              store(message)
              Thread.sleep(300)
            }
          }
        }).start()

      }
      override def onStop(): Unit =  {
        flage = false
      }
}

val message = sc.receiverStream(new MyReceiver())
message.print()
   

——Kafka数据源

ReceiverAPI(早期版本):需要一个专门的 Executor 去接收数据,然后发送给其他的 Executor 做计算。存在 的问题,接收数据的 Executor 和计算的 Executor 速度会有所不同,特别在接收数据的 Executor 速度大于计算的 Executor 速度,会导致计算数据的节点内存溢出。

DirectAPI:是由计算的 Executor 来主动消费 Kafka 的数据,速度由自身控制。

/** Kafka 0.10版本下的数据消费配置 */
//1.定义 Kafka 参数
val kafkaPara: Map[String, Object] = Map[String, Object](
    ArrowAssoc(BOOTSTRAP_SERVERS_CONFIG) ->
    "hadoop102:9092,hadoop103:9092,hadoop104:9092",
    GROUP_ID_CONFIG -> "5yw",
    "key.deserializer" ->
    "org.apache.kafka.common.serialization.StringDeserializer",
    "value.deserializer" ->
    "org.apache.kafka.common.serialization.StringDeserializer"
)
//2.读取 Kafka 数据创建 DStream
val kafkaDStream: InputDStream[ConsumerRecord[String, String]] =
KafkaUtils.createDirectStream[String, String](sc,                                             		    LocationStrategies.PreferConsistent,                                    ConsumerStrategies.Subscribe[String, String](Set("5yw"), kafkaPara))
//3.将每条消息的 KV 取出
val valueDStream: DStream[String] = kafkaDStream.map(record => record.value())
valueDStream.print()
三、DStream数据转换

​ DStream 上的操作与 RDD 的类似,分为 Transformations(转换)和 Output Operations(输出)两种,此外转换操作中还有一些比较特殊的原语,如:updateStateByKey()、transform()以及 各种 Window 相关的原语。注意:针对键值对的 DStream 转化操作(比如 reduceByKey())要添加 import StreamingContext._才能在 Scala 中使用

​ SparkStreaming是将一个流数据划分为一个个小时间段,每个时间段封装为一个RDD。无状态转化即不保存各采集周期的数据,各RDD间无关。有状态转化操作即保存采集周期的数据,RDD间相关。

——无状态转化操作

​ Transform 允许 DStream 上执行任意的 RDD-to-RDD 函数。即使这些函数并没有在 DStream 的 API 中暴露出来,通过该函数可以方便的扩展 Spark API。该函数每一批次调度一次。其实也就是对 DStream 中的 RDD 应用转换。

​ 使用transform,一来是因为DStream本身也对map等函数进行了封装,但是有些功能尚不完善,所以我们使用transform将其转化为RDD进行操作;二来是针对某些伴随RDD的输入所进行的周期性操作。

//创建 DStream
val lineDStream: ReceiverInputDStream[String] = ssc.socketTextStream("linux1", 9999)
//转换为 RDD 操作
val wordAndCountDStream: DStream[(String, Int)] = lineDStream.transform(rdd => 
{     
    //********************* 这里的代码会周期执行,即每进来一个RDD都会执行一次
 val words: RDD[String] = rdd.flatMap(_.split(" "))         
 val wordAndOne: RDD[(String, Int)] = words.map((_, 1))
 val value: RDD[(String, Int)] = wordAndOne.reduceByKey(_ + _)
 value
})
//打印
wordAndCountDStream.print

​ 两数据流间实现join操作。

//1.从端口获取数据创建流
val lineDStream1: ReceiverInputDStream[String] = ssc.socketTextStream("linux1", 9999)
val lineDStream2: ReceiverInputDStream[String] = ssc.socketTextStream("linux2", 8888)
//2.将两个流转换为 KV 类型
val wordToOneDStream: DStream[(String, Int)] = lineDStream1.flatMap(_.split(" ")).map((_, 1))
val wordToADStream: DStream[(String, String)] = lineDStream2.flatMap(_.split(" ")).map((_, "a"))
//3.流的 JOIN
val joinDStream: DStream[(String, (Int, String))] = wordToOneDStream.join(wordToADStream)

——有状态转化操作

  1. UpdateStateByKey()

​ UpdateStateByKey 原语用于记录历史记录,有时,我们需要在 DStream 中跨批次维护状态(例如流计算中累加 wordcount)。针对这种情况,updateStateByKey()为我们提供了对一个状态变量的访问,用于键值对形式的 DStream。

​ 给定一个由(键,事件)对构成的 DStream,并传递一个指定如何根据新的事件更新每个键对应状态的函数,它可以构建出一个新的DStream,其内部数据为(键,状态) 对。 updateStateByKey() 的结果会是一个新的 DStream,其内部的 RDD 序列是由每个时间区间对 应的(键,状态)对组成的。

​ updateStateByKey 操作使得我们可以在用新信息进行更新时保持任意的状态。为使用这个功 能,需要做下面两步: 1. 定义状态,状态可以是一个任意的数据类型。 2. 定义状态更新函数,用此函数阐明如何使用之前的状态和来自输入流的新值对状态进行更新。

    /**
     * 根据key对数据的状态进行更新
     * 传递两个参数
     * 第一个:表示相同的key的value数据
     * 第二个:表示缓冲区相同key的value数据,因为初始缓冲区可能没有数据,所以定义为Option[]
     *
     * 在wordCount中,加入现在缓冲区已经有(word, 3) (hello, 4)
     * 第一个参数表示新接收到的RDD的value(1),第二个参数表示为(3) (4) (根据不同key进行对应计算)
     * */
    val value2 = word2.updateStateByKey(
      (seq: Seq[Int], buf:Option[Int]) => {
        val newCount = buf.getOrElse(0) + seq.sum
        Option(newCount)
      }
    )
  1. WindowOperations()

​ 当我们希望对多个采集周期的数据进行分析,可以设置窗口。Window Operations 可以设置窗口的大小和滑动窗口的间隔来动态的获取当前 Streaming 的允许状态。所有基于窗口的操作都需要两个参数,分别为窗口时长以及滑动步长。

➢ 窗口时长:计算内容的时间范围

➢ 滑动步长:隔多久触发一次计算。

​ 允许我们每隔一段时间(sliding duration)对过去一个时间段内(window duration)的数据进行转换操作(tranformation)。slideDruation控制着窗口计算的频度,windowDuration控制着窗口计算的时间跨度。slideDruation和windowDuration都必须是batchInterval的整数倍。

    val line2 = sc.socketTextStream("localhost", 8083) //监听8082端口
    val word2 = line2.flatMap(_.split(" ")).map((_, 1))
    //窗口大小必须是采集周期的整数倍
    val window = word2.window(Seconds(6), Seconds(3))	//每隔三秒对过去六秒的数据进行获取
    window.reduceByKey(_+_).print()
四、DStream输出

​ 输出操作指定了对流数据经转化操作得到的数据所要执行的操作(例如把结果推入外部数据库或输出到屏幕上)。与 RDD 中的惰性求值类似,如果一个 DStream 及其派生出的 DStream 都没有被执行输出操作,那么这些 DStream 就都不会被求值。

方法作用
print()直接打印在控制台
saveAsTextFiles(prefix, [suffix])以text文件存储,每一批次文件名:prefix-Time_IN_MS[.suffix]
saveAsObjectFiles(prefix, [suffix])以 Java 对象序列化的方式将 Stream 中的数据保存为 SequenceFiles .
saveAsHadoopFiles(prefix, [suffix])将 Stream 中的数据保存为 Hadoop files
foreachRDD(rdd => {})参数func 应该实现将每一个 RDD 数据推送到外部系统,如将 RDD 存入文件或者通过网络将其写入数据库。注意:外部连接对象不应该为每一个RDD创建,参考SparkCore的foreachPartition方法
五、DStream关闭及数据恢复
//TODO 数据恢复
val sc = StreamingContext.getActiveOrCreate("cp", () => {
    val sparkconf = new SparkConf().setMaster("local[*]").setAppName("SparkStreamning")
    val sc = new StreamingContext(sparkconf, Seconds(3))
    sc
})
sc.checkpoint("cp")
//TODO 关闭
sc.start()
new Thread(new Runnable {
    override def run(): Unit = {
        val state: StreamingContextState = sc.getState		//获取当前streaming
        if (true) {     //这里应该是任务是否完成的判断,比如数据库是否读取完成
            if (state == StreamingContextState.ACTIVE) {    //只有检测当前sparkstreaming是激活的,才需要执行关闭操作
                sc.stop(stopSparkContext = true, stopGracefully = true)   //当执行关闭操作时,接收操作先关闭,等待已接收数据都处理完成后,整个关闭
                System.exit(0)    //线程关闭
            }
        }
    }
}).start()
sc.awaitTermination()

具体代码可以参考:
https://github.com/Ostrich5yw/java4BigData

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: KafkaSpark Streaming大数据领域中非常重要的技术,它们可以协同工作,实现实时数据处理和分析。Kafka是一个分布式的消息队列系统,可以高效地处理海量数据流,而Spark Streaming则是一个基于Spark的流处理框架,可以实现实时数据处理和分析。在学习KafkaSpark Streaming时,需要掌握它们的基本概念、原理和使用方法,以及如何将它们结合起来实现实时数据处理和分析。同时,还需要了解KafkaSpark Streaming的优缺点,以及如何优化它们的性能和可靠性。 ### 回答2: Kafka是一个高性能,可扩展的分布式消息系统。它通过将消息划分成一个或多个主题,然后将这些主题划分成一个或多个分区来进行实现。Kafka是由LinkedIn开发的,由Apache基金会进行管理。它的主要设计目标是支持分布式处理,如流处理和批处理等。Kafka通过使用Zookeeper来进行节点管理和故障转移,能够快速处理海量的数据。Kafka采用发布/订阅模式,支持多个消费者订阅同一个主题,每个消费者可以读取主题的所有分区数据,也可以选择读取其中的某个分区。 Spark Streaming是一个流处理框架,它能够利用Spark的分布式处理能力来对实时数据进行处理。Spark Streaming采用微批处理的方式,将实时数据流切片成一段一段的,并通过并行处理的方式进行计算。Spark Streaming的数据源可以是Kafka、Flume或者TCP sockets等。与Kafka相比,Spark Streaming更适合于需要进行实时计算的场景,例如:实时日志分析、实时推荐、实时风控等。同时,Spark Streaming还能够与Spark的批处理进行无缝对接,实现流处理与批处理的统一计算引擎。Spark Streaming支持机器学习、图计算等高级计算库,能够为用户提供更强大的计算能力。 学习KafkaSpark Streaming的过程中,需要掌握Java、Scala等编程语言基础知识,并具备分布式系统的相关知识。对于Kafka,需要了解其基本概念、架构、API等,理解消息系统、发布/订阅模式、分区等内容。对于Spark Streaming,需要掌握其基本概念、流式计算流程、数据源等,同时也要熟悉Spark的RDD、DataFrame等相关知识。在学习中,需要结合实际项目,进行代码实践和调试,同时不断学习、思考和总结,以加深对KafkaSpark Streaming的理解和应用。 ### 回答3: Kafka是由Apache SoftWare Foundation开发的一种分布式发布/订阅消息系统。其主要目的是为数据传输提供一种高吞吐量、低延迟的解决方案。Kafka提供了一种可靠的、持久化的、实时的数据传输方式,适用于众多的场景,如:日志收集、数据传输、消息系统等。 Kafka的特点: 1、高吞吐量:Kafka可以支持非常高的数据传输吞吐量,同时保持低延迟和高稳定性。 2、可扩展性:Kafka可以轻松扩展以适应更大的数据需求,并可以在运行时添加新的主题分区。 3、持久化:Kafka保证数据能够可靠地在分布式集群中传输,同时保证数据不会丢失或者被意外删除。 4、多样化的客户端:Kafka提供了多种语言的客户端接口,以满足不同的开发需求。 SparkStreaming 是由Apache Spark社区发展的一个实时数据处理框架。它用于将实时数据流分成小批处理,可以跨越不同的时间窗口进行计算。Spark Streaming提供了与Spark非常相似的编程模型,同时支持不同的输入源,包括社交媒体、传感器、消息队列等。 SparkStreaming的特点: 1、处理速度快:它可以支持毫秒级别的处理速度,并且可以在分布式系统中实现高吞吐量。 2、支持多种数据源:Spark Streaming可以从多种类型的数据源中读取数据,如HDFS、Flume、Kafka等。 3、编程简单:Spark Streaming提供了与Spark相似的编程模式,使得开发人员可以将Spark StreamingSpark整合在一起进行处理。 4、高容错性:Spark Streaming在分布式环境中实现了高可靠性和容错性,使得它可以支持大规模的实时数据处理需求。 总之,KafkaSpark Streaming这两个工具是在大数据处理领域中非常重要的工具。它们可以很好地相互结合,支持大规模的实时数据处理和分析,进而为企业提供更好更快的数据处理方案。如果你对这两个技术感兴趣,可以从官方文档和教程开始学习,逐步掌握它们的定义、特点、应用场景和基本使用方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ostrich5yw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值