简介
BitSwap 是 IPFS 网络中定义数据块交换方式的协议,它是一个一种基于统一格式的消息对等协议,有别于 request/response 方式。简单来说就是,在 IPFS 中,请求和响应的消息都使用同一类型的消息包。由于在 IPFS 网络中,所有的 Peers 都是对等节点,不存在 BitTorrent 中那样的 Tracker 服务器,所以通信方式更加简单。
BitSwap 协议还定义了如何请求数据、如何发送数据以及向谁发送数据等策略,每个节点都可以有自己的策略,作为数据交换的核心模块,BitSwap 使用一些预定义的激励机制来促进网络中数据的流动,通过一个点对点之间的传输记录账本来达到互惠的目的。
IPFS 网络中使用 Bitswap 协议获取数据块一个最大的特点是,请求的数据块是跨文件的,这个是跟 BitTorrent 最大的区别所在,因为在 BitTorrent 中,块请求都是基于文件的,一个 Peer Swarm 都是对同一个文件(目录)进行数据传输。而在 IPFS 中,由于数据请求是基于块的,任何类型的数据块,只要其哈希值一样,都可以拿为己用,一个 Peer Swarm 对应的是整个 IPFS 网络中的数据,因此所有的数据块都可以被用来使用,实现真正的跨文件数据交换。这不仅大大减少了数据的冗余,还大大提高的块检索的效率。显然,BitSwap 的效率比 BitTorrent 更高。
基于上,BitSwap 协议定义了 Message, Networking, Decision Engine 以及 WantList 等主要模块。
1. Message Protocol
IPFS 中使用 Protocol Buffer 对消息进行编码,Peers 之间通信的消息分为两种,一种是 WantList 用于描述请求,第二种是 Block 用于表示传递的块数据。
WantList 中包含了 blockCid, priority, cancel, full 等字段用于描述要请求的 Block 索引,优先级以及是否是完整请求等信息。
我们知道,在 IPFS 中,文件被分为若干 Chunks,也叫 Blocks,Block 是 IPFS 网络中最基本的数据操作单位。每个 Block 使用一个 CID 标识符来索引,CID 是一个自描述的索引结构体,它集成了对 Block 编码所使用 codec, length, hash 等信息,可以唯一标识一个 Block。因此,要想从 Peer 下载一个 Block,只需在告诉它 CID 即可,收到 Block 时我们也可以容易进行验证。
实际上,由于 IPFS 中使用了 Multicodec 自适应编码协议,因此消息发送前还会添加 multicodec 前缀,这样,就使得消息的格式范围大大增加了,而不仅仅是 Protobuf。比如 JSON, Cbor 等都可以支持!更加强大的是,IPFS 还定义了一套 Multistream 作为网络流的格式协议,因此它甚至还能支持协议的不同版本。
2. Networking
Networking 模块定义了消息发送和处理,查找 Block Providers,Announce Keys,Session 管理,路由等组件。
1)Message Stream
在 IPFS 网络中,消息都是被打包成 Multistream 流进行传输的,Peer 接收到一个 Stream 之后,会先对其解码成对应的消息格式,然后根据消息内容的要求决定是响应请求还是接收块数据。
如果 Decision Engine 决定响应 WantList 请求,那么 BitSwap 会从本地的块数据库中取出块数据,往 Peer Request Queue 中添加一个任务,把块数据发送给对方。
2)Provider
当前节点想要下载一个数据块,本地块数据库中未找到时,就会调用 BitSwap 的网络模块(DHT)查找 Providers,一旦找到,就会连接它并向其发送 WantList 请求,
如果收到了块数据,那么会把存入本地的块数据库。更新本地的 WantList 以及传输记录账本,更新 Session 等一些列操作。
- Announce
Announce 操作是本地节点作为 Key Provider 进行的。在 IPFS 网络中,Block 是用 Key 来标识的(即 Cid Prefix),因此,每当本地新增一个 Block 数据是,provide worker 会异步的向网络中进行 Announce 操作,以声明自己拥有某个块。这样,当其他 Peer 想要下载时,就可以根据 DHT Table 方便的找到要连接的 Providers。
4)Session
Session 管理 Peers 之间的连接,包括 Peers 的请求状态(优先级,是否已取消?等),以及 Peer 存活状态等等信息。
3. Decision Engine
Decision Engine 是 BitSwap 协议的信用管理模块。它管理一个请求队列,使用一个账本来记录节点之间的传输记录,并以此决定是否响应对端的下载请求。
之所以建立一个信用账本,主要是为了以下目的:
- 提高节点之间数据交换的效率
- 防止 freerider
- 防止一些攻击行为(比如:女巫攻击)
- 对信任的节点建立宽松机制
需要注意的是,信用记录是两个节点之间的,分为 Credit 和 Debt 两部分,比如,节点 A 向节点 B 发送过数据,那么 A 就拥有对 B 的 Credit,相反,B 欠了 A 的 Debt。如果 A 对 B 拥有的 Credit 超过 Debt,那么下次其向 B 发出 WantList 请求块数据的时候,B 就会立刻反馈数据。总的来说,A 的 Credit 减去其 Debt 就是净值,IPFS 中使用负债率(debt ratio,r)来表示。
负债率的公式是:
debtRatio = bytes_sent/(bytes_recv + 1)
节点根据负债率来计算出这个节点的发送率 P (send|r) = 1− 1/(1+exp(6−3r))
根据这两个函数可以发现,当负债率达到某一个值的时候负债率会急剧下降。
这个模型表达的意义:如果一个节点只接受数据不分享数据,别人发送给它数据的概率会越来越低(到达某一个值后就会急剧降低接近0),如果节点持续保持分享数据,别的节点向你发送数据的概率就会越来越大。
Decision Engine 会记录下来和其他节点通信的账单(数据收发),可以保持节点间数据交换的历史和防止篡改。当两个节点之间建立连接的时候,BitSwap 会相互交换账单信息,如果账单不匹配,则清除重新记账。恶意节点可能会故意“丢失”账单,以希望清除掉自己的债务。其它交互节点会把这些都记下来,如果总是发生,节点就会被拒绝。
这套信用系统跟 BitTorrent 和 Emule 的信用系统是类似的,Tit-for-Tat,其信用记录都是基于传输节点双方的,并不是全局共享的,也就是说,即使你往某个节点传输了大量的数据,如果你想要的数据不在那个节点上,你也无法根据你的贡献度从整个 IPFS 网络受益。
为此,IPFS 的团队开发了一个全新的 Filecoin 项目,它就是构建与整个 IPFS 网络之上的激励层。后续文章再介绍。
4. WantManager
WantManager 模块主要是管理 WantList 请求的,它是一个实现模块。WantList 是核心数据结构,通过管理一个消息队列,一旦有新的 WantList Entry 添加,就会触发消息队列的工作线程,从而往指定的 Peer 发送数据块。WantManager 提供了一些机制来保证数据块的分发,比如发送失败时会等待一定间隔后进行重发 Rebroadcast,通过 WantList Gauge 监控发送过程,完成数据下载之后的请求取消等。
实验
假如我们想要下载一个 Video 文件,我们知道它的哈希是:Qmdsrpg2oXZTWGjat98VgpFQb5u1Vdw5Gun2rgQ2Xhxa2t
,因此,在启动 ipfs daemon
之后,我们执行:
$ ipfs get Qmdsrpg2oXZTWGjat98VgpFQb5u1Vdw5Gun2rgQ2Xhxa2t
这时候,IPFS 的 WantManager 会计算出 WantList,搜寻网络中的 Peers 并下载相应的 Block。
我们可以通过下列命令查看 WantList。
$ ipfs bitswap wantlist
QmYEqofNsPNQEa7yNx93KgDycmrzbFkr5oc3NMKXMxx5ff
QmUmDEBm9a8MYyqRdb3YQnoqPmqAo4cEWdKQErirFJdSWD
QmY5VJPbsRZzFCTMrFBx2qtZiyyeLhsjBysyfC1fx2gE9S
QmdbzYgyhqUNCNL8xU2HTSKwao1ck2Gmi5U1ygjQuJd92b
QmbZDe5Dcv9mJr8fiqp5aJL2cbyu64tgzwCS2Vy4P3krCL
QmRjzMzVeYRE5b6tDF3sTXMV1sTffno92uL3WwuFavBrWQ
...
找到我们拥有 Debt 的节点列表
QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
QmUh2KnjAvgEbJFSd5JZws4CNvt6LbC4C1sRpBgCbZQiqD
Qmc9pBLfKSwWboKHMvmKx1P7Z738CojuUXkPA1dsPrvSw2
...
选择一个并查看我们是否从该节点下载过数据
$ ipfs bitswap ledger QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
Ledger for <peer.ID SoLMeW>
Debt ratio: 0.000000
Exchanges: 11
Bytes sent: 0
Bytes received: 2883738
全文完!