关于SparkStreaming的DStream原理以及代码详解

1. 什么是DStream

  • Discretized Stream是Spark Streaming的基础抽象,代表持续性的数据流和经过各种Spark算子操作后的结果数据流。

  • 内部实现上,DStream是一系列连续的RDD来表示。每个RDD含有一段时间间隔内的数据
    在这里插入图片描述

  • 工作流程图如下: 接受到实时数据后,给数据分批次,然后传给Spark Engine处理最后生成该批次的结果
    在这里插入图片描述

2. DStream相关的算子汇总

  • 转换函数【Transformation转换算子】: 将一个DStream转换为另外一个DStream
    在这里插入图片描述
  • 注意:
  • 1-SparkStreaming的Transformation算子比较有限,但是有的时候仍然需要使用
    • 比如,需要对wordcount的结果进行排序,这里没有sortBy或sortByKey的算子
    • 所以,借助于tranform的方法将DStream的数据转化成RDD进行操作

在这里插入图片描述

  • 输出函数【Output Operations行动算子】: 将一个DStream输出到外部存储系统
    在这里插入图片描述

在SparkStreaming企业实际开发中,建议:能对RDD操作的就不要对DStream操作,当调用DStream中某个函数在RDD中也存在,使用针对RDD操作。

3. StreamingContext对象

  • 1)、SparkCore
    数据结构:RDD
    SparkContext:上下文实例对象
  • 2)、SparkSQL
    数据结构:Dataset/DataFrame = RDD + Schema
    SparkSession:会话实例对象, 在Spark 1.x中SQLContext/HiveContext
  • 3)、SparkStreaming
    数据结构:DStream = Seq[RDD]
    StreamingContext:流式上下文实例对象, 底层还是SparkContext
    参数:划分流式数据时间间隔BatchInterval:1s,5s(演示)

4. DStream算子实现wordcount实时计算案例

模拟TCP socket实现简单的实时计算wordcount

import org.apache.spark.streaming.dstream.{
    
    DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{
    
    Seconds, StreamingContext}
import org.apache.spark.{
    
    SparkConf, SparkContext}

/**
 * @author liu a fu
 * @date 2021/1/20 0020
 * @version 1.0
 * @DESC   第一个SparkStreaming wordcount案例    不会累加(称之为无状态计算)
 *
 * 1-首先声明StreamingContext申请资源,进入调用sparkContext
 * 2-这里从socket接受数据,从node1节点下安装nc服务,使用nc -lk 9999端口发送数据**
 * 3-将接受到的数据进行Tranformation转换
 * 4-使用OutPutOpration操作输出结果
 * 5-开启start,streamingcontext.start开启接受数据
 * 6-指导StreamingContext.awaitTermination停止
 * 7-StreamingContext.stop
 */

object _01StreamingCompution {
    
    
  def main(args: Array[String]): Unit = {
    
    
    //1-首先声明StreamingContext申请资源,进入调用sparkContext
    val conf: SparkConf = new SparkConf()
      .setMaster("local[8]")
      .setAppName(this.getClass.getSimpleName.stripSuffix("$"))

    val sc = new SparkContext(conf)
    val ssc = new StreamingContext(sc, Seconds(5))  //每经过5秒处理一次数据
    sc.setLogLevel("WARN")

    //2-这里从socket接受数据,从node1节点下安装nc服务,使用nc -lk 9999端口发送数据
    val receiveDS: ReceiverInputDStream[String] = ssc.socketTextStream("node1", 9999) //指定主机和端口
    
    //3-将接受到的数据进行Tranformation转换
    val resultDS: DStream[(String, Int)] = receiveDS
      .flatMap(_.split("\\s+"))
      .map((_, 1))
      .reduceByKey(_ + _)

    //4-使用OutPutOpration操作输出结果-----------print属于类似于action算子的
    resultDS.print()
    //5-开启start,streamingcontext.start开启接受数据
    ssc.start() //Start the execution of the streams.
    //6-指导StreamingContext.awaitTermination停止,有任何的异常都会触发停止
    ssc.awaitTermination()
    //7-StreamingContext.stop
    ssc.stop()
  }
}

在这里插入图片描述

模拟TCP 实现排序(transform转换算子 + sortBy实现)

import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.dstream.{
    
    DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{
    
    Seconds, StreamingContext}
import org.apache.spark.{
    
    SparkConf, SparkContext}

/**
 * @author liu a fu
 * @date 2021/1/20 0020
 * @version 1.0
 * @DESC   实现wordcount统计后的排序输出
 */
object _02SreamingCompution {
    
    
  def main(args: Array[String]): Unit = {
    
    
    //1-首先声明StreamingContext申请资源,进入调用sparkContext
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName.stripSuffix("$")).setMaster("local[3]")
    val sc = new SparkContext(conf)
    val scc = new StreamingContext(sc, Seconds(5))
    sc.setLogLevel("WARN")

    //2-这里从socket接收数据
    val reviceDS: ReceiverInputDStream[String] = scc.socketTextStream("node1", 9999)

    //3-将接收的数据进行Tranformation转换
    val resultDS: DStream[(String, Int)] = reviceDS
      .flatMap(_.split("\\s+"))
      .map((_, 1))
      .reduceByKey(_ + _)
    //实现排序操作
    val output: DStream[(String, Int)] = resultDS.transform(iter => {
    
    
      val valueRDD: RDD[(String, Int)] = iter.sortBy(_._2, false)   //按照第二个进行排序  value
      valueRDD
    })

    //4-使用OutPutOpration操作输出结果-----------print属于类似于action算子的
    output.print()

    //5-开启start,streamingcontext.start开启接受数据
    scc.start()
    scc.awaitTermination()
    scc.stop()

  }

}

在这里插入图片描述
TCP 实现有状态 累加(updateStateByKey算子 定义方法)

import org.apache.spark.streaming.dstream.{
    
    DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{
    
    Seconds, StreamingContext}
import org.apache.spark.{
    
    SparkConf, SparkContext}

/**
 * @author liu a fu
 * @date 2021/1/20 0020
 * @version 1.0
 * @DESC  SparkStreaming wordcount案例    会累加(称之为有状态计算)
 */
object _03StreamingComput {
    
    

  /**
   * 这里自己定义的一个方法用于累加 和 判断历史值是否存在
   * @param currentValue 这里是当前的值,需要是用sum累加
   * @param historyValue 这里是历史的值,判断历史的值是否存在,如果存在直接使用,如果不存在赋值为0
   * @return
   */
  def updateFunc(currentValue:Seq[Int],historyValue:Option[Int]):Option[Int] = {
    
    
      val  addSum = currentValue.sum + historyValue.getOrElse(0)
      Option(addSum)
  }

  def main(args: Array[String]): Unit = {
    
    
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName.stripSuffix("$")).setMaster("local[5]")
    val sc = new SparkContext(conf)
    val scc = new StreamingContext(sc, Seconds(5))
    sc.setLogLevel("WARN")
    scc.checkpoint("data/checkpoint/check001")

    2-这里从socket接受数据,从node1节点下安装nc服务,使用nc -lk 9999端口发送数据
    val reviceDS: ReceiverInputDStream[String] = scc.socketTextStream("node1", 9999)
    //3-将接受到的数据进行Tranformation转换
    val resultDS: DStream[(String, Int)] = reviceDS
      .flatMap(_.split("\\s+"))
      .map((_, 1))
      .updateStateByKey(updateFunc)

    //4-使用OutPutOpration操作输出结果-----------print属于类似于action算子的
    resultDS.print()
    //5-开启start,streamingcontext.start开启接受数据
    scc.start()  //Start the execution of the streams.
    //6-指导StreamingContext.awaitTermination停止,有任何的异常都会触发停止
    scc.awaitTermination()
    scc.stop()


  }
}

在这里插入图片描述

5. 应用的监控界面

运行上述词频统计案例,登录到WEB UI监控页面:http://localhost:4040,查看相关监控信息。

扫描二维码关注公众号,回复: 12166712 查看本文章
  • 其一、Streaming流式应用概要信息
    在这里插入图片描述
    每批次Batch数据处理总时间TD = 批次调度延迟时间SD + 批次数据处理时间PT。
    在这里插入图片描述

  • 性能衡量标准
    SparkStreaming实时处理数据性能标准:
    每批次数据处理时间TD <= BatchInterval每批次时间间隔
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_49834705/article/details/112902137