写点什么

干货|原来 IPFS 是这样存储文件的

用户头像
QTech
关注
发布于: 2021 年 01 月 04 日
干货|原来IPFS是这样存储文件的

概述


IPFS - InterPlanetary File System 星际文件系统,是一个点对点的分布式文件存储系统,IPFS 的愿景是构建一个全世界的分布式网络,用来替代传统中心化的服务器模式,所有的 IPFS 节点组成一个分布式网络,每个节点都可以存储文件,用户可以从 IPFS 构建的网络中以 DHT(Distributed Hash Table,分布式哈希表) 的方式获取文件,从而实现了新一代的完全去中心化的网络,旨在取代现有的万维网。IPFS 功能很丰富,包括 DHT 组网,文件存储,Bitswap 文件交换等功能。本文主要介绍 IPFS 的文件存储原理,文件上传到 IPFS 节点存储时,节点会将文件分块后进行存储,每个文件以 Merkle DAG(默克尔有向无环图)的格式组织,而 Merkle DAG 的根哈希则用来表示该文件。本文将对 IPFS 存储进行详解,所述的 IPFS 的版本为 v0.6.0。


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 表示根据哈希算法确定长度。


IPFS 组件介绍

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



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



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


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 的仓库中,上传的流程可以如下图所示,生成默克尔 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)。

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

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

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 则写入了该目录下面的文件中。



总结


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


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


欢迎进技术群交流区块链技术,与大咖面对面交流


添加小助手桔子(微信:18458407117)备注“进群”


发布于: 2021 年 01 月 04 日阅读数: 37
用户头像

QTech

关注

趣探索区块链技术世界 2020.08.13 加入

趣链科技官方技术内容输出平台

评论

发布
暂无评论
干货|原来IPFS是这样存储文件的