SparkStreaming

SparkSreaming

1.0 概述

1.1-1.2 相关概念

离线和实时 批量和流式

1.3 spark streaming是什么

  1. spark streaming 用于流式数据的处理
  2. 处理的时候不是单条的处理而是一批一批来处理
  3. 有采集周期|批处理间隔的概念,决定和作业的频率和数据处理的延迟,同时也影响着数据处理的吞吐量的性能
  4. input data stream => Spark Streaming => batches of input data => Spark Engine =>batches of processed data
  5. 好好理解Dstream的概念:一个周期里的也是用Dstream来封装RDD

1.4 Spark Streaming的特点

优点:易用 容错 易整合
缺点:"微量批处理"的架构,延迟会相对高一些

1.5 Spark Streaming架构

  1. 程序入口 StreamingContext,也是封装了SparkContext,至少需要两个executor
  2. 单独来一个executor来接收数据 “Zero Copy”
  3. 不是一次运行就结束了,而是每一个采集周期就处理一次
  • 遇到采集快,处理慢的情况怎么办
  1. Spark1.5版本以前可以限速采集器,1.5以后采用背压机制;就可以不用限速了,不然即使开了backpressure也不会超过限速的.

2.0 DStream入门

2.1 WordCount案例实操

object Spark01_WOrdCount{
	def main(args:Array[String]):Unit={
		//创建SparkConf配置文件对象
		//至少需要2个线程local[2]
		val conf = new SparkConf().setMaster("local[*]").setAppName("111")

		//创建SparkSteaming的执行入口
		 val ssc = new StramingContext(conf,Seconds(3))

		//读取指定端口号的数据,并且数据是以流的形式,源源不断的过来
		val lineDS : ReceiverInputDSteam[String] = ssc.socketTextStream("hadoop102",9999)

		//对当前的一行数据进行扁平映射
		val faltMapDS = lineDS.flatMap(_.split(" "))

		//对数据进行结构的转换
		val mapDS=flatMapDS.map((_,1))

		//对单词出现的次数 进行计数
		val reduceDS = mapDS.reduceByKey(_+_)

		
		reduceDS.print()

		//开始采集
		ssc.start()

		//释放资源 默认情况下不使用 因为我们要实时的不间断的采集数据,所以不能调用Stop方法结束StreamingCont ext
		//让采集线程一直执行
		ssc.awaitTermination()
	}
}
  • 最小化安装要再安装一下netcat,使用命令sudo yum install -y nc

2.2 WordCount解析

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

2.3 几点注意

  1. 一旦StreamingContext已经启动,则不能再添加新的Streaming Computation
  2. 一旦一个StreamingContext已经停止(sc.stop()),那么它也不能再重启
  3. 在一个JVM内,同一时间只能启动一个StreamingContext
  4. stop()的方式停止StreamingContext,也会把SparkContext停掉.如果仅仅想停止StreamingContext,则应该这样:stop(false) 一般不会这么去使用
  5. 一个SparkContext可以重用去创建多个StreamingContext,前提是以前的StreamingContext已经停掉,并且SparkContext没有被停掉

3.0 DStream创建

3.1 RDD队列(了解)

object Spark02_Create_RDDQueue{
	def main(args:Array[String]):Unit={
		//创建SparkConf配置文件对象
		//至少需要2个线程local[2]
		val conf = new SparkConf().setMaster("local[*]").setAppName("111")

		//创建SparkSteaming的执行入口
		 val ssc = new StramingContext(conf,Seconds(3))

		//创建RDD队列
		var queue : mutable.Queue = new mutable.Queue[RDD[Int]]()

		//创建离散化流(第二个参数oneAtTime:是否一个周期只处理一个RDD,默认为true)
		val queueDS = ssc.queueStream(queue,false)

		//对采集到的DS的数据进行操作
		queueDS.map((_,1)).reduceByKey(_+_).print



		//开启采集数据的线程
		ssc.start()

		//向队列中放数据
		for(i<- 1 to 5){
			//通过ssc获取sparkContext,创建RDD,并将创建好的RD放到RDD队列中
			queue.enqueue(  ssc.sparkContext.makeRDD(1 to 5))
			Thread.sleep(2000)
		}




		ssc.awaitTermination()


}

3.2 自定义数据源

看视频09_自定义数据源

object Spark03_Create_Customer {
  def main(args: Array[String]): Unit = {
    //1.创建Spark配置文件对象
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("sparkDemo")

    //2.创建Streaming程序执行的入口
    val ssc: StreamingContext = new StreamingContext(conf,Seconds(3))

    //自定义数据源    创建DStream
    val lineDS: ReceiverInputDStream[String] = ssc.receiverStream(new MyReceiver("hadoop202",9999))

    lineDS
      .flatMap(_.split(" "))
      .map((_,1))
      .reduceByKey(_+_)
      .print()

    //开始采集
    ssc.start()

    ssc.awaitTermination()

  }
}

class MyReceiver(host: String,port: Int) extends Receiver[String](StorageLevel.MEMORY_ONLY){

  private var socket: Socket = _

  override def onStart(): Unit = {
    try {
      socket = new Socket(host, port)
    } catch {
      case e: ConnectException =>
        restart(s"Error connecting to $host:$port", e)
        return
    }

    new Thread("Socket Receiver") {
      setDaemon(true)
      override def run(): Unit = { receive() }
    }.start()
  }

  def receive(): Unit = {
    //读取指定端口的数据
    val bf = new BufferedReader(new InputStreamReader(socket.getInputStream,StandardCharsets.UTF_8))

    //定义一个变量,存储读取到的一行的数据
    var line:String = null

    while((line=bf.readLine())!=null){
      //调用store方法,将读到的数据进行缓存
      store(line)
    }

  }
  override def onStop(): Unit = {
    synchronized {
      if (socket != null) {
        socket.close()
        socket = null
      }
    }
  }
}

3.3 Kafka数据源(面试开发重点)

  • Spark-streaming-kafka-0-8 从spark2.30开始就过时了,在Spark3.0已经删除了,原因:还是因为接收和计算的数据速度不同,会导致计算数据的节点内存溢出
    -现在用的是Spark-streaming-kafka-0-10

3.3.2 Kafka 0-10 Direct模式

//从Kafka中读取数据 ,创建DStream

object Spark04_Create_Kafka {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf
    val conf: SparkConf = new SparkConf().setAppName("DirectAPI010").setMaster("local[*]")

    //2.创建StreamingContext
    val ssc = new StreamingContext(conf, Seconds(3))

    //构建Kafka参数
    val kafkaParmas: Map[String, Object] = Map[String, Object](
      ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG -> "hadoop102:9092,hadoop103:9092,hadoop104:9092",
      ConsumerConfig.GROUP_ID_CONFIG -> "myGroup",
      //ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG -> "org.apache.kafka.common.serialization.StringDeserializer",
      ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG -> classOf[StringDeserializer]
    )

    //读取Kafka数据,创建Dstream
    val kafkaDS: InputDStream[ConsumerRecord[String, String]] = KafkaUtils.createDirectStream(
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](Set("bigdata0317"), kafkaParmas)
    )

    kafkaDS
      .map(_.value())
      .flatMap(_.split(" "))
      .map((_,1))
      .reduceByKey(_+_)
      .print()

    ssc.start()

    ssc.awaitTermination()
  }
}

看视频11 主要还是了解0-8

kafka常用命令:

<!-- 查询topic -->
bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --list

<!-- 创建topic -->
bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --create --replication-factor 1 --partitions 3 --topic bigdata0317

<!-- 删除topic -->
bin/Kafka-topics.sh --bootstrap-server hadoop102:9092 --delete --topic bigdata0317

<!-- 查看topic情况 -->
bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --describe --topic first

<!-- 生产数据 -->
bin/kafka-console-producer.sh --broker-list hadoop102:9092 --topic first

<!-- 消费数据 -->
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first

3.3.3 消费Kafka数据模式总结

  1. “0-8 ReceiverAPI”:
  • 专门的Executor读取数据,速度不统一
  • 跨机器传输数据,WAL
  • Executor读取数据通过多个线程的方式,想要增加并行度,则需要多个流union
  • offset存储在Zookeeper中
  1. “0-8 DirectAPI”:
  • Executor读取数据并计算
  • 增加Executor个数来增加消费的并行度
  • offset存储(
    CheckPoint(getActiveOrCreate方式创建StreamingContext)
    手动维护(有事务的存储系统)
    获取offset必须在第一个调用的算子中:offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
    )
  1. “0-10 DirectAPI”:
  • Executor读取数据并计算
  • 增加Executor个数来增加消费的并行度
  • offset存储(
    _consumer_offsets系统主题中
    手动维护(有事务的存储系统)
    )

今日重点:理解DStream 看看Spark-Kafka-0-8


4.0 DStream转换

  • DStream上的操作与RDD的类似,分为Transformations(转换)和Output Operations(输出)两种。相当于RDD的转换算子和行动算子.
  • 此外转换操作中还有一些比较特殊的算子,如:updateStateByKey()、transform()以及各种Window相关的算子。

4.1 无状态转化操作

  • 无状态转化操作就是把简单的RDD转化操作应用到每个批次上,也就是转化DStream中的每一个RDD。(不会把上一个RDD的状态(结果)延续到下一个RDD)

4.1.1 Transform

  • 对DStream中的RDD应用转换
object Spark01_Transform {
  def main(args: Array[String]): Unit = {
    //创建SparkConf
    val conf: SparkConf = new SparkConf().setAppName("DirectAPI010").setMaster("local[*]")

    //创建StreamingContext
    val ssc = new StreamingContext(conf, Seconds(3))

    //从指定的端口读取数据
    val lineDS : ReceiverInputDSteam[String] = ssc.socketTextStream("hadoop102",9999)

    //转换成RDD
    val resDS=lineDS.transform(
        rdd=>{
          val sortRDD = rdd
          .flatMap(_.split(" "))
          .map((_,1))
          .reduceByKey(_+_)
          .sortByKey()

          sortRDD
        }
      )

      resDS.print()

      //开始采集数据
      ssc.strat()
      ssc.awaitTermination()

4.2 有状态转化操作

4.2.1 UpdateStateByKey

object Spark01_UpdateStateByKey {
  def main(args: Array[String]): Unit = {
    //创建SparkConf
    val conf: SparkConf = new SparkConf().setAppName("DirectAPI010").setMaster("local[*]")

    //创建StreamingContext
    val ssc = new StreamingContext(conf, Seconds(3))

    //设置检查点的目录,用于保存上一个周期的状态


    //从指定的端口读取数据
    val lineDS : ReceiverInputDSteam[String] = ssc.socketTextStream("hadoop102",9999)

    val mapDS= lineDS.faltMap(_.split(" ")).map((_,1))

    //reduceByKey只能聚合一个周期内的数据,不传递到下一个周期
    //UpdateStateByKey可以记录上一个采集周期的状态与当前的采集周期数据进行聚合
    val resDS=mapDS.updateStateByKey(
        (seq:Seq[Int],state:Option[Int])=>{
          Option(state.getOrElse(0)+seq.sum)
        }
      )

      resDS.print()

      //开始采集数据
      ssc.strat()
      ssc.awaitTermination()

4.2.2 Window Operations(窗口操作)

  • 有点像是滑窗
  • 所有的窗口操作都需要两个参数:窗口时长和滑动步长:都是周期的整数倍

需求:WordCount统计3秒一个批次,滑动窗口6秒

object Spark03_wordCount {
  def main(args: Array[String]): Unit = {
    //创建SparkConf
    val conf: SparkConf = new SparkConf().setAppName("DirectAPI010").setMaster("local[*]")

    //创建StreamingContext
    val ssc = new StreamingContext(conf, Seconds(3))


    //从指定的端口读取数据
    val lineDS : ReceiverInputDSteam[String] = ssc.socketTextStream("hadoop102",9999)


 

      resDS.print()

      //开始采集数据
      ssc.strat()
      ssc.awaitTermination()

4.2.3 关于Window的操作还有如下的方法:

要看看,有点不清晰,晚上也要练习

  1. window(windowLength, slideInterval)
  • 基于对源DStream窗化的批次进行计算返回一个新的Dstream
  1. countByWindow(windowLength, slideInterval)
  • 返回一个滑动窗口计数流中的元素个数
  1. countByValueAndWindow()
  • 返回的DStream则包含窗口中每个值的个数
  1. reduceByWindow(func, windowLength, slideInterval)
  • 通过使用自定义函数整合滑动区间流元素来创建一个新的单元素流
  1. reduceByKeyAndWindow(func, windowLength, slideInterval, [numTasks])
  • 当在一个(K,V)对的DStream上调用此函数,会返回一个新(K,V)对的DStream,此处通过对滑动窗口中批次数据使用reduce函数来整合每个key的value值
  1. reduceByKeyAndWindow(func, invFunc, windowLength, slideInterval, [numTasks])
  • 这个函数是上述函数的变化版本,每个窗口的reduce值都是通过用前一个窗的reduce值来递增计算。通过reduce进入到滑动窗口数据并”反向reduce”离开窗口的旧数据来实现这个操作。如果把3秒的时间窗口当成一个池塘,池塘每一秒都会有鱼游进或者游出,那么第一个函数表示每由进来一条鱼,就在该类鱼的数量上累加。而第二个函数是,每游出去一条鱼,就将该鱼的总数减去一。

5.0 DStream输出

5.1 常用输出操作

  1. print() 主要用于开发测试
  2. saveAsTextFiles(prefix, [suffix])
  3. saveAsObjectFiles(prefix, [suffix])
  4. saveAsHadoopFiles(prefix, [suffix])
  5. foreachRDD(func) 较为常用的输出,功能和transform类似,不过是行动算子

6.0 DStream编程进阶

6.1 累加器和广播变量

  • 和RDD中的操作一样

6.2 DataFrame and SQL Operations

  • 可以以SQL表格的形式输出

6.3 Caching/Persistence

  • 和RDD类似cache和persit

7.0 Spark Streaming项目实战

kafka有问题该怎么办:

1. 删除zookeeper中的kafka/brokers/ids
2. 删除zookeeper中的kafka目录
3. 删除kafka中 meta.proprety中的broker.ids
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值