IPFS是怎样存储文件的呢?

2020-08-12 16:57:25

IPFS是一个点对点的分布式文件存储系统,IPFS的愿景是构建一个全世界的分布式网络,用来替代传统的中心化存储模式。

  我们都知道,IPFS是一个点对点的分布式文件存储系统,IPFS的愿景是构建一个全世界的分布式网络,用来替代传统的中心化存储模式。一个完整的IPFS存储系统是由成千上万个节点组成的,每个节点都可以存储文件,用户也可以从IPFS构建的网络中以DHT(Distributed Hash Table,分布式哈希表)的方式获取文件。那么,IPFS节点究竟是怎样存储文件的呢?下面小编带大家来详细了解一下。


  CID

  在介绍IPFS存储文件的原理之前,先介绍一个重要的标识——CID(Content-ID),CID是IPFS中用来表示内容的标识,可以用来表示一个文件,也可以用来表示一个文件块。如下所示,CID是一个字符串,它主要由Version、Codec和Multihash三部分构成,Version目前分为v0和v1版本,v0版本的CID可以由V0Builder生成,v0版本的CID以Qm字符串开头,v1版本的CID可以由V1Builder生成,v1版本的CID主要包含三个部分Codec,MhType和MhLength,其中Codec是表示内容的编码类型,例如DagProtobuf(即protobuf格式),DagCBOR(即cbor格式)等,MhType是哈希算法,例如SHA2_256(默认的哈希算法),SHA2_512,SHA3_256,SHA3_512等等,MhLength是生成哈希的长度,默认用-1表示根据哈希算法确定长度。


0812-3-1.png


  IPFS组件介绍

  IPFS用IpfsNode表示IPFS的节点,存储相关组件的如下所示:


0812-3-2.png


  这些组件的关系如下图所示,最上层是DAGService,它组合了BlockService组件,而BlockService组合了GCBlockstore组件,然后GCBlockstroe包含BaseBlocks和GCLocker两个组件,最后BaseBlocks组合了最原始的blockstore组件。


0812-3-3.png


  接下来分别介绍这些组件的功能:

  Pinning:固定CID的管理器,主要负责将文件或者文件块(又叫Block)的CID固定,固定CID的块不会被GC掉。上传的文件最后的文件的CID都会被固定住,防止被GC。

  Blockstore:GCBlockstore类型,组合Blockstore和GCLocker两个组件。

  BaseBlocks:原始的blockstore,提供了对Block的Get/Put/Has/DeleteBlock等操作。

  GCLocker:用来锁住blockstore,保护blockstore防止被GC影响。

  Blocks:提供Block的服务,组合Blockstore组件,提供了GetBlock/GetBlocks、AddBlock/AddBlocks、DeleteBlock等操作。

  DAG:IPFS的默克尔DAG的服务,组合BlockService组件,提供Get/GetMany,Add/AddMany,Remove/RemoveMany等操作。


  IPFS文件存储流程:

  文件上传时将文件添加到IPFS的仓库中,上传的流程可以如下图所示,生成默克尔DAG的结构,生成的结构有两种Layout:balanced和trickle。这里介绍默认的balanced结构,首先生成root作为根节点,然后将文件分割,默认按照256KB大小读取一个chunk,生成叶子节点,依次生成node1,node2,root节点会有Link指向挂在root节点的叶子节点node1和node2。root节点下面能够Link的叶子节点数量是有限的,IPFS中默认设置的是174个(定义的Link的总的大小是8KB,每个Link的大小是34 + 8 + 5【sha256 multihash + size + no name + protobuf framing】,默认的Link的个数为8192/47约等于174)。


0812-3-4.png


  如下图所示,超过174个后则会新创建一个new root节点,并Link到old root,新的chunk作为node3(这里用node3简约了,实际上是第175个节点)被new root直接Link。


0812-3-5.png


  当继续有新的chunk添加时,则会生成node34作为node3和node4的父节点,node34含有两个Link分别链接到node3和node4。


0812-3-6.png


  IPFS在init的时候会生成.ipfs目录,如下图所示,其中blocks则为文件块存储的目录,datastore为leveldb数据库,其中存储了文件系统的根哈希等,存储相关的配置关联在.ipfs目录下面的config文件。

  经过上面的步骤,文件已经切块并转化成Merkle DAG的结构,接下来详细介绍每个块是如何进行存储的。

  如下图所示,一个Block存储时,首先由dagService(实现了DAGService接口)调用Add进行添加;

  之后由blockService(实现了BlockService接口)调用AddBlock添加该Block;

  再调用arccache的Put,arccache是对存储的Block做arc策略的缓存;

  再之后由VerifBS调用Put进行存储,VerifyBS主要对CID的合法性进行校验,合法则进行Put;

  接着blockstore(实现了Blockstore接口)调用Put进行存储,Put函数中会对CID进行转化,调用dshelp的CidToDsKey方法将CID转化成存储的Key;

  再接着调用keytransform.Datastore的Put,Put函数中会将前缀拼上,这时Key加上了前缀/blocks;

  然后调用measure的Put函数,measure是对mount的封装;

  之后调用mount的Put函数,mount和IPFS的config配置文件中结构对应,根据key去查找对应的datastore,由于前缀是/blocks则可以找到对应的measure;

  调用该measure的Put函数;

  最后调用flatfs的Put函数,由Put函数调用doPut最终调用encode函数将完整的block写入的目录指定为/home/test/.ipfs/blocks/WD,其中WD来自于blocks/CIQFSQATUBIEIFDECKTNGHOKPOEE7WUPM5NNNSJCCDROMM6YHEKTWDY中的倒数第三第二个字符。这样该Block则写入了该目录下面的文件中。

0812-3-7.png



  总结

  IPFS文件存储格式为默克尔DAG格式,每一层Links大小为174个,超过了则会重新调整。文件存储过程中有多个Datastore进行了组合和封装,每个Datastore功能比较单一,例如arccache只做Block的缓存,VerifBS只做CID的校验,这样做的好处是每个组件功能明确,不好的地方在于组合太多,调用深度太深,加上内部都是用interface,好几个组件都实现了该interface,不便于阅读。

  IPFS的存储模式面向互联网用户而设计,因为它的开放性,允许所有节点随意接入,已接入IPFS网络的节点可以自由查找内容,不适合直接用来作为企业的文件存储服务。但其分布式存储的特点,很容易进行存储的动态扩容,可以通过结合节点认证机制和DHT查找内容的剥离,为企业的分布式存储系统,另外配合区块链技术,通过链上链下协同技术,很容易地解决链上存储容量不足的问题。


最新推荐