Spark 定製版:002~Spark Streaming(二)

本講內容:

a. 解密Spark Streaming運行機制
b. 解密Spark Streaming架構

注:本講內容基於Spark 1.6.1版本(在2016年5月來說是Spark最新版本)講解。

上節回顧:

上節課談到技術界的尋龍點穴,Spark就是大數據的龍脈,而Spark Streaming就是Spark的穴位。假如要構建一個強大的Spark應用程序 ,Spark Streaming 是一個值得借鑑的參考,Spark Streaming涉及多個job交叉配合,幾乎可以包括spark的所有的核心組件,如果對Spark Streaming精通了的話,可以說就精通了整個Spark,因此精通並掌握Spark Streaming是至關重要的。

在Spark官網(這裏寫鏈接內容)中,可以看到如下圖所示:

這裏寫圖片描述

Spark Core上面有4個流行的框架:Spark SQL、Spark Streaming、機器學習、圖計算。除了Spark Streaming,其他的子框架大多都是在Spark Core上對一些算法或者接口進行了高層的封裝。例如Spark SQL 封裝了SQL語法,主要功能就是將SQL語法解析成Spark Core的底層API。而機器學習則是封裝了許多的數學向量及算法。GraphX目前也沒有太大的更新。

而Spark Streaming更像是對Spark Core的衍生子框架,可想而知,他是相當複雜的一個應用程序。同時我們也不難發現,基於Spark Core的時候,都是基於RDD編程,Spark Streaming則是基於DStream編程。DStream是邏輯級別的,而RDD是物理級別的。DStream是隨着時間的流動內部將集合封裝RDD。對DStream的操作,歸根結底還是對其RDD進行的操作。

我們查看上一節中Spark Streaming的運行日誌,就可以看出和RDD的運行幾乎是一致的:

這裏寫圖片描述

SparkStreaming Job在運行的時候,首先會生成DStream的Graph,在特定的時間將DStream Graph轉換成RDD Graph。然後再去運行RDD的job 。如下圖:

這裏寫圖片描述

從這個角度來講,可以將Spark Streaming放在座標系中。其中Y軸就是對RDD的操作,RDD的依賴關係構成了整個job的邏輯,而X軸就是時間。隨着時間的流逝,固定的時間間隔(Batch Interval)就會生成一個job實例,進而在集羣中運行。

這裏寫圖片描述

由此爲大家詳細總結並揭祕 Spark Streaming五大核心特徵

特徵1:邏輯管理

DStream是對RDD封裝的集合,作用於DStream的操作會對其中每個RDD進行作用,DStream Graph就是RDD Graph的模板,其邏輯管理完全繼承RDD的DAG關係。

特徵2:時間管理

Spark Streaming的最大特徵是引入了時間屬性,DStream在RDD的基礎上增加了時間緯度,隨着時間的緯度,不斷把模板實例化,通過動態Job控制器運行作業。

特徵3:流式輸入和輸出

以InputStream和OutputStream爲核心,進行流式的數據輸入輸出。

特徵4:高容錯

具體Job運行在Spark Cluster之上,此時系統容錯就至關重要。

主要思路:

a、限流
b、根據需要調整資源安排

特徵5:事務處理

在處理出現崩潰的情況下確保Exactly once的事務語義。主要通過檢查點等技術實現。(下一講再細說)

結合Spark Streaming源碼進一步解析:

StreamingContext方法中調用JobScheduler的start方法(StreamingContext.scala,610行代碼)

這裏寫圖片描述

JobGenerator的start方法中,調用startFirstTime方法,來開啓定時生成Job的定時器

JobScheduler.scala,83行代碼
這裏寫圖片描述
JobGenerator.scala,98行代碼
這裏寫圖片描述

startFirstTime方法,首先調用DStreamGraph的start方法,然後再調用RecurringTimer的start方法。

JobGenerator.scala,193行代碼
這裏寫圖片描述
DStreamGraph.scala,39行代碼
這裏寫圖片描述
RecurringTimer.scala,59行代碼
這裏寫圖片描述

timer對象爲一個定時器,根據batchInterval時間間隔定期向EventLoop發送GenerateJobs的消息。

JobGenerator.scala,58~59行代碼
這裏寫圖片描述

接收到GenerateJobs消息後,會回調generateJobs方法。

JobGenerator.scala,181行代碼
這裏寫圖片描述

generateJobs方法再調用DStreamGraph的generateJobs方法生成Job

JobGenerator.scala,248行代碼
這裏寫圖片描述
DStreamGraph.scala,248行代碼
這裏寫圖片描述

DStreamGraph的實例化是在StreamingContext中的

(StreamingContext.scala,162~164行代碼)
這裏寫圖片描述

在DStreamGraph的類中還保存了輸入流和輸出流的信息

(DStreamGraph.scala,29~30行代碼)
這裏寫圖片描述

DStream類中依賴、計算、保存RDD信息

(DStream.scala,74、77、85行代碼)
這裏寫圖片描述

回到JobScheduler的start方法中receiverTracker.start()

(JobScheduler.scala,82行代碼)
這裏寫圖片描述
(ReceiverTracker.scala,149行代碼)
這裏寫圖片描述

其中ReceiverTrackerEndpoint對象爲一個消息循環體

(ReceiverTracker.scala,449行代碼)
這裏寫圖片描述

launchReceivers方法中發送StartAllReceivers消息

(ReceiverTracker.scala,413行代碼)
這裏寫圖片描述

接收到StartAllReceivers消息後,進行如下處理

(ReceiverTracker.scala,454行代碼)
這裏寫圖片描述
(ReceiverTracker.scala,594行代碼)
這裏寫圖片描述

StartReceiverFunc方法如下,實例化Receiver監控者,開啓並等待退出

(ReceiverTracker.scala,573行代碼)
這裏寫圖片描述

supervisor的start方法中調用startReceiver方法

(ReceiverSupervisor.scala,130行代碼)
這裏寫圖片描述
(ReceiverSupervisor.scala,148行代碼)
這裏寫圖片描述

舉例解析:
以socketTextStream爲例,其啓動的是SocketReceiver,內部開啓一個線程,來接收數據

(SocketInputDStream.scala,55~60行代碼)
這裏寫圖片描述
(SocketInputDStream.scala,73、77行代碼)
這裏寫圖片描述

store(iterator.next)內部調用Receiver中的store方法裏supervisor的pushSingle方法,最終將數據聚集後存放在內存中

(Receiver.scala,73、77行代碼)
這裏寫圖片描述

supervisor的pushSingle方法如下,將數據放入到defaultBlockGenerator中,defaultBlockGenerator爲BlockGenerator,保存Socket接收到的數據

(ReceiverSupervisorImpl.scala,118行代碼)
這裏寫圖片描述
(BlockGeneratorListener.scala,162、165行代碼)
這裏寫圖片描述

BlockGenerator對象中有一個定時器,來更新當前的Buffer

(BlockGenerator.scala,106行代碼)
這裏寫圖片描述
(BlockGenerator.scala,241、246行代碼)
這裏寫圖片描述

BlockGenerator對象中有一個線程,來從阻塞隊列中取出數據

(BlockGenerator.scala,109行代碼)
這裏寫圖片描述
(BlockGenerator.scala,278行代碼)
這裏寫圖片描述
(BlockGenerator.scala,296行代碼)
這裏寫圖片描述

接下來會調用ReceiverSupervisorImpl類中的繼承BlockGeneratorListener的匿名類中的onPushBlock方法

(ReceiverSupervisorImpl.scala,108行代碼)
這裏寫圖片描述
(ReceiverSupervisorImpl.scala,123、128行代碼)
這裏寫圖片描述
(ReceiverSupervisorImpl.scala,157、161行代碼)
這裏寫圖片描述

receivedBlockHandler對象如下

(ReceiverSupervisorImpl.scala,53~64行代碼)
這裏寫圖片描述

這裏我們講解BlockManagerBasedBlockHandler的方式

(BlockManagerBasedBlockHandler.scala,74、79、81行代碼)
這裏寫圖片描述

trackerEndpoint如下

(ReceiverSupervisorImpl.scala,70行代碼)
這裏寫圖片描述
(RpcUtils.scala,31行代碼)
這裏寫圖片描述

其實是發送給ReceiverTrackerEndpoint類

(ReceiverTracker.scala,156行代碼)
這裏寫圖片描述
(ReceiverTracker.scala,495、507行代碼)
這裏寫圖片描述
(ReceivedBlockTracker.scala,90行代碼)
這裏寫圖片描述
(ReceiverInputDStream.scala,69、81、85行代碼)
這裏寫圖片描述

InputInfoTracker類的reportInfo方法只是對數據進行記錄統計

(InputInfoTracker.scala,64行代碼)
這裏寫圖片描述
(DStreamGraph.scala,442、446、448行代碼)
這裏寫圖片描述
(DStreamGraph.scala,352行代碼)
這裏寫圖片描述

其generateJob方法是被DStreamGraph調用

(DStreamGraph.scala,115行代碼)
這裏寫圖片描述

DStreamGraph的generateJobs方法是被JobGenerator類的generateJobs方法調用

(JobGenerator.scala,248行代碼)
這裏寫圖片描述

JobGenerator類中有一個定時器,batchInterval發送GenerateJobs消息

(JobGenerator.scala,59行代碼)
這裏寫圖片描述

源碼解密總結:

a,當調用StreamingContext的start方法時,啓動了JobScheduler

b,當JobScheduler啓動後會先後啓動ReceiverTracker和JobGenerator

c,ReceiverTracker啓動後會創建ReceiverTrackerEndpoint這個消息循環體,來接收運行在Executor上的Receiver發送過來的消息

d,ReceiverTracker在啓動時會給自己發送StartAllReceivers消息,自己接收到消息後,向Spark提交startReceiverFunc的Job

e,startReceiverFunc方法中在Executor上啓動Receiver,並實例化ReceiverSupervisorImpl對象,來監控Receiver的運行

f,ReceiverSupervisorImpl對象會調用Receiver的onStart方法,我們以SocketReceiver爲例,啓動一個線程,連接Server,讀取網絡數據先調用ReceiverSupervisorImpl的pushSingle方法,

保存在BlockGenerator對象中,該對象內部有個定時器,放到阻塞隊列blocksForPushing,等待內部線程取出數據放到BlockManager中,併發AddBlock消息給ReceiverTrackerEndpoint。

ReceiverTrackerEndpoint爲ReceiverTracker的內部類,在接收到addBlock消息後將streamId對應的數據阻塞隊列streamIdToUnallocatedBlockQueues中

g,JobGenerator啓動後會啓動以batchInterval時間間隔發送GenerateJobs消息的定時器

h,接收到GenerateJobs消息會先後觸發ReceiverTracker的allocateBlocksToBatch方法和DStreamGraph的generateJobs方法

i,ReceiverTracker的allocateBlocksToBatch方法會調用getReceivedBlockQueue方法從阻塞隊列streamIdToUnallocatedBlockQueues中根據streamId獲取數據

j,DStreamGraph的generateJobs方法,繼而調用變量名爲outputStreams的DStream集合的generateJob方法

k,繼而調用DStream的getOrCompute來調用具體的DStream的compute方法,我們以ReceiverInputDStream爲例,compute方法是從ReceiverTracker中獲取數據

經典直說:
  在空間維度上的業務邏輯作用於DStream,隨着時間的流逝,每個Batch Interval形成了具體的數據集,產生了RDD,對RDD進行transform操作,進而形成了RDD的依賴關係RDD DAG,形成job。然後jobScheduler根據時間調度,基於RDD的依賴關係,把作業發佈到Spark Cluster上去運行,不斷的產生Spark作業。

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