hadoop基礎學習三十一(spark-streaming)

一隻小呆呆發表於2020-11-09

一、流處理和批處理

  • 流處理:資料大小未知,操作簡單,及時響應
    訊息採集=》訊息佇列(排隊等候)=》計算=》資料庫
  • 批處理:資料大小固定,操作賦值,需要一段時間
  • 有界流:具有定義的開始和結束
  • 無界流:有一個開始,但沒有定義的結束

二、spark-streaming

  • SparkStreaming是一套框架。
  • SparkStreaming是Spark核心API的一個擴充套件,可以實現高吞吐量的,具備容錯機制的實時流資料處理。
  • Spark處理的是批量的資料(離線資料),Spark Streaming實際上處理並不是像Strom一樣來一條處理一條資料,而是對接的外部資料流之後按照時間切分,批處理一個個切分後的檔案,和Spark處理邏輯是相同的。
  • Spark Streaming將接收到的實時流資料,按照一定時間間隔,對資料進行拆分,交給Spark Engine引擎,最終得到一批批的結果。
    在這裡插入圖片描述
    總結:spark是離線處理資料的,可以通過sparkstreaming來做實時處理資料,但是本質實現,是通過較短的時間進微批處理

三、程式碼演示streaming原理

加入依賴

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming_2.11</artifactId>
            <version>2.4.5</version>
        </dependency>

在這裡插入圖片描述

1)實時統計

  • 當使用awaitTermination時,主執行緒會處於一種等待的狀態,等待執行緒池中所有的執行緒都執行完畢後才繼續執行。
  • spark streaming 需要指定多個資源
  • 在master中啟動socket服務,用於接收資料

首先需安裝一個外掛nc
yum install nc -y
在這裡插入圖片描述
啟動socket中設定的要監聽的埠
nc -lk 9999

在這裡插入圖片描述

無狀態運算元

package com.sparkstreaming
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}

object Demo1_wc {
    def main(args: Array[String]): Unit = {
        //建立spark的配置,指明執行方式和執行緒數,和程式名稱
        // spark streaming 需要指定多個資源,  接收資料會佔用一個,計算會佔用一個
        //由於是無限流,沒有指定的結束,執行緒會一直等待,沒有執行緒用來處理輸出
        //所以需要指定多個資源,資料結束會佔用一個
        val conf: SparkConf = new SparkConf()
        conf.setMaster("local[2]").setAppName("streaming")

        //建立spark的上下文物件
        val sc: SparkContext = new SparkContext(conf)
        //建立sparkStreaming 的上下文物件,設定多長時間處理一次,可以指定分鐘,毫秒
        val ssc: StreamingContext = new StreamingContext(sc,Durations.seconds(5))

        //指定一個埠獲取資料,連線socket獲取資料,  建立DStream
        //需要到master中啟動一個socket服務,用來輸入資料
        val rds: ReceiverInputDStream[String] = ssc.socketTextStream("master",9999)
        //對接收到rds的資料進行邏輯處理,,每五秒執行一次該邏輯
        //該邏輯為統計word的數量
        val ds: DStream[String] = rds.flatMap(_.split(","))
        val ds1: DStream[(String, Int)] = ds.map((_,1)).reduceByKey(_+_)
        //不能用foreach,foreach需要遍歷完,這是是一個無界流
        ds1.print()
        //需啟動sparkstreaming,設定主執行緒為等待狀態
        ssc.start()
        ssc.awaitTermination()

    }

}

指定要監聽的埠號,在master中啟動該埠,執行程式

在master中輸入資料
在這裡插入圖片描述
會發現idea中每五秒更新一次,每五秒都重新計算,不儲存之前的狀態,所以也稱為無狀態運算元

在這裡插入圖片描述
1000ms=1s 5s=5000ms 時間戳加了5s
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

有狀態運算元

  • 統計累加的資料,包括之前時間內
  • 將每一個統計單詞的數量看著是一個狀態(數值)
  • 後面的計算不停的去更新之前的狀態
package com.sparkstreaming

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

object Demo2_updatabykey {
    def main(args: Array[String]): Unit = {
        val conf: SparkConf = new SparkConf().setAppName("up").setMaster("local[2]")
        val sc: SparkContext = new SparkContext(conf)

        val ssc: StreamingContext = new StreamingContext(sc, Durations.seconds(5))
        //由於有狀態運算元,需要保持狀態,此處需儲存快照
        ssc.checkpoint("spark/data/checkpoint")

        //連線socket
        val ds1: ReceiverInputDStream[String] = ssc.socketTextStream("master",9999)
        val ds2: DStream[(String, Int)] = ds1.flatMap(_.split(",")).map((_,1))

        //定義一個功能函式
        //seq為所有可能的狀態的值
        //option之前一個key計算的狀態,  之前的結果需要儲存的checkpoint中
        //返回一個新的狀態
        def Funcation(seq:Seq[Int],option:Option[Int]): Option[Int] ={
            val now: Int = seq.sum
            val before: Int = option.getOrElse(0)
            Some(now+before)
        }
        val ds3: DStream[(String, Int)] = ds2.updateStateByKey(Funcation)
        ds3.print()

        ssc.start()
        ssc.awaitTermination()


    }

}

在這裡插入圖片描述
在這裡插入圖片描述

有狀態運算元=》window

  • 統計最近一段時間內的資料
  • 視窗操作
  • 計算最近一段時間的資料, 每隔一段時間計算一次
  • 口大小和滑動時間必須是, spark batch是的整數倍
package com.sparkstreaming

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

object Demo3_Window {
    def main(args: Array[String]): Unit = {
        val conf: SparkConf = new SparkConf().setAppName("window").setMaster("local[2]")
        val sc: SparkContext = new SparkContext(conf)

        val ssc: StreamingContext = new StreamingContext(sc, Durations.seconds(5))
        ssc.checkpoint("spark/data/checkpoint")

        val ds1: ReceiverInputDStream[String] = ssc.socketTextStream("master", 9999)
        val ds2: DStream[(String, Int)] = ds1.flatMap(_.split(",")).map((_, 1))

        //兩個時間需是streamingcontext上下文時間的整數倍
        val ds3 = ds2.reduceByKeyAndWindow(
            (x: Int, y: Int) => x + y,//需要聚合的操作 聚合函式
            Durations.seconds(15),//視窗大小
            Durations.seconds(5)//多久計算一次,滑動一次
        )
        
        
        //減少重疊計算的優化版本
//        val ds3=ds2.reduceByKeyAndWindow(
//            (x: Int, y: Int) => x + y, //聚合函式
//            (i: Int, j: Int) => i - j, // 減去多餘部分的函式
//            Durations.seconds(15), // 視窗大小
//            Durations.seconds(5) // 多久季賽那一次 (滑動時間)
//        )
        
        //去掉空資料,不加的話有些資料沒了還會顯示,xx 0,易干擾視覺
        val ds4: DStream[(String, Int)] = ds3.filter(_._2 != 0)
        ds4.print()

        ssc.start()
        ssc.awaitTermination()

    }
}

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

2)Datafram連線socket,寫sql

  • Datafram在批處理和流處理中是一樣的介面,只是實現不同,批處理是rdd,流處理是ds
package com.sparkstreaming

import org.apache.spark.sql.streaming.OutputMode
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}

object Demo4_dfStream {
    def main(args: Array[String]): Unit = {
        val spark=SparkSession.builder()
                .appName("dfstream")
                //將其註釋掉可以打包上傳至虛擬機器中執行
                .master("local[2]")
                .config("spark.sql.shuffle.partitions",2)
                .getOrCreate()
        //df連線socket
        val df1: DataFrame =spark.readStream
                .format("socket")
                .option("host","master")
                .option("port",9999)
                .load()
        import spark.implicits._
        import org.apache.spark.sql.functions._
        //為了方便呼叫切分發方法,需將datafram轉化為String
        //Dataset使用和df一樣
        val ds1: Dataset[String] = df1.as[String]
        //此處切分之後,會固定有一個叫value的列
        val ds2: DataFrame = ds1.flatMap(_.split(",")).select($"value" as "word")

        /**
          * dsl
          */
        val ds3=ds2.groupBy($"word").agg(count($"word") as "count")
                .select($"word",$"count")
        /**
          * sql
          */


//        ds2.createTempView("wordview")
//
//        val ds3=spark.sql(
//            """
//              |select word,count(word) from wordview group by word
//            """.stripMargin)
        ds3 .writeStream // 輸入結果
                .outputMode(OutputMode.Complete()) //
                .format("console") //輸出到控制檯
                .start()
                .awaitTermination()

    }

}

輸入資料就會更新且會累加
在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述

3)檔案流,監控一個目錄

package com.sparkstreaming

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.streaming.OutputMode

object Demo5_filestream {
    def main(args: Array[String]): Unit = {
        val spark=SparkSession.builder()
                .master("local[2]")
                .appName("file")
                .config("spark.sql.shuffle.paratitions",2)
                .getOrCreate()
        val student=spark.readStream
                .format("csv")
                .option("sep",",")
                .schema("id STRING ,name STRING , age  int ,gender string ,clazz string")
                .load()
        student
                .writeStream
                .format("console")
                .outputMode(OutputMode.Append())
                .start()
                .awaitTermination()
        
    }

Hadoop
hadoop學習一
hadoop學習二
hadoop學習三
hadoop學習四
hadoop學習五
hadoop學習六
hadoop學習七
hadoop學習八
hadoop異常處理
hadoop基礎學習九
hadoop基礎學習十
hadoop基礎學習十一
hadoop基礎學習十二
hadoop基礎學習十三
hadoop基礎學習十四
hadoop基礎學習十五
hadoop基礎學習十六
hadoop基礎學習十七
hadoop基礎學習十八
hadoop基礎學習十九
Hadoop基礎學習二十
hadoop基礎學習二十一
hadoop基礎學習二十二
hadoop基礎學習二十三
hadoop基礎學習二十四
hadoop基礎學習二十五
hadoop基礎學習二十六
hadoop基礎學習二十七
Hadoop基礎學習二十九

相關文章