第12章 【IPFS一问一答】IPFS是怎么进行文件存储的?

12. IPFS是怎么进行文件存储的?

IPFS文件的存储和读取与BitTorrent上传下载原理相似。IPFS采用的索引结构是DHT(分布式哈希表),数据结构是MerkleDAG(Merkle有向无环图)。

12.1 IPFS单文件存储

研究过文件系统的人都知道索引和扇区这两个概念,如:NTFS一个扇区通常是4K,真正的文件数据都是保存在扇区里面的,找到这些扇区的方式就是建立索引(确切的说是高效的索引),IPFS也是一个文件系统,不同的是,IPFS是没有存储上限的,且不存在空间回收的功能。IPFS存储文件时,会经历以下几个步骤:

1、把单个文件拆分成若干个256KB大小的块(block,这个就可以理解成扇区);

2、逐块(block)计算blockhash,hashn=hash(blockn);

3、把所有的blockhash拼凑成一个数组,再计算一次hash,便得到了文件最终的hash,hash(file)=hash(hash1……n),并将这个hash(file)和blockhash数组“捆绑”起来,组成一个对象,把这个对象当做一个索引结构;

4、把block、索引结构全部上传给IPFS节点(这里先不介绍细节),文件便同步到了IPFS网络了;

这里还漏掉了一个小文件的处理逻辑,和NTFS等文件系统类似,小文件(小于1KB)的文件,IPFS会把数据内容直接和Hash(索引)放在一起上传给IPFS节点,不会再额外的占用一个block的大小。现在,已经把文件的原始数据和文件的索引(即hash)上传到IPFS网络了。前面已经讲过,IPFS是不支持空间回收的,文件一旦同步到IPFS,将永久的存在。看起来这样会招来一个严重的后果就是,如果频繁的编辑大文件,每编辑一次就要重新同步,岂不是会过度浪费空间!

举个例子:本地有一个1G的大文件File1,已经同步到IPFS了,后面在这个文件File1后面追加了1K的内容,现在需要重新同步这个文件,算下来需要花费的空间应该是:1G+1G+1K;然而,事实并非如此。IPFS在储存数据的时候,同一份数据只存储一次,文件是分块(block)存储的,hash相同的block,只会存储一次,也就说,前面1G的内容没有发生改变,其实IPFS并不会为这些数据分配新的空间,只会为最后1K的数据分配一个新的block,再重新上传hash,实际占用的空间是:1G+1K;

不同的文件有很多数据是存在重复的,如不同语言字幕的电影,影音部分相同的,只有字幕部分不一样,当两个不同国家的人都在上传同一部电影的时候,这些文件在分块(block)的时候,很有可能有大部分block的hash是一致的,这些block在IPFS上也只会存储一份,这样一来就可能会有很多文件的索引指向同一个block,这里就构成了前面提到的一个数据结构——MerkleDAG(Merkle有向无环图)。

因为所有的索引上都保存了hash,所以MerkleDAG具有以下特点(从白皮书上扒下来的):1.内容可寻址:所有内容都是被多重hash校验和来唯一识别的,包括links。2.无法篡改:所有的内容都用它的校验和来验证。如果数据被篡改或损坏,IPFS会检测到。3.重复数据删除:重复内容并只存储一次。

12.2 IPFS目录文件存储

IPFS支持目录结构,存储目录的方式很简单:

1、先把目录下所有的文件同步到IPFS网络中去,为所有的文件hash建立一个别名,这个别名其实就是本地文件名,把hash和别名“捆绑”在一起组建成一个名为IPFSLink的对象;

2、把该目录下所有的IPFSLink对象组成一个数组,对该数组计算一个目录hash,并将数组和目录hash拼成一个结构体,同步到IPFS网络;

3、如果上层还有目录结构,则为目录hash建立一个别名(就是目录名),把目录hash和别名“捆绑”在一起组建成一个IPFSLink的对象,重复从步骤2开始执行;

4、把目录hash打印出来,读取的时候用;

由上可以看出,对于IPFS而言,存储目录和文件其实是一样的处理方式,IPFS甚至根本没有关心节点想要存储的是一个目录还是一个文件。