Spark 定製版:010~Spark Streaming源碼解讀之流數據不斷接收全生命週期徹底研究和思考

本講內容:

a. 數據接收架構設計模式
b. 數據接收源碼徹底研究

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

上節回顧

上一講中,我們給大傢俱體分析了Receiver啓動的方式及其啓動設計帶來的多個問題:

a. 如果有多個InputDStream,那就要啓動多個Receiver,每個Receiver也就相當於分片partition,那我啓動Receiver的時候理想的情況下是在不同的機器上啓動Receiver,但是Spark Core的角度來看就是應用程序,感覺不到Receiver的特殊性,所以就會按照正常的Job啓動的方式來處理,極有可能在一個Executor上啓動多個Receiver;這樣的話就可能導致負載不均衡

b. 有可能啓動Receiver失敗,只要集羣存在,Receiver就不應該啓動失敗

c. 從運行過程中看,一個Reveiver就是一個partition的話,Reveiver的啓動伴隨一個Task啓動,如果Task啓動失敗,以Task啓動的Receiver也會失敗

由此,我們通過源碼分析,徹底解析了Spark Streaming是如何解決這些問題的:

a. Spark使用一個Job啓動一個Receiver.最大程度的保證了負載均衡

b. Spark Streaming已經指定每個Receiver運行在那些Executor上,在Receiver運行之前就指定了運行的地方

c. 如果Receiver啓動失敗,此時並不是Job失敗,在內部會重新啓動Receiver

開講

本講我們主要給大家介紹Spark Streaming在接收數據的全生命週期貫通;

a. 當有Spark Streaming有應用程序的時候Spark Streaming會持續不斷的接收數據

b. 一般Receiver和Driver不在一個進程中的,所以接收到數據之後要不斷的彙報給Driver

c. Spark Streaming要接收數據肯定要使用消息循環器,循環器不斷的接收到數據之後,然後將數據存儲起來,再將存儲完的數據彙報給Driver

d. Sparkstreaming接收數據的整個流程類似於MVC模式,M就是Receiver,V就是Driver,C就是ReceiverSupervisor

e. ReceiverSupervisor是控制器,Receiver的啓動是靠ReceiverTracker啓動的,Receiver接收到數據之後是靠ReceiverSupervisor存儲數據的。然後Driver就獲得元數據也就是界面,通過界面來操作底層的數據,這個元數據就相當於指針

Spark Streaming接收數據流程如下:

這裏寫圖片描述

接收數據的時候肯定有一個循環器不斷的接收數據,接收到數據肯定也有存儲器,存儲過之後向Driver彙報。接收數據和存儲數據當然要分爲兩個不同的模塊。

這裏寫圖片描述

ReceiverSupervisorImpl是receiver的監控器,同時負責receiver的寫操作 這個方法需要傳入一個Iterator,實時上裏邊就只有一個Receiver

獲得receiver,這個receiver是根據數據輸入來源InputDstream獲得的receiver。以SocketInputDstream爲例,它的receiver就是SocketReceiver.這裏的receiver只是一個引用,並沒有被實例化。作爲一個參數傳入ReceiverSupervisorImpl

這裏寫圖片描述

爲了啓動Receiver啓動了一個spark作業,每一個Receiver的啓動都會有一個作業來負責,Receiver是一個一個的啓動的如果是將所有的Receiver作爲一個作業的不同task來啓動會有很多弱點

a. Reciver啓動可能失敗進而導致應用程序失敗
b. 運行的過程中會有任務傾斜的問題,將所有的Receiver作爲一個作業的不同task來運行是採用的spark core的調度方式,在很不幸的情況下會出現所有Receiver運行在一個節點上,Receiver要不斷的接收數據,需要消耗很多資源,就會導致這個節點負載特別大。

將每個Receiver都作爲一個job來運行就會最大可能的負載均衡,不過這樣也有可能失敗,失敗之後不會重試job,而是從新schedule提交一個新的job來運行

Receiver,並且不會在之前運行的executor上啓動,只要sparkstreaming程序不停止,假如Receiver出故障就會不休止的進行重新echedule並啓動,確保Receiver一定會啓動還有很重要的一點是,當重新啓動一個Receiver時,是用一個線程池在新的線程中啓動的

這裏寫圖片描述

ReceiverSupervisorImpl負責處理Receiver接收到的數據,處理之後彙報給ReceiverTracker,所以ReceiverSupervisorImpl內部有和ReceiverTracker進行通信的endpoint。這個負責向ReceiverTracker發送消息。

private val trackerEndpoint = RpcUtils.makeDriverRef(“ReceiverTracker”, env.conf,env.rpcEnv)

這個負責接收ReceiverTracker發送的消息,CleanupOldBlocks是用來清除運行完的每個batch的Blocks,UpdateRateLimit是用來隨時調整限流(限流其實是限的數據存儲的速度)

這裏寫圖片描述

ReceiverSupervisor的start方法

這裏寫圖片描述

在onStart中啓動的是BlockGenerator,BlockGenerator是把接收到的一條一條的數據生成block存儲起來,一個BlockGenerator只服務於一個Receiver。所以BlockGenerator要在Receiver啓動之前啓動

這裏寫圖片描述

BlockGenerator種有一個定時器。這個定時器每隔一定(默認是200ms,和設定的batchduration無關)的時間就執行如下方法。這個方法就是把接收到的數據一條一條的放入到這個buffer緩存中,再把這個buffer按照一定的時間或者尺寸合併成block。除了定時器以外還有一條線程不停的把生成的block交給blockmanager存儲起來。

這裏寫圖片描述

下面來看startReceiver方法

這裏寫圖片描述

在啓動Receiver之前還要向ReceiverTracker請求是否可以啓動Receiver。當返回是true纔會啓動。ReceiverTracker接收到彙報的信息就把註冊Receiver的信息。

這裏寫圖片描述

Receiver的啓動只是調用receiver.onStart(),Receiver就在work節點上運行了

以SocketReceiver爲例我看看它的onStart方法

這裏寫圖片描述

發佈了42 篇原創文章 · 獲贊 11 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章