Spark Streaming

Spark Streaming的简介和原理

Spark Streaming接收Kafka、Flume、HDFS等各种数据源的实时输入数据,进行处理后,将数据保存在HDFS、Database等地方。

Spark处理的是批量的数据(离线数据),Spark Streamings也是基于核心Spark的,Spark Streaming在内部的处理机制,接收实时的输入数据流,并根据一定的时间间隔拆分成一批批的数据,然后通过Spark Engine处理这些批数据,最终得到处理后的一批批结果数据。
在这里插入图片描述
Spark Streaming支持一个高度的抽象,叫做离散流或者DStream,它代表连续的数据流。
DStream既可以根据Kafka、Flume等数据源来获取输入数据流来创建,也可以在DStream的基础上通过高阶函数来获得。

在内部,DStream是由一系列的RDD组成的,一批数据在spark内核中对应一个RDD实例。因此,对应流的DStream可以看成一组RDD,即RDD的一个序列。

Spark Streaming的一些常用数据说明:

名称说明
离散流Spark Streaming对内部连续的实时数据流的抽象描述
时间片拆分流数据的时间单元
批数据一个时间片内所包含的流数据,表示一个RDD
窗口(Window)一个时间段,系统支持对一个窗口内的数据进行计算
窗口长度一个窗口所覆盖的流数据的时间长度,必须是批处理时间间隔的倍数
滑动步长前一个窗口到后一个窗口所经过的时间长度,必须是批处理时间间隔的倍数

transform(黑名单过滤)
spark Streaming的算子几乎都是作用在DStream中,而DStream的本质是RDD,如果想要直接操作DStream中的RDD,需要借助算子transfrom
nc -lk ip port
数据:
197.129.76.123##2020-10-19 11:11:11##GET /taobao/image/common/1.jpg Http/1.1##200##1271

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

object Demo_Transform extends LoggerTrait {
  def main(args: Array[String]): Unit = {
    val ssc: StreamingContext = SparkUtils.getStreamingContext("Demo_Transform")
    //黑名单
    val blackRDD: RDD[(String, Boolean)] = ssc.sparkContext.parallelize(
      List(
        ("127.129.76.113", true)
      )
    )
    val socket: ReceiverInputDStream[String] = ssc.socketTextStream("192.168.10.111", 9999)
    val mapDStream: DStream[(String, String)] = socket.map(
      line => {
        val index: Int = line.indexOf("##")
        val ip: String = line.substring(0, index)
        val other: String = line.substring(index + 2)
        (ip, other)
      }
    )
    val resDStream: DStream[(String, Option[Boolean])] = mapDStream.transform(
      rdd => {
        val joinRDD: RDD[(String, (String, Option[Boolean]))] = rdd.leftOuterJoin(blackRDD)
        joinRDD.filter {
          case (ip, (left, right)) => !right.isDefined
        }.map {
          case (ip, (left, right)) => (ip, right)
        }
      }
    )
    resDStream.print()
    ssc.start()
    ssc.awaitTermination()
  }
}

updateStatusByKey(WordCount)
注意点:设置检查点,用于保存上一次运行的结果;

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

/**
 * 根据key的前置状态和key的新值进行key的更新,统计截止到目前位置的key的状态
 */
object Demo_updateStateByKey extends LoggerTrait {
  def main(args: Array[String]): Unit = {
    val ssc: StreamingContext = SparkUtils.getStreamingContext("Demo_updateStateByKey")
    ssc.checkpoint("file:/c:/data")
    val scokDStream: ReceiverInputDStream[String] = ssc.socketTextStream("192.168.10.111", 9999)
    val mapDStream: DStream[(String, Int)] = scokDStream.flatMap(_.split("\\s+")).map((_, 1))
    val resDStrean: DStream[(String, Int)] = mapDStream.updateStateByKey(updateFunc)
    resDStrean.print()
    ssc.start()
    ssc.awaitTermination()
  }
  def updateFunc(seq:Seq[Int], option:Option[Int])={
    Option(seq.sum+option.getOrElse(0))
  }
}


SparkSql和SparkSession的聚合

import org.apache.spark.sql.{DataFrame, SparkSession}
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}

object Demo_Top3 extends LoggerTrait {
  def main(args: Array[String]): Unit = {
    //统计全局变量
    val spark: SparkSession = SparkUtils.getSparkSession("Demo_Top3")
    val ssc = new StreamingContext(spark.sparkContext, Seconds(2))
    import spark.implicits._
    ssc.checkpoint("file:/c:/data")
    val sockDStream: ReceiverInputDStream[String] = ssc.socketTextStream("192.168.10.111", 9999)
    val filterDStream: DStream[(String, Int)] = sockDStream.map(line => {
      val fields: Array[String] = line.split("\\s+")
      if (fields == null || fields.length != 3) {
        ("", -1)
      } else {
        val brand = fields(1)
        val category = fields(2)
        (s"${category}_${brand}", 1)
      }
    }).filter(kv => kv._2 != -1)
    val usbDStream: DStream[(String, Int)] = filterDStream.updateStateByKey(updateFunc)
    //统计tops
    usbDStream.foreachRDD((rdd, time)=>{
      if (!rdd.isEmpty()){
        val df: DataFrame = rdd.map {
          case (cb, cnt) => {
            val category: String = cb.substring(0, cb.indexOf("_"))
            val brand: String = cb.substring(cb.indexOf("_") + 1)
            (category, brand, cnt)
          }
        }.toDF("a1", "a2", "a3")
        df.createOrReplaceTempView("Tmp")
        val sql =
          """
            |select
            |A.a1,
            |A.a2,
            |A.a3,
            |A.rank
            |from(
            |select a1,
            |a2,
            |a3,
            |row_number() over(partition by a1 order by cnt desc) rank
            |from
            |tmp)A
            |where A.rank < 4
            |""".stripMargin
        spark.sql(sql).show()
      }
    })
    ssc.start()
    ssc.awaitTermination()
  }
  def updateFunc(seq:Seq[Int], option:Option[Int])={
    Option(seq.sum+option.getOrElse(0))
  }
}

SparkStreaming和Kafka的整合

准备工作:
1,启动Zookeeper和Kafka
2,创建主题
3,利用Kafka生产者生产数据
一、receiver方式

import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.dstream.ReceiverInputDStream
import org.apache.spark.streaming.kafka.KafkaUtils

object Demo_Kafka_Receiver extends LoggerTrait {
  def main(args: Array[String]): Unit = {
    //1,获取到Streaming的入口
    val ssc: StreamingContext = SparkUtils.getStreamingContext("Demo_Kafka_Receiver")
    //2,spark-streaming-kafka依赖包提供了一个工具类,帮助我们使用spark-streaming来获取到kafka中的数据
    val zkQuorum:String = "192.168.10.111/kafka"
    val groupId = "hzbigdata2004"
    val topics = Map(
      "receiver_topics" -> 1
    )
    val msgDStream: ReceiverInputDStream[(String, String)] = KafkaUtils.createStream(ssc, zkQuorum, groupId, topics)
    //打印
    msgDStream.print()
    //启动
    ssc.start()
    //始终处于阻塞状态
    ssc.awaitTermination()
  }
}

恰好一次最好的方法是保存数据处理和偏移量保存的原子性,这就必须使用spark streaming的预写日志机制(Write Ahead Log,WAL)。这种方式虽然能够解决问题,但是性能较差,所以receiver模式被抛弃了。

二、Direct模式
最大的好处就是可以手动的保存偏移量,实现恰好一次

import kafka.serializer.StringDecoder
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.kafka.KafkaUtils

object Demo_Direct {
  def main(args: Array[String]): Unit = {
    //获取入口
    val ssc: StreamingContext = SparkUtils.getStreamingContext("Demo_Direct")
    val topic: Set[String] = "direct_topics".split(",").toSet
    val kafkaParams:Map[String, String] = Map(
      "bootstrap.servers"->"192.168.10.111:9092",
      "group.id" -> "hzbigdata2004",
      "auto.offset.reset"->"largest"
    )
    val msgDStream: InputDStream[(String, String)] = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, topic)
    
    //获取到离散流
    
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值