《spark streaming源碼八》ReceiverTraker, ReceivedBlockTracker 詳解

轉載自https://github.com/lw-lin/CoolplaySpark

本系列內容適用範圍:

* 2017.07.11 update, Spark 2.2 全系列 √ (已發佈:2.2.0)
* 2017.10.02 update, Spark 2.1 全系列 √ (已發佈:2.1.0, 2.1.1, 2.1.2)
* 2016.11.14 update, Spark 2.0 全系列 √ (已發佈:2.0.0, 2.0.1, 2.0.2)

目錄

 

引言

ReceiverTracker 詳解

(1) ReceiverTracker 分發和監控 Receiver

(2) ReceiverTracker 作爲 RpcEndpoint

(3) ReceiverTracker 管理塊數據的 meta 信息

ReceivedBlockTracker 詳解

總結


引言

我們在 [Spark Streaming 實現思路與模塊概述](Spark Streaming 實現思路與模塊概述.md) 給出了 模塊 3:數據產生與導入的基本工作流程:

  • (1) 由 Receiver 的總指揮 ReceiverTracker 分發多個 job(每個 job 有 1 個 task),到多個 executor 上分別啓動 ReceiverSupervisor 實例;

  • (2) 每個 ReceiverSupervisor 啓動後將馬上生成一個用戶提供的 Receiver 實現的實例 —— 該 Receiver 實現可以持續產生或者持續接收系統外數據,比如 TwitterReceiver 可以實時爬取 twitter 數據 —— 並在 Receiver 實例生成後調用 Receiver.onStart()

(1)(2) 的過程由上圖所示,這時 Receiver 啓動工作已運行完畢。

接下來 ReceiverSupervisor 將在 executor 端作爲的主要角色,並且:

  • (3) Receiver 在 onStart() 啓動後,就將持續不斷地接收外界數據,並持續交給 ReceiverSupervisor 進行數據轉儲;

  • (4) ReceiverSupervisor 持續不斷地接收到 Receiver 轉來的數據:

    • 如果數據很細小,就需要 BlockGenerator 攢多條數據成一塊(4a)、然後再成塊存儲(4b 或 4c)

    • 反之就不用攢,直接成塊存儲(4b 或 4c)

    • 這裏 Spark Streaming 目前支持兩種成塊存儲方式,一種是由 blockManagerskManagerBasedBlockHandler 直接存到 executor 的內存或硬盤,另一種由 WriteAheadLogBasedBlockHandler 是同時寫 WAL(4c) 和 executor 的內存或硬盤

  • (5) 每次成塊在 executor 存儲完畢後,ReceiverSupervisor 就會及時上報塊數據的 meta 信息給 driver 端的 ReceiverTracker;這裏的 meta 信息包括數據的標識 id,數據的位置,數據的條數,數據的大小等信息。

  • (6) ReceiverTracker 再將收到的塊數據 meta 信息直接轉給自己的成員 ReceivedBlockTracker,由 ReceivedBlockTracker 專門管理收到的塊數據 meta 信息。

 

這裏 (3)(4)(5)(6) 的過程是一直持續不斷地發生的,我們也將其在上圖裏標識出來。

上面的內容我們已經在 [Receiver 分發詳解](3.1 Receiver 分發詳解.md) 和 [Receiver, ReceiverSupervisor, BlockGenerator, ReceivedBlockHandler 詳解](3.2 Receiver, ReceiverSupervisor, BlockGenerator, ReceivedBlockHandler 詳解.md) 中介紹過了。

本文我們詳解的是 driver 端的 ReceiverTracker 和 ReceivedBlockTracker

ReceiverTracker      的全限定名是:org.apache.spark.streaming.scheduler.ReceiverTracker
ReceivedBlockTracker 的全限定名是:org.apache.spark.streaming.scheduler.ReceivedBlockTracker

ReceiverTracker 詳解

ReceiverTracker 在 Spark 1.5.0 版本里的代碼變動比較大,不過其主要功能還是沒怎麼改變,我們一一來看:

  • (1) ReceiverTracker 分發和監控 Receiver
    • ReceiverTracker 負責 Receiver 在各個 executor 上的分發
    • 包括 Receiver 的失敗重啓
  • (2) ReceiverTracker 作爲 RpcEndpoint
    • ReceiverTracker 作爲 Receiver 的管理者,是各個 Receiver 上報信息的入口
    • 也是 driver 下達管理命令到 Receiver 的出口
  • (3) ReceiverTracker 管理已上報的塊數據 meta 信息

整體來看,ReceiverTracker 就是 Receiver 相關信息的中樞。

(1) ReceiverTracker 分發和監控 Receiver

ReceiverTracker 分發和監控 Receiver 的內容我們已經在 [Receiver 分發詳解.md](3.1 Receiver 分發詳解.md) 詳解過了,我們這裏總結一下。

在 ssc.start() 時,將隱含地調用 ReceiverTracker.start();而 ReceiverTracker.start() 最重要的任務就是調用自己的 launchReceivers() 方法將 Receiver 分發到多個 executor 上去。然後在每個 executor 上,由 ReceiverSupervisor 來分別啓動一個 Receiver 接收數據。這個過程用下圖表示:

而且在 1.5.0 版本以來引入了 ReceiverSchedulingPolicy,是在 Spark Streaming 層面添加對 Receiver 的分發目的地的計算,相對於之前版本依賴 Spark Core 的 TaskScheduler 進行通用分發,新的 ReceiverSchedulingPolicy 會對 Streaming 應用的更好的語義理解,也能計算出更好的分發策略。

並且還通過每個 Receiver 對應 1 個 Job 的方式,保證了 Receiver 的多次分發,和失效後的重啓、永活。

從本小節 ReceiverTracker 分發和監控 Receiver 的角度,我們對以前版本的 Spark Streaming(以 1.4.0 爲代表)、和新版本的 Spark Streaming(以 1.5.0 爲代表)有總結對比:

Spark Streaming 1.4.0 Spark Streaming 1.5.0
Receiver 活性 不保證永活 無限重試、保證永活
Receiver 均衡分發 無保證 round-robin 策略
自定義 Receiver 分發 很 tricky 方便

 

(2) ReceiverTracker 作爲 RpcEndpoint

RpcEndPoint 可以理解爲 RPC 的 server 端,供 client 調用。

ReceiverTracker 作爲 RpcEndPoint 的地址 —— 即 driver 的地址 —— 是公開的,可供 Receiver 連接;如果某個 Receiver連接成功,那麼 ReceiverTracker 也就持有了這個 Receiver 的 RpcEndPoint。這樣一來,通過發送消息,就可以實現雙向通信。

1.5.0 版本以來,ReceiverTracker 支持的消息有 10 種,我們進行一個總結:

StopAllReceivers 消息 消息 解釋
ReceiverTracker
只接收、不回覆
StartAllReceivers 消息 在 ReceiverTracker 剛啓動時,發給自己這個消息,觸發具體的 schedulingPolicy 計算,和後續分發
RestartReceiver 消息 當初始分發的 executor 不對,或者 Receiver 失效等情況出現,發給自己這個消息,觸發 Receiver 重新分發
CleanupOldBlocks 消息 當塊數據已完成計算不再需要時,發給自己這個消息,將給所有的 Receiver 轉發此 CleanupOldBlocks 消息
UpdateReceiverRateLimit 消息 ReceiverTracker 動態計算出某個 Receiver 新的 rate limit,將給具體的 Receiver 發送 UpdateRateLimit 消息
ReportError 消息 是由 Receiver 上報上來的,將觸發 reportError() 方法向 listenerBus 擴散此 error 消息
ReceiverTracker
接收並回復
RegisterReceiver 消息 由 Receiver 在試圖啓動的過程中發來,將回復允許啓動,或不允許啓動
AddBlock 消息 具體的塊數據 meta 上報消息,由 Receiver 發來,將返回成功或失敗
DeregisterReceiver 消息 由 Receiver 發來,處理後,無論如何都返回 true
AllReceiverIds 消息 在 ReceiverTracker stop() 的過程中,查詢是否還有活躍的 Receiver
StopAllReceivers 消息 在 ReceiverTracker stop() 的過程剛開始時,要求 stop 所有的 Receiver;將向所有的 Receiver 發送 stop 信息

(3) ReceiverTracker 管理塊數據的 meta 信息

一方面 Receiver 將通過 AddBlock 消息上報 meta 信息給 ReceiverTracker,另一方面 JobGenerator 將在每個 batch 開始時要求 ReceiverTracker 將已上報的塊信息進行 batch 劃分,ReceiverTracker 完成了塊數據的 meta 信息管理工作。

具體的,ReceiverTracker 有一個成員 ReceivedBlockTracker,專門負責已上報的塊數據 meta 信息管理。

ReceivedBlockTracker 詳解

我們剛剛講到,ReceivedBlockTracker 專門負責已上報的塊數據 meta 信息管理,但 ReceivedBlockTracker 本身不負責對外交互,一切都是通過 ReceiverTracker 來轉發 —— 這裏 ReceiverTracker 相當於是 ReceivedBlockTracker 的門面(可參考 門面模式)。

在 ReceivedBlockTracker 內部,有幾個重要的成員,它們的關係如下:

  • streamIdToUnallocatedBlockQueues
    • 維護了上報上來的、但尚未分配入 batch 的 Block 塊數據的 meta
    • 爲每個 Receiver 單獨維護一個 queue,所以是一個 HashMap:receiverId → mutable.Queue[ReceivedBlockInfo]
  • timeToAllocatedBlocks
    • 維護了上報上來的、已分配入 batch 的 Block 塊數據的 meta
    • 按照 batch 進行一級索引、再按照 receiverId 進行二級索引的 queue,所以是一個 HashMap: time → HashMap
  • lastAllocatedBatchTime
    • 記錄了最近一個分配完成的 batch 是哪個

上面是用於狀態記錄的主要數據結構。對這些狀態存取主要是 4 個方法:

  • addBlock(receivedBlockInfo: ReceivedBlockInfo)
    • 收到某個 Receiver 上報上來的塊數據 meta 信息,將其加入到 streamIdToUnallocatedBlockQueues 裏
  • allocateBlocksToBatch(batchTime: Time)
    • 主要是 JobGenerator 在發起新 batch 的計算時,第一步就調用本方法
    • 是將 streamIdToUnallocatedBlockQueues 的內容,以傳入的 batchTime 參數爲 key,添加到 timeToAllocatedBlocks
    • 並更新 lastAllocatedBatchTime
  • getBlocksOfBatch(batchTime: Time)
    • 主要是 JobGenerator 在發起新 batch 的計算時,由 DStreamGraph 生成 RDD DAG 實例時,將調用本方法
    • 調用本方法查 timeToAllocatedBlocks,獲得劃入本 batch 的塊數據元信息,由此生成處理對應塊數據的 RDD
  • cleanupOldBatches(cleanupThreshTime: Time, ...)
    • 主要是當一個 batch 已經計算完成、可以把已追蹤的塊數據的 meta 信息清理掉時調用
    • 將清理 timeToAllocatedBlocks 表裏對應 cleanupThreshTime 之前的所有 batch 塊數據 meta 信息

這 4 個方法,和對應信息狀態的修改關係如下圖總結:

 

上面即是 ReceivedBlockTracker 的主體內容。

但我們還需要強調一點非常重要的內容,即 ReceivedBlockTracker 需要對 driver 進行容錯保障。也就是,如果 driver 失效,新起來的 driver 必須能夠通過 WAL 恢復出失效前的 ReceivedBlockTracker 狀態,具體的就需要包括 streamIdToUnallocatedBlockQueuestimeToAllocatedBlockslastAllocatedBatchTime 等內容,也即需要前面講的 4 個方法在修改 ReceivedBlockTracker 的狀態信息的時候,要首先寫入 WAL,才能在失效後從 WAL 恢復出相關信息。

有關 WAL 寫入和故障恢復的內容,我們將在 模塊 4:長時容錯 裏系統性的詳解。

總結

本文主要詳解了 driver 端的 Receiver 管理者 —— ReceiverTracker —— 的主要功能:

  • (1) ReceiverTracker 分發和監控 Receiver
    • ReceiverTracker 負責 Receiver 在各個 executor 上的分發
    • 包括 Receiver 的失敗重啓
  • (2) ReceiverTracker 作爲 RpcEndpoint
    • ReceiverTracker 作爲 Receiver 的管理者,是各個 Receiver 上報信息的入口
    • 也是 driver 下達管理命令到 Receiver 的出口
  • (3) ReceiverTracker 管理已上報的塊數據 meta 信息
    • 委託給自己的成員 ReceivedBlockManager 進行具體管理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章