技术解析 IPFS 数据交换模块 Bitswap 架构与工作机制
温馨提示:这篇文章已超过879天没有更新,请注意相关的内容是否还可用!
Bitswap 作为 IPFS 网络数据交换接口的具体实现,主要关注如何快速、高效获取需要的区块。
原文标题:《揭秘 IPFS 数据交换模块 Bitswap》
撰文:马耀耀,就职于数据网格实验室 BitXMesh
星际文件系统(InterPlanetary File System,缩写 IPFS)是一个旨在创建持久且分布式存储和共享文件的网络传输协议。
与传统的文件系统不同,它是一种基于内容寻址的点对点超媒体分发协议。
IPFS 网络中的节点构成一个分布式文件系统网络,其中 Bitswap 是 IPFS 的核心模块,负责与网络中其他节点之间请求和发送数据块。
图 1
IPFS 将文件分解为称为 block 的数据块,这些块由内容标识符(CID)标识。
IPFS 文件内容存储在不同的节点上,每个节点存储 root block,少量节点存储完整文件数据,大部分节点存储部分文件 block。因为 block 分散存储在不同节点,Bitswap 协议解决了从多个节点高效获取全部数据块的问题。
图 2 多节点文件存储示意图
总体架构
本文基于 Bitswap v0.3.3 版本进行分析。
IPFS 向 Bitswap 获取 block,Bitswap 是 IPFS exchange 接口的具体实现,负责完成 IPFS 网络数据交换功能。
图 3 Bitswap 组件架构图
Bitswap 协议内容比较繁琐,为了降低实现复杂度协议划分为 block 请求模块、block 发送模块、会话管理模块、block 提供者发现模块、网络模块等。
Bitswap 模块负责接收新的消息并且提供对外数据交换接口。
session 管理模块用来管理多个 session,每个 session 管理一组文件的下载,来提高下载效率。
block 发送模块负责管理向其它节点发送数据块。block 请求模块负责管理数据块的请求。block 提供者发现模块负责通过 DHT 网络发现网络中的数据块,通常 session 找不到已拥有所需 block 的节点时会调用此模块进行数据块发现。
协议概述
为了完成节点间 block 交换,Bitswap 定义了通信消息及通信协议。
图 4
Bitswap 消息处理流程:
- IPFS 请求文件区块,Bitswap 发送 want-have 消息携带 CID1 信息到连接的所有节点。节点根据自己是否有 CID1 文件块返回 have 或 dont-have 消息。
- client 向拥有 CID1 的节点发送 want-block 消息,节点返回相应的 block 消息。
- 当没有节点有请求的 block,Bitswap 广播 want-have 到所有的连接节点,或者通过 DHT 查找拥有文件区块的节点。
模块详解
Bitswap 模块
Bitswap 模块负责接收新消息并且实现对外的数据交换接口。
当接收到新消息后,Bitswap 处理流程:
- 记录有关消息的一些统计信息
- 通知发送模块 wants 消息,这样数据发送模块可以根据实际情况向需求节点发送响应消息。
- 通知发送模块任何收到的 blocks,发送模块根据节点的需求列表可以将接收到的块发送给任何需要它们的节点
- 向 SessionManager 通知接收到的 blocks,HAVEs 和 DONT_HAVEs 消息,这样 SessionManager 可以通知消息相关的 session。
Bitswap 通过 Facade Pattern 提高了模块使用的便利性,使得 Bitswap 子系统的用法变得简单,避免了 IPFS 和 Bitswap 的高度耦合。
Session 管理模块
session 管理模块用来管理多个数据块下载 session,每个 session 管理一组文件的下载。
当 SessionManager 收到新消息时,它将
- 通知 BlockPresenceManager 组件跟踪每个 block。
- 通知对接收到的 block 感兴趣并想要的 Sessions。
- 通知 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 处理流程如下:
- 通知 SessionInterestManager 组件它感兴趣的 block。
- 通知 sessionWantManager 组件需要的 block。
- 通知 PeerManager 组件向连接节点发送「want-have」消息,以发现哪些节点有需要的 block。
- 查询 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 时
- 将 want 添加到 Ledger,Ledger 会存储每个节点的需求列表。
- 检查 blockstore 中的相应 block,并将任务添加到 PeerTaskQueue 组件。如果 block 库没有想要的 block,则添加「DONT_HAVE」任务;如果 blockstore 有 block,对于「want-have」添加了「HAVE」任务,对于「want-block」添加了「block」任务。
- 当 Engine 收到新 block 的消息时,它会检查 Ledger 以查看是否有节点需要此 block。对于发送「want-have」的每个节点向 PeerTaskQueue 组件添加一个 「HAVE」任务,对于为发送了「 want-block」的每个节点,向 PeerTaskQueue 组件添加一个「block」任务。
- 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 提高了模块使用的便利性,在具体实现上解耦复杂依赖到各功能模块,从而降低系统实现的复杂度。