Spark學習進度11-Spark Streaming&Structured Streaming

清風紫雪 發表於 2021-01-15

Spark Streaming

Spark Streaming 介紹

批量計算

Spark學習進度11-Spark Streaming&Structured Streaming

 

 流計算

Spark學習進度11-Spark Streaming&Structured Streaming

 

Spark Streaming 入門

 Netcat 的使用

Spark學習進度11-Spark Streaming&Structured Streaming

 專案例項

目標:使用 Spark Streaming 程式和 Socket server 進行互動, 從 Server 處獲取實時傳輸過來的字串, 拆開單詞並統計單詞數量, 最後列印出來每一個小批次的單詞數量

Spark學習進度11-Spark Streaming&Structured Streaming

 步驟: 

package cn.itcast.streaming

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

object StreamingWordCount {

  def main(args: Array[String]): Unit = {
    //1.初始化
    val sparkConf=new SparkConf().setAppName("streaming").setMaster("local[2]")
    val ssc=new StreamingContext(sparkConf,Seconds(5))
    ssc.sparkContext.setLogLevel("WARN")

    val lines: ReceiverInputDStream[String] = ssc.socketTextStream(
      hostname = "192.168.31.101",
      port = 9999,
      storageLevel = StorageLevel.MEMORY_AND_DISK_SER
    )
    //2.資料處理
    //2.1把句子拆單詞
    val words: DStream[String] =lines.flatMap(_.split(" "))
    val tuples: DStream[(String, Int)] =words.map((_,1))
    val counts: DStream[(String, Int)] =tuples.reduceByKey(_+_)

    //3.展示
    counts.print()

    ssc.start()

    ssc.awaitTermination()


  }

}

開始進行互動:

Spark學習進度11-Spark Streaming&Structured Streaming

Spark學習進度11-Spark Streaming&Structured Streaming

 

注意:

Spark Streaming 並不是真正的來一條資料處理一條

Spark Streaming 的處理機制叫做小批量, 英文叫做 mini-batch, 是收集了一定時間的資料後生成 RDD, 後針對 RDD 進行各種轉換操作, 這個原理提現在如下兩個地方

  • 控制檯中列印的結果是一個批次一個批次的, 統計單詞數量也是按照一個批次一個批次的統計
  • 多長時間生成一個 RDD 去統計呢? 由 new StreamingContext(sparkConf, Seconds(1)) 這段程式碼中的第二個引數指定批次生成的時間

Spark Streaming 中至少要有兩個執行緒

在使用 spark-submit 啟動程式的時候, 不能指定一個執行緒

  • 主執行緒被阻塞了, 等待程式執行
  • 需要開啟後臺執行緒獲取資料

各種運算元

 Spark學習進度11-Spark Streaming&Structured Streaming

  • 這些運算元類似 RDD, 也會生成新的 DStream

  • 這些運算元操作最終會落到每一個 DStream 生成的 RDD 中

運算元釋義

flatMap

lines.flatMap(_.split(" "))

將一個資料一對多的轉換為另外的形式, 規則通過傳入函式指定

map

words.map(x => (x, 1))

一對一的轉換資料

reduceByKey

words.reduceByKey(_ + _)

這個運算元需要特別注意, 這個聚合並不是針對於整個流, 而是針對於某個批次的資料

Structured Streaming

Spark 程式設計模型的進化過程

程式設計模型解釋

RDD

rdd.flatMap(_.split(" "))
   .map((_, 1))
   .reduceByKey(_ + _)
   .collect
  • 針對自定義資料物件進行處理, 可以處理任意型別的物件, 比較符合物件導向

  • RDD 無法感知到資料的結構, 無法針對資料結構進行程式設計

DataFrame

spark.read
     .csv("...")
     .where($"name" =!= "")
     .groupBy($"name")
     .show()
  • DataFrame 保留有資料的元資訊, API 針對資料的結構進行處理, 例如說可以根據資料的某一列進行排序或者分組

  • DataFrame 在執行的時候會經過 Catalyst 進行優化, 並且序列化更加高效, 效能會更好

  • DataFrame 只能處理結構化的資料, 無法處理非結構化的資料, 因為 DataFrame 的內部使用 Row 物件儲存資料

  • Spark 為 DataFrame 設計了新的資料讀寫框架, 更加強大, 支援的資料來源眾多

Dataset

spark.read
     .csv("...")
     .as[Person]
     .where(_.name != "")
     .groupByKey(_.name)
     .count()
     .show()
  • Dataset 結合了 RDD 和 DataFrame 的特點, 從 API 上即可以處理結構化資料, 也可以處理非結構化資料

  • Dataset 和 DataFrame 其實是一個東西, 所以 DataFrame 的效能優勢, 在 Dataset 上也有

Spark Streaming 和 Structured Streaming

Spark Streaming 時代

20190628010204
  • Spark Streaming 其實就是 RDD 的 API 的流式工具, 其本質還是 RDD, 儲存和執行過程依然類似 RDD

Structured Streaming 時代

20190628010542
  • Structured Streaming 其實就是 Dataset 的 API 的流式工具, API 和 Dataset 保持高度一致

Spark Streaming 和 Structured Streaming

  • Structured Streaming 相比於 Spark Streaming 的進步就類似於 Dataset 相比於 RDD 的進步

  • 另外還有一點, Structured Streaming 已經支援了連續流模型, 也就是類似於 Flink 那樣的實時流, 而不是小批量, 但在使用的時候仍然有限制, 大部分情況還是應該採用小批量模式

在 2.2.0 以後 Structured Streaming 被標註為穩定版本, 意味著以後的 Spark 流式開發不應該在採用 Spark Streaming 了

Structured Streaming 入門案例

需求

20190628144128
  • 編寫一個流式計算的應用, 不斷的接收外部系統的訊息

  • 對訊息中的單詞進行詞頻統計

  • 統計全域性的結果

步驟:

package cn.itcast.structured


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

object SocketWordCount {

  def main(args: Array[String]): Unit = {

    //1.建立SparkSession
    val spark=SparkSession.builder().master("local[5]")
      .appName("structured")
      .getOrCreate()

    spark.sparkContext.setLogLevel("WARN")
    import spark.implicits._

    //2.資料集的生成,資料讀取
    val source: DataFrame =spark.readStream
      .format("socket")
      .option("host","192.168.31.101")
      .option("port",9999)
      .load()

    val sourceDS: Dataset[String] = source.as[String]

    //3.資料的處理
    val words=sourceDS.flatMap(_.split(" "))
      .map((_,1))
      .groupByKey(_._1)
      .count()
    //4.結果集的生成和輸出
    words.writeStream
      .outputMode(OutputMode.Complete())
      .format("console")
      .start()
      .awaitTermination()


  }

}

互動結果:

Spark學習進度11-Spark Streaming&Structured Streaming

 

 Spark學習進度11-Spark Streaming&Structured Streaming

從結果集中可以觀察到以下內容

  • Structured Streaming 依然是小批量的流處理

  • Structured Streaming 的輸出是類似 DataFrame 的, 也具有 Schema, 所以也是針對結構化資料進行優化的

  • 從輸出的時間特點上來看, 是一個批次先開始, 然後收集資料, 再進行展示, 這一點和 Spark Streaming 不太一樣

從 HDFS 中讀取資料

使用 Structured Streaming 整合 HDFS, 從其中讀取資料的能力

步驟

  1. 案例結構

  2. 產生小檔案並推送到 HDFS

  3. 流式計算統計 HDFS 上的小檔案

  4. 執行和總結

實驗步驟:

Step1:利用py產生檔案源源不斷向hdfs上傳檔案

Step2:編寫 Structured Streaming 程式處理資料

py程式碼:

import os

for index in range(100):

    content = """
    {"name": "Michael"}
    {"name": "Andy", "age": 30}
    {"name": "Justin", "age": 19}
    """


    file_name = "/export/dataset/text{0}.json".format(index)


    with open(file_name, "w") as file:
        file.write(content)


    os.system("/export/servers/hadoop-2.7.5/bin/hdfs dfs -mkdir -p /dataset/dataset/")
    os.system("/export/servers/hadoop-2.7.5/bin/hdfs dfs -put {0} /dataset/dataset/".format(file_name))

spark處理流式檔案

package cn.itcast.structured

import org.apache.spark.SparkContext
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.streaming.OutputMode
import org.apache.spark.sql.types.{StructField, StructType}

object HDFSSource {

  def main(args: Array[String]): Unit = {

    System.setProperty("hadoop.home.dir","C:\\winutil")

    //1.建立SparkSession
    val spark=SparkSession.builder()
      .appName("hdfs_source")
      .master("local[6]")
      .getOrCreate()

    //2.資料讀取
    val schema=new StructType()
        .add("name","string")
        .add("age","integer")
    val source=spark.readStream
        .schema(schema)
      .json("hdfs://hadoop101:8020/dataset/dataset")

    //3.輸出結果
    source.writeStream
      .outputMode(OutputMode.Append())
      .format("console")
      .start()
      .awaitTermination()

  }

}

總結

20190715111534
  1. Python 生成檔案到 HDFS, 這一步在真實環境下, 可能是由 Flume 和 Sqoop 收集並上傳至 HDFS

  2. Structured Streaming 從 HDFS 中讀取資料並處理

  3. Structured Streaming 講結果表展示在控制檯