Spark每日半小時(35)——Spark Streaming:基本概念

接下來,我們將超越簡單的示例,詳細介紹Spark Streaming的基礎知識。

鏈接

與Spark類似,Spark Streaming可以通過Maven Central獲得。要編寫自己的Spark Streaming程序,必須將以下依賴項添加到Maven項目中。

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

要從Kafka,Flume和Kinesis等源中提取Spark Streaming核心API中不存在的數據,我們必須將相應的artifact spark-streaming-xyz_2.11 添加到依賴中。例如,一些常見的如下:

Source Artifact
Kafka spark-streaming-kafka-0-10_2.11
Flume spark-streaming-flume_2.11
Kinesis spark-streaming-kinesis-asl_2.11[Amazon Software License]

初始化StreamingContext

要初始化Spark Streaming程序,必須創建一個StreamingContext對象,它是所有Spark Streaming功能的主要入口點。

一個StreamingContext對象可以被SparkConf對象創建,如下:

import org.apache.spark._
import org.apache.spark.streaming._

val conf = new SparkConf().setAppName(appName).setMaster(master)
val ssc = new StreamingContext(conf, Seconds(1))

該appName參數時應用程序在集羣UI上顯示的名稱。master是Spark,Mesos或YARN集羣URL,或在本地local模式下運行的特殊“local[*]”字符串。實際上,當在集羣上運行時,我們不希望master在程序中進行硬編碼,而是啓動應用程序spark-submit並在那裏接受它。但是,對於本地測試和單元測試,我們可以傳遞“local[*]”以在進程中運行Spark Streaming。請注意,這會在內部創建一個JavaSparkContext(所有Spark功能的起點),可以將其作爲ssc.sparkContext。

必須根據應用程序的延遲要求和可用的集羣資源設置批處理間隔。

一個JavaStreamingContext還可以通過JavaSparkContext大對象創建。

import org.apache.spark.streaming.api.java.*;

JavaSparkContext sc = ...   //existing JavaSparkContext
JavaStreamingContext ssc = new JavaStreamingContext(sc, Durations.seconds(1));

定義上下文後,我們必須執行以下操作。

  1. 通過創建輸入DStream來定義輸入源。
  2. 通過將轉換和輸出操作應用於DStream來定義流式計算。
  3. 開始接收數據並使用它進行處理streamingContext.start()。
  4. 等待處理停止(手動或由於任何錯誤)使用streamingContext.awaitTermination()。
  5. 可以使用手動停止處理streamingContext.stop()。

要記住的要點:

  • 一旦啓動了上下文,就不能設置或添加新的流式計算。
  • 上下文停止後,無法重新啓動。
  • 在JVM中只能同時激活一個StreamingContext。
  • StreamingContext上的stop()也會停止SparkContext。要僅停止StreamingContext,需要將名爲stopSparkContext的stop()的可選參數設置爲false。
  • 只要創建下一個StreamingContext之前停止前一個StreamingContext(不停止SparkContext),就可以重複使用SparkContext創建多個StreamingContexts。

離散流(DStreams)

Discretized Stream或DStream是Spark Streaming提供的基本抽象。它表示連續的數據流,可以是從源接收的輸入數據流,也可以是通過轉換輸入流生成的已處理數據流。在內部,DStream由一系列連續的RDD表示,這是Spark對不可變分佈式數據集的抽象。DStream中的每個RDD都包含來自特定時間間隔的數據。

Spark Streaming

應用於DStream的任何操作都轉換爲底層RDD上的操作。例如,在先前將行流轉換爲單詞的示例中,flatMap操作應用於lines DStream中的每個RDD以生成DStream的wordsRDD。如下圖:

Spark Streaming

這些底層RDD轉換由Spark引擎計算。DStream操作隱藏了大部分細節,併爲開發人員提供了更高級別的API以方便使用。

輸入DSreams和Receivers

輸入DStream是表示從流源接收的輸入數據流的DStream。在上示例中,lines輸入DStream是表示從netcat服務器接收的數據流。每個輸入DStream(文件流除外)都與Receiver對象相關聯,該對象從源接收數據並將其存儲在Spark的內存中進行處理。

Spark Streaming提供兩類內置流媒體源。

  • 基本來源:StreamingContext API中直接提供的源。示例:文件系統和socket連接。
  • 高級資源:Kafka,Flume,Kinesis等資源可通過額外的實用程序類獲得。這些需要連接額外的依賴關係。

注意,如果要在應用程序中並行接收多個數據流,可以創建多個輸入DStream。這將創建多個接收器,這些接收器將同時接收多個數據流。但請注意,Spark worker / executor是一個長期運行的任務,因此它佔用了分配給Spark Streaming應用程序的其中一個核心。因此,重要的是要記住,Spark Streaming應用程序需要分配足夠的內核來處理接收的數據,以及運行接收器。

要記住的要點

  • 在本地運行Spark Streaming程序時,請勿使用“local”或“local[1]”作爲主URL。這兩種方法都意味着只有一個線程將用於本地運行任務。如果我們正在使用基於接收器的輸入DStream(例如Kafka,Socket,Flume等),那麼將使用單個線程來運行接收器,而不留下用於處理接收數據的線程。因此,在本地運行時,始終使用“local[n]”作爲主URL,其中n>要運行的接收器數量。
  • 將邏輯擴展到在集羣上運行時,分配給Spark Streaming應用程序的核心數必須大於接收器數。否則系統將接收數據,但無法處理數據。

基本來源

我們已經在示例中看了通過TCP Socket連接接收的文本數據創建DStream的示例ssc.socketTextStream(...)。除了Socket之外,StreamingContext API還提供了從文件創建DStream作爲輸入源的方法。

文件流

對於從於HDFS API兼容的任何文件系統(即HDFS,S3,NFS等)上的文件讀取數據,可以創建DStream作爲viaStreamingContext.fileStream[keyClass, valueClass, InputFormatClass]。

文件流不需要運行接收器,因此不需要爲接收文件數據分配任何內核。

對於簡單的文本文件,最簡單的方法是StreamingContext.textFileStream(dataDirectory)。

streamingContext.fileStream<KeyClass, ValueClass, InputFormatClass>(dataDirectory);

對於文本文件

streamingContext.textFileStream(dataDirectory);

如何監控目錄

Spark Streaming將監視目錄dataDirectory並處理在該目錄中創建的任何文件。

  • 可以監視一個簡單的目錄,例如“hdfs://namenode:8040/logs/”。直接在這種路徑下的所有文件將在發現時進行處理。
  • 一個POSIX glob模式可以被提供,例如“hdfs://namenode:8040/logs/2017/*”。這裏,DStream將包含與模式匹配的目錄中的所有文件。那就是:它是目錄的模式,而不是目錄中的文件。
  • 所有文件必須採用相同的數據格式。
  • 根據文件的修改時間而不是創建時間,文件被視爲時間段的一部分。
  • 一旦處理完畢後,對當前窗口中文件的更改不會導致重新讀取文件。那就是:忽略更新。
  • 目錄下的文件越多,掃描更改所需要的時間越長:即使沒有修改過任何文件。
  • 如果使用通配符來標識目錄,例如“hdfs://namenode:8040/logs/2016-*”,重命名整個目錄以匹配路徑,則會將該目錄添加到受監視目錄列表中。只有修改時間在當前窗口內的目錄中的文件纔會包含在流中。
  • 調用FileSystem.setTimes()修復時間戳是一種在稍後的窗口中拾取文件的方法,即使其內容未更改。

使用對象存儲作爲數據源

“完整”文件系統(如HDFS)會在創建輸出流後立即在其文件上設置修改時間。打開文件時,即使在數據完全寫入之前,它也可能包含在DStream-after將忽略同一窗口中文件大的更新。即:可能會遺漏更改,並從流中省略數據。

要確保在窗口中選擇更改,請將文件寫入不受監視的目錄,然後在關閉輸出流後立即將其重命名爲目標目錄。如果重命名的文件在其創建窗口期間出現在掃描的目標目錄中,則將拾取新數據。

相比之下,Amazon S3和Azure Storage等對象存儲通常具有較慢的重命名操作,因爲實際上是複製了數據。此外,重命名的對象可能將rename()操作的時間作爲其修改時間,因此可能不被視爲原始創建時間所暗示的窗口的一部分。

需要對目標對象存儲進行仔細測試,以驗證存儲的時間戳行爲是否與Spark Streaming所期望的一致。可能是直接寫入目標目錄是通過所選對象存儲流傳輸數據的適當策略。

基於自定義接收器的流

可以使用通過自定義接收器接收的數據流創建DStream。

RDD作爲流的隊列

爲了測試帶有測試數據的Spark Streaming應用程序,還可以使用基於RDD隊列streamingContext.queueStream(queueOfRDDs)創建DStream。推入隊列的每個RDD將被視爲DStream中的一批數據,並像流一樣處理。

高級資源

從Spark2.3.0開始,在這些源代碼中,Kafka,Kinesis和Flume在Python API中可用,咱不關注。此類源需要與外部非Spark庫連接,其中一些庫具有複雜的依賴性(例如,Kafka和Flume)。因此,爲了最大限度地減少與依賴項版本衝突相關的問題,從這些源創建DStream的功能已移至可在必要時顯示連接的單獨庫。

請注意,Spark shell中不提供這些高級資源,因此無法在shell中測試基於這些高級資源的應用程序。如果我們真的想在Spark shell中使用它們,則必須下載相應的Maven依賴,並將其添加到類路徑中。

其中一些高級資源的版本兼容如下:

  • Kafka:Spark Streaming 2.3.0與Kafka broker版本 0.8.2.1或更高版本兼容
  • Flume:Spark Streaming 2.3.0與Flume 1.6.0兼容。
  • Kinesis:Spark Streaming 2.3.0與Kinesis Client Library 1.2.1兼容。

自定義來源

輸入DStream也可以從自定義數據源創建。我們所要做的就是實現一個用戶自定義的接收器,它可以從自定義源接收數據並將其推送到Spark。

接收器可靠性

根據其可靠性,可以有兩種數據源。資源(如Kafka和Flume)允許傳輸數據得到確認。如果從這些可靠來源接收數據的系統正確地確認接收到地數據,則可以確保不會因任何類型地故障而丟失數據。這導致兩種接收器:

  1. 可靠的接收器:可靠的接收器在接收到數據並將其存儲在帶複製的Spark中時,正確地將確認發送到可靠地源。
  2. 不可靠地接收器:一個不可靠地接收器並沒有發送確認地資源等。這可以用於不支持確認地源,甚至可以用於不需要或需要進入確認複雜性的可靠源。

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章