Bitswap 作爲 IPFS 網絡數據交換接口的具體實現,主要關注如何快速、高效獲取需要的區塊。

原文標題:《揭祕 IPFS 數據交換模塊 Bitswap》
撰文:馬耀耀,就職於數據網格實驗室 BitXMesh

星際文件系統(InterPlanetary File System,縮寫 IPFS)是一個旨在創建持久且分佈式存儲和共享文件的網絡傳輸協議。

與傳統的文件系統不同,它是一種基於內容尋址的點對點超媒體分發協議。

IPFS 網絡中的節點構成一個分佈式文件系統網絡,其中 Bitswap 是 IPFS 的核心模塊,負責與網絡中其他節點之間請求和發送數據塊。

技術解析 IPFS 數據交換模塊 Bitswap 架構與工作機制圖 1

IPFS 將文件分解爲稱爲 block 的數據塊,這些塊由內容標識符(CID)標識。

IPFS 文件內容存儲在不同的節點上,每個節點存儲 root block,少量節點存儲完整文件數據,大部分節點存儲部分文件 block。因爲 block 分散存儲在不同節點,Bitswap 協議解決了從多個節點高效獲取全部數據塊的問題

技術解析 IPFS 數據交換模塊 Bitswap 架構與工作機制圖 2 多節點文件存儲示意圖

總體架構

本文基於 Bitswap v0.3.3 版本進行分析。

IPFS 向 Bitswap 獲取 block,Bitswap 是 IPFS exchange 接口的具體實現,負責完成 IPFS 網絡數據交換功能。

技術解析 IPFS 數據交換模塊 Bitswap 架構與工作機制圖 3 Bitswap 組件架構圖

Bitswap 協議內容比較繁瑣,爲了降低實現複雜度協議劃分爲 block 請求模塊、block 發送模塊、會話管理模塊、block 提供者發現模塊、網絡模塊等。

Bitswap 模塊負責接收新的消息並且提供對外數據交換接口。

session 管理模塊用來管理多個 session,每個 session 管理一組文件的下載,來提高下載效率。

block 發送模塊負責管理向其它節點發送數據塊。block 請求模塊負責管理數據塊的請求。block 提供者發現模塊負責通過 DHT 網絡發現網絡中的數據塊,通常 session 找不到已擁有所需 block 的節點時會調用此模塊進行數據塊發現。

協議概述

爲了完成節點間 block 交換,Bitswap 定義了通信消息及通信協議。

技術解析 IPFS 數據交換模塊 Bitswap 架構與工作機制圖 4

Bitswap 消息處理流程:

  1. IPFS 請求文件區塊,Bitswap 發送 want-have 消息攜帶 CID1 信息到連接的所有節點。節點根據自己是否有 CID1 文件塊返回 have 或 dont-have 消息。
  2. client 向擁有 CID1 的節點發送 want-block 消息,節點返回相應的 block 消息。
  3. 當沒有節點有請求的 block,Bitswap 廣播 want-have 到所有的連接節點,或者通過 DHT 查找擁有文件區塊的節點。

模塊詳解

Bitswap 模塊

Bitswap 模塊負責接收新消息並且實現對外的數據交換接口。

當接收到新消息後,Bitswap 處理流程:

  1. 記錄有關消息的一些統計信息
  2. 通知發送模塊 wants 消息,這樣數據發送模塊可以根據實際情況向需求節點發送響應消息。
  3. 通知發送模塊任何收到的 blocks,發送模塊根據節點的需求列表可以將接收到的塊發送給任何需要它們的節點
  4. 向 SessionManager 通知接收到的 blocks,HAVEs 和 DONT_HAVEs 消息,這樣 SessionManager 可以通知消息相關的 session。

Bitswap 通過 Facade Pattern 提高了模塊使用的便利性,使得 Bitswap 子系統的用法變得簡單,避免了 IPFS 和 Bitswap 的高度耦合。

Session 管理模塊

session 管理模塊用來管理多個數據塊下載 session,每個 session 管理一組文件的下載。

當 SessionManager 收到新消息時,它將

  1. 通知 BlockPresenceManager 組件跟蹤每個 block。
  2. 通知對接收到的 block 感興趣並想要的 Sessions。
  3. 通知 PeerManager 組件收到的 block,PeerManager 檢查是否有任何 wants 被髮送到節點以接收已經收到的塊。 如果是這樣,它將向那些節點發送「CANCEL」消息,防止其它節點重複發送消息。

Session 管理模塊通過協調多個 session 的數據需求來提高數據交互的效率,避免數據塊的重複請求、發送。

Session 模塊

Session 管理一組文件的下載,用來提高一組文件塊,比如單個文件下載效率。當 IPFS 調用 Bitswap 時,Bitswap 會創建一個新的 Session 並調用 Session 的相應方法,比如 GetBlocks() 獲取 blocks。Session 會管理一個節點列表,數據獲取過程只會向 session 中的節點獲取數據,而不是所有的連接節點。當 Session 中的節點都沒有某個 block 時,Bitswap 纔會通過 DHT 獲取具有 block 的節點並加入 session。

由於 session 剛開始沒有任何節點,處於「discovery」模式。當 IPFS 最初從 session 請求 block 時,該 session 處理流程如下:

  1. 通知 SessionInterestManager 組件它感興趣的 block。
  2. 通知 sessionWantManager 組件需要的 block。
  3. 通知 PeerManager 組件向連接節點發送「want-have」消息,以發現哪些節點有需要的 block。
  4. 查詢 ProviderQueryManager 組件以發現哪些節點具有該 block。

當 session 收到帶有「 HAVE」或「 block」的消息時,它將通知 SessionPeerManager 組件。

當 session 收到帶有「 block」的消息時,它將通知 SessionInterestManager 組件。

一旦 session 具有節點,就不再處於「discovery」模式。當 IPFS 請求後續 block 時,session 將通知 sessionWantSender 組件。sessionWantSender 組件通知 PeerManager 組件向會話中的節點發送「 want-have」和「 want-block」消息。

對於 session 所需的每個 block,sessionWantSender 組件通過與 BlockPresenceManager 組件覈對哪些節點已爲該 block 發送了「 HAVE」,來確定哪個節點最有可能擁有該 block。如果多個節點發送過「 HAVE」,則會根據先前請求回覆速度來選擇節點。

由於 DHT 內容發現速度慢並且網絡帶寬消耗大,session 通過向一組含有目標數據塊可能性大的節點獲取數據,從而大大提高了數據塊獲取的效率。

Block 發送模塊

block 發送模塊負責管理向其它節點發送數據塊,包含節點需求管理組件(Ledger)和消息發送任務隊列(PeerTaskQueue)。

Engine 是 block 發送模塊的處理類,當 Engine 被告知有新的 wants 時

  1. 將 want 添加到 Ledger,Ledger 會存儲每個節點的需求列表。
  2. 檢查 blockstore 中的相應 block,並將任務添加到 PeerTaskQueue 組件。如果 block 庫沒有想要的 block,則添加「DONT_HAVE」任務;如果 blockstore 有 block,對於「want-have」添加了「HAVE」任務,對於「want-block」添加了「block」任務。
  3. 當 Engine 收到新 block 的消息時,它會檢查 Ledger 以查看是否有節點需要此 block。對於發送「want-have」的每個節點向 PeerTaskQueue 組件添加一個 「HAVE」任務,對於爲發送了「 want-block」的每個節點,向 PeerTaskQueue 組件添加一個「block」任務。
  4. Engine 會定期從 PeerTaskQueue 組件中取出任務,並創建帶有「 blocks」,「 HAVEs」和「 DONT_HAVEs」的消息。

PeerTaskQueue 組件通過對任務進行優先級排序,發送隊列中數據量最少的節點方具有最高優先級,通過這種流控措施,提高數據塊發送處理效率。

數據塊請求模塊

Block 請求模塊負責管理數據塊的請求。PeerManager 組件爲連接到 Bitswap 的每個節點創建一個 MessageQueue 組件,記錄了「want-have」 、「want-block」已發送到哪個節點,並將任何新的 wants 定向到正確的節點。並且 MessageQueue 組件通過合併多個 want 爲一條消息,然後將該消息發送給節點,從而提高了消息發送效率。

內容發現模塊

當 Bitswap 找不到已擁有所需 block 的節點時,它會使用 DHT 進行內容發現。Bitswap 通過 ProviderQueryManager 組件管理這些請求,ProviderQueryManager 組件對請求進行速率限制,並對進行中的請求進行重複刪除處理。

總結

Bitswap 作爲 IPFS 網絡數據交換接口的具體實現,設計並實現了一套高效的節點間交換數據的協議。

協議主要關注點是如何快速、高效獲取需要的 block,其中包括節點選擇策略,如何最大化利用每個節點的能力。

Bitswap 通過 Facade Pattern 提高了模塊使用的便利性,在具體實現上解耦複雜依賴到各功能模塊,從而降低系統實現的複雜度。