SparkStreaming知识总结

本文主要介绍了流式计算的概念,对比了SparkStreaming与其他框架,并详细阐述了SparkStreaming的基本原理和入门编程,包括从内存和HDFS读取数据,以及与Kafka的整合。此外,还探讨了SparkStreaming的常用算子,如窗口操作和转换算子。
摘要由CSDN通过智能技术生成

一、流式计算的概述

1.1 什么是流式计算

1. 数据流与静态数据的区别
	-- 数据流指的就是不断产生的数据,是源源不断,不会停止。
	-- 静态数据指的就是存储在磁盘中的固定的数据
2. 流式计算的概念
      就是对数据流进行计算,由于数据是炼苗不断的产生的,所以这个计算也是一直再计算,不会停止。
3. 流式计算的数据流有什么特点:
   - 数据是无界的(unbounded)
   - 数据是动态的
   - 计算速度是非常快的(是不断计算的,每次计算都是微小的批量数据,因此速度快,而且还是基于内存的)
   - 计算不止一次 
   - 计算不能终止
4. 离线计算的特点:
	- 数据是有界的(unbounded)
	- 数据是静态的
	- 计算速度通常较慢   
	- 计算只执行一次
	- 计算终会终止

1.2 常见的离线和流式计算框架

1. 离线计算框架
	-- mapreduce
	-- hive
	-- sparkcore
	-- sparksql
	-- flink-dataset
2. 流式计算框架
   -- storm
   -- sparkStreaming
   -- flink-datastream(blink)

1.3 SparkStreaming简介

1.3.1 简介

1. SparkStreaming也是Spark生态栈中的一个重要模块,是一个流式计算框架
2. SparkStreaming属于准实时计算框架
3. SparkStreaming是SparkCore的api的一种扩展,使用DStream(离散流)作为数据模型。 本质就是一个时间序列上的RDD。

DStream,本质上是RDD的序列。SparkStreaming的处理流程可以归纳为下图:
在这里插入图片描述

流式计算框架从延迟的角度来分类:

1. 纯实时流式计算: 毫秒级别的延迟,或者没有延迟的计算。
2. 准实时流式计算: 亚秒级别,秒级别,分钟级别的计算

流式计算框架从处理的记录条数来分类

1. 纯实时流式计算: 来一条记录,就计算一条记录。
2. 准实时流式计算: 微小的批处理,还是多条记录一起计算。

1.3.2 原理

DStream数据流模型

1. SparkStreaming 会实时的接受输入的数据
2. SparkStreaming 会按照固定长度的时间段将源源不断进来的数据划分成batch
3. SparkStreming 会每一个batch进行一次计算,计算是不停止的
4. 每次的计算结果也是一个batch,因此结果集就是多个batch的构成
5. SparkStreaming,将数据流抽象成DStream.  称之为离散流的数据模型。本质就是一个时间序列上的RDD。
6. 在整个数据流作业中,会有多个DStream。


参考下图:    rdd1 就是一个时间序列上的 DStream
				rdd2 就是一个时间序列上的 DStream
				rdd3 就是一个时间序列上的 DStream
				rdd4 就是一个时间序列上的 DStream
             

      8:00:00      hello world  hello java hello c++
      
      rdd1 = sc.textFile("....")
      rdd2 = rdd1.flatMap(_.split(" "))
      rdd3 = rdd2.map((_,1))
      rdd4 = rdd3.reduceByKey(_+_)
      
      针对于rdd1来说:
             8:00:00      hello world  hello java hello c++
             8:00:10      no zuo no die
             8:00:20      you are best
             8:00:30:     hello you are best
      针对于rdd2来说:
             8:00:00      [hello, world,hello,java,hello,c++]
             8:00:10      [no,zuo,no,die]
             8:00:20      [you,are,best]
             8:00:30:     [hello,you,are,best]
      针对于rdd3来说:
             8:00:00      (hello,1), (world,1),(hello,1),(java,1),(hello,1),(c++,1)
             8:00:10      (no,1),(zuo,1),(no,1),(die,1)
             8:00:20      (you,1),(are,1),(best,1)
             8:00:30:     (hello,1),(you,1),(are,1),(best,1)

参考下图: 一个DStream是由不同时间段上的同一个RDD构成的
在这里插入图片描述

参考下图:如果算子的返回值是DStream,则不管是哪一个时间段上的数据,只要调用了同一个算子,则返回的都同一个DStream
在这里插入图片描述

1.3.3 Storm VS SparkStreaming VS Flink

在这里插入图片描述

1.4 怎样选择流式处理框架

何时选择storm
	--需要纯实时,不能忍受1秒以上延迟的场景
	--实时计算的功能中,要求可靠的事务机制和可靠性机制,即数据的处理完全精准,一条也不能多,一条也不能少
   --针对高峰低峰时间段,动态调整实时计算程序的并行度,以最大限度利用集群资源(通常是在小型公司,集群资源紧张的情况)
何时选择Spark Streaming	
	--不满足上述3点要求的话,我们可以考虑使用Spark Streaming来进行实时计算
	--如果一个项目除了实时计算之外,还包括了离线批处理、交互式查询、图计算和MLIB机器学习等业务功能,而且实时计算中,
	   可能还会牵扯到高延迟批处理、交互式查询等功能,,那么就应该首选Spark生态,用Spark Core开发离线批处理,
	   用Spark SQL开发交互式查询,用Spark Streaming开发实时计算,三者可以无缝整合,给系统提供非常高的可扩展性。
何时选择Flink
	支持高吞吐、低延迟、高性能的流处理
	支持带有事件时间的窗口(Window)操作
	支持有状态计算的Exactly-once语义
	支持高度灵活的窗口(Window)操作,支持基于time、count、session,以及data-driven的窗口操作
	支持具有Backpressure功能的持续流模型
	支持基于轻量级分布式快照(Snapshot)实现的容错
	一个运行时同时支持Batch on Streaming处理和Streaming处理
	Flink在JVM内部实现了自己的内存管理
	支持迭代计算
	支持程序自动优化:避免特定情况下Shuffle、排序等昂贵操作,中间结果有必要进行缓存

二、SparkStreaming的入门编程

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>redis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- sparkstreaming的核心包 -->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming_2.11</artifactId>
            <version>2.2.3</version>
        </dependency>
        <!-- sparkstreaming与kafka的整合包 -->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
            <version>2.2.3</version>
        </dependency>
         <!-- redis的整合包 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.0.0</version>
        </dependency>
          <!-- sparksql的核心包 -->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
            <version>2.2.3</version>
        </dependency>
    </dependencies>
</project>

2.1 wordcount案例演示

package com.qf.sparkstreaming.day01

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

/**
 *  sparkCore的入门api:    SparkContext
 *  sparkSql的入门:        SparkSession
 *  sparkStreaming的入门API: StreamingContext
 *
 *
 *  注意:
 *     1. 要先使用nc指令 开启qianfeng01和10086端口,否则sparkStreaming会提前报错
 *          在qianfeng01上运行指令: nc -lp 10086
 *                          -l  表示监听
 *                          -p  表示端口
 */
object Streaming_01_WordCount {
   
    def main(args: Array[String]): Unit = {
   
        val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("wordcount")

        /**
         * 构造器:StreamingContext(conf:SparkConf, batchDuration:Duration)
         * 第一个参数:配置对象
         * 第二个参数:用于指定SparkStreaming的流式计算的batch的时间间隔,即时间片段
         *           Durations.milliseconds(milliseconds: Long)    毫秒级别
         *           Durations.seconds(seconds: Long)      秒级别
         *           Durations.minutes(minutes: Long)      分钟级别
         *           Milliseconds(milliseconds: Long)    毫秒级别
         *           Seconds(seconds: Long)   秒级别
         *           Minutes(minutes: Long)  分钟级别
         */
        val context = new StreamingContext(conf, Seconds(10))

        /**
         * 利用TCP协议的套接字,实时的监听一个端口,如果有数据,就采集,并计算。
         * socketTextStream(hostname: String,port: Int,......)
         * T:  泛型
         * hostname: 要监听的主机名
         * port:要监听的端口号
         *
         */
        val dStream: ReceiverInputDStream[String] = context.socketTextStream("qianfeng01", 10086)
        // 打印数据流中的数据,默认打印10条记录
        //dStream.print()

        // 按照空格切分成各个单词,  返回的是一个新的DStream
        val wordDStream: DStream[String] = dStream.flatMap(_.split(" "))

        //构建成元组,返回一个新的DStream
        val wordAndOneDStream: DStream[(String, Int)] = wordDStream.map((_, 1))

        //进行统计每个单词的数量,返回的是一个新的DStream
        val wordCountDStream: DStream[(String, Int)] = wordAndOneDStream.reduceByKey(_ + _)

        //打印,默认打印10条
        wordCountDStream.print()



        //启动程序
        context.start()

        /**
         * 因为main方法一旦结束,整个程序就结束,因此需要让main方法处于等待状态
         */
        context.awaitTermination()

    }
}

2.2 从内存中的Queue中获取数据

package com.qf.sparkstreaming.day01

import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.{
   Durations, StreamingContext}

import scala.collection.mutable

/**
 * 从内存中的Queue中获取数据
 */
object Streaming_02_FromQueue {
   
    def main(args: Array[String]): Unit = {
   
        val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("FromQueue")
        val ssc:StreamingContext = new StreamingContext(conf,Durations.seconds(10))

        /**
         * queueStream[T: ClassTag]( queue: Queue[RDD[T]],oneAtATime: Boolean = true)
         * 从一个RDD队列中获取一个或多个RDD数据,进行处理。
         * queue:RDD队列
         * oneAtATime: 是否一次处理一个RDD,默认值是true。   false表示队列中有多少,就一次性处理多少。 注意:从队列中获取数据时,队列中就没有该数据了。
         */
        val queue = new mutable.Queue[RDD[Int]]()
        val dStream: InputDStream[Int] = ssc.queueStream(queue,true)

        //直接打印,默认打印10行
        dStream.print()

        //开启数据流作业
        ssc.start()

        /**
         * 利用main线程,向队列中源源不断的添加RDD。
         */
        val rdd: RDD[Int] = ssc.sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8))
        for(i<- 1 to 300){
   
            queue.enqueue(rdd)//将rdd填入队列中
            Thread.sleep(1000)
            // println(queue.size)  //如果将oneAtATime改为false,则可证明队列中的数据每10秒都会被清空。
        }

        // 该方法的作用就是阻塞main方法,不让其结束。因为main方法已结束,就会停止数据流作业
        ssc.awaitTermination()
    }
}

2.3 自定义接收器

package com.qf.sparkstreaming.day01

import org.apache.spark.SparkConf
import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.dstream.ReceiverInputDStream
import org.apache.spark.streaming.receiver.Receiver
import org.apache.spark.streaming.{
   Durations, StreamingContext}

object Streaming_03_CustomReceiver {
   
    def main(args: Array[String]): Unit = {
   
        val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("FromQueue")
        val ssc:StreamingContext = new StreamingContext(conf,Durations.seconds(10))

        //从采集器中获取DStream

        val dStream: ReceiverInputDStream[String] = ssc.receiverStream(new MyReceiver())
        dStream.flatMap(_.split(" ")).map((_,1))</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值