本文将会介绍 IPFS 以及 IPFS Cluster 的原理,并且简述 loomts/ipfs-cluster 的 Reed-Solomon 实现 的纠删码优化以及测试细节。

IPFS

IPFS 是一个分布式文件系统,其最大的特点是内容寻址,能够将文件的 CID 作为索引,在世界各地获取文件的内容。

具体来说,IPFS 在存储文件的时候,会将文件分成默认 256KB 的数据块,同时也会生成一些元数据块,用于存储其他块的 CID,最终会组成一个 Merkle DAG(与 git 的数据结构类似)。

如果文件有部分内容被修改,IPFS 会重新分块并构成一颗新的 Merkle DAG——内容寻址下数据本身不可变,修改产生的是新 DAG、新的根 CID。因为 IPFS 的底层存储可以随意更换,可以用 linux 默认的文件系统,也可以用其他 KV storage。

2026-08 更新:原文这里有两处说法要修正。

一是「只会将被修改的部分切割成小块」容易误导。默认的固定 256KB 分块下,在文件中间插入或删除字节会让后面所有块的边界整体偏移,于是绝大多数块的 CID 都会变,只有边界和内容都没变的块才能复用。想让改动的影响局部化,得换成 rabin 或 buzhash 这类内容定义分块。

二是「IPFS 默认使用的是 pebble」不对。Kubo 默认用 flatfs 存数据块、leveldb 存其余元数据;pebble 在官方文档里明确标为 experimental 且需要显式配置,本文写作时(2024-03)的 Kubo 还不支持它。

IPFS Cluster

IPFS 虽然能通过 BitSwap 等机制从对等点获取数据块,但是无法保证对等点存在自己需要的数据,即无法进行方便的容错。

IPFS Cluster 作为 IPFS 的集群管理工具,提供了多副本容错机制,能够让集群通过 CRDT 或 Raft 复制 pinset 等元数据,并且能够管理集群成员的状态。

复制层只同步元数据(哪些 CID 该被 pin、分配给谁),数据本体不走这条链路:各节点收到自己那份 pin 之后,再通过 Bitswap 从对等点把块拉过来。另外 Raft 是共识算法,CRDT 不是——它属于无协调复制,只保证最终收敛,没有 leader 也没有全局定序。

IPFS Cluster With EC

EC 即 Erasure Coding,使用的是 Reed-Solomon 码,能够通过 k 个等长的数据分片生成 m 个校验分片,并且只要拿到这 k+m 个分片中的任意 k 个就能恢复出原始数据。

在 IPFS Cluster 里面实现 EC 首先需要获取文件块,将文件块组装成等长的文件分片,进而再进行 RS 编码和额外的校验分片存储。

「等长」这一步不是白来的:DAG 块并不都是 256KB,末尾块和元数据节点都更小,而 RS 要求参与编码的分片严格等长。所以组装时必须补零对齐到统一长度,并把原始长度单独记下来,恢复时按记录的长度截断,否则解出来的数据会多出一截零字节。

分片的分配方式(本 fork 的实现)是通过将 hash(filename+peerID) 作为键值进行排序,排序得到的 peerIDs 将会被分为存储数据分片和校验分片的两类节点。对于这个文件,每类节点分别存储对应类型的分片。

这个一致性哈希式的分配是本 fork 自己加的,不是 IPFS Cluster 的既有机制。上游 Cluster 靠 allocator 配合 informer 上报的指标来选节点(如 freespacebalanced),跟一致性哈希无关。

IPFS Cluster 将文件切块、编码为数据分片与校验分片,并将分片分配到多个节点的流程
IPFS Cluster 纠删码的数据切分、编码与节点分配流程。

在 IPFS Cluster 而不在 IPFS 直接进行 EC 的原因

  1. IPFS 无法控制其他节点实际存储的块,因此无法起到纠删码分散容错的效果。
  2. IPFS Cluster 提供了很多节点之间同步和交互的功能,能维护一个集群一致的分片分配元数据。
  3. 生成的校验数据会破坏原文件的 Merkle DAG,需要改动很多接口和细节。

但是目前在 IPFS Cluster 上使用 EC 也有一个很令人难受的缺点:因为默认的添加文件方式通过一个 io.Reader 读入数据,切块,并构造 Merkle DAG,所以生成的校验块也是通过这样的方式添加到集群,这样会使得 pinset 比较大,可能在存储的文件过多的时候会对性能有影响。

考虑的优化是将这个 Merkle DAG 作为子节点拓展出一个新的 Merkle DAG,新的 Merkle DAG 需要包括校验数据,但 hack Merkle DAG 的方式以及 Merkle DAG 的实际结构还有待商榷。

IPFS Cluster test

详见 IPFS Cluster 纠删码测试示例