作者: Juan Benet
翻译: IPFS点滴资讯
摘要
星际文件系统(IPFS)是一种点对点的分布式文件系统,旨在将所有计算设备连接到相同的文件系统。在某些方面,IPFS和Web很像,但IPFS可以看作是一个BitTorrent集群,并在Git仓库中做对象交换。换句话来说,IPFS提供了高吞吐的基于内容寻址的块存储模型和超链接。这形成了一个广义的默克尔有向无环图(Merkle DAG)数据结构,可以用这个数据结构构建版本化文件系统,区块链,甚至是永久性网站。IPFS结合了分布式哈希表,带激励机制的块交换和自认证的命名空间。IPFS没有单点故障,节点不需要相互信任。
1. 介绍
在构建全球化的分布式文件系统方面,已经有很多尝试。一些系统取得了重要的成功,而另一些却彻底的失败了。在学术界的尝试中,AFS[6]取得了广泛的成功,至今也还在使用。另一些[7,?]就没有获得一样的成功。学术之外,最成功的系统是面向大多媒体(音频和视频)的点对点,文件共享的应用系统。最值得注意的是,Napster,KaZaA和BitTorrent[2]部署了大型文件分发系统,支持超过1亿的同步用户。即使在今天, BitTorrent也维持着每天千万节点的活跃数[16]。可以看到,这些应用程序分发的用户和文件数量比学术文件系统对应数量多。但是,这些应用不是作为基础设施来设计的。虽然取得了成功的应用,但没有出现一种通用的文件系统,支持全球化,低延迟,去中心化分发。
可能是适用大多数场景的“足够好用”的系统已经存在的原因:它就是HTTP。到目前为止,HTTP是最成功的“文件发布系统”。与浏览器相结合,HTTP在技术和社会上有巨大的影响力。它已成为互联网文件传输的事实标准。然而,它没有采用最近15年发明的数十种先进的文件分发技术。从一个角度来看,考虑到向后兼容性约束的数量以及对当前模型感兴趣的强大团队的数量,演进Web基础架构几乎不可能实现。但从另一个角度来看,自HTTP出现以来,新的协议已经出现并得到广泛的应用。 缺乏的是升级设计:增强当前的HTTP网络,并引入新功能而不会降低用户体验。
业界长期使用HTTP,因为移动小文件相对便宜,即使对于流量大的小型组织也是如此。但我们正在进入了一个数据分发的新时代,随之而来的是新的挑战:(a)托管和分发PB级的数据集,(b)跨组织的大数据计算,(c)大容量高清晰度按需或实时媒体流,(d)大规模的数据集版本化和链接,(e)防止重要文件意外丢失,等等。许多挑战可以归结来“大量数据,随处访问”。受关键特性和带宽问题的影响,我们已经放弃了HTTP,而使用不同的数据分布协议。下一步是让这些协议成为Web本身的一部分。
与高效的数据分发相对应,版本控制系统已经设法开发了重要数据的协作工作流。分布式源代码版本控制系统Git开发了许多有用的方法来建模和实现分布式数据操作。 Git工具链提供了大型文件分发系统严重缺乏的多种版本功能。 受Git启发的新解决方案正在兴起,如Camlistore [?],个人文件存储系统,以及Dat [?]数据协作工具链和数据集包管理器。 Git已经影响了分布式文件系统设计[9],因为它的内容寻址Merkle DAG数据模型可以实现强大的文件分发策略。 还有待探讨的是,这种数据结构如何影响高吞吐量文件系统的设计,以及它如何升级Web本身。
本文介绍IPFS,一种新颖的对等网络版本控制的文件系统,旨在解决这些问题。 IPFS综合了过去许多成功的系统的经验教训。精心设计、专注于接口集成的系统产生的效益大于构建它的各个部件的总和。IPFS的核心原则是将所有数据建模为同一Merkle DAG的一部分。
2. 背景
本章节回顾了成功的点对点系统的重要特性,而IPFS正是结合了这些特性。
2.1 分布式哈希表
分布式哈希表(DHT)被广泛用于协调和维护点对点系统的元数据。例如,BitTorrent MainlineDHT可以跟踪Torrent群组的一些对等节点。
2.1.1 KADEMLIA DHT
Kademlia[10]是一个流行的分布式哈希表(DHT),它提供了:
- 大规模网络的高效查询:平均查询 [log2(n)] 节点。(例如,对于10,000,000个节点的网络为20跳)。
- 低协调开销:它优化了发送给其他节点的控制消息的数量。
- 通过选择长期在线节点来抵抗各种攻击。
- 在包括Gnutella和BitTorrent在内的对等应用中广泛使用,形成了超过2000万个节点的网络[16]。
2.1.2 CORAL DSHT
一些点对点文件系统直接将数据块文件存在DHTs中,这“浪费存储和带宽,因为必须数据存储在实际不需要的它的节点上”[5]。Coral DSHT在3个特别重要的方面扩展Kademlia:
- Kademlia将值存储在IDs与结点“最接近”(使用XOR-distance方法)的节点中。这样做没有考虑应用程序数据局部性,忽略了“远”节点可能已经有数据,并强制“最近”的节点存储数据,无论这些节点是否需要。这浪费了大量的存储和带宽。相反,Coral存储的是可以提供数据块的节点地址。
- Coral将DHT API的
get_value(key)
修改成get_any_values(key)
(DSHT中的“sloppy”)。Coral用户只要一个(在线)节点,而不是完整列表就可以正常工作。作为回报,Coral可以仅将值的子集分配到“最近”的节点,避免热点(当某个Key变得流行时,重载所有最近的节点)。 - 另外,Coral根据区域和大小组织了一个称为群集的独立DSHT层次结构。这允许节点首先查询其区域中的节点,“查找附近的数据而不查询远程节点”[5]并大大减少查找的延迟。
2.1.3 S/Kademlia DHT
S/Kademlia [1]在两个特别重要的方面扩展了Kademlia,用来防止恶意攻击。
- S/Kademlia提供了保护节点ID生成和防止女巫攻击的方案。它需要节点生成公私钥对,从中获取标识,并相互签名。 其中一种方案包括一个工作证明密码难题,增加女巫攻击的成本。
- S/Kademlia节点在不相交的路径上查找值,是为了保证网络中存在很大一部分恶意节点的情况下,节点也能相互连接。即使恶意节点的高达一半,S/Kademlia连接的成功率为0.85。
2.2 区块交换 – BitTorrent
BitTorrent[3]是一个非常成功的点对点文件共享系统,它成功地协调了不信任的对等网络节点(集群)相互分发文件块。IPFS从BitTorrent和它的生态系统的关键特征获得设计灵感:
- BitTorrent的数据交换协议使用了类似针锋相对(tit-for-tat)的策略,即奖励贡献节点,惩罚只索取的节点。
- BitTorrent节点会跟踪文件块的可用性,会优先发送最稀缺的文件块。这减轻了种子节点的负担,使得非种子节点能相互交换数据(交易)。
- BitTorrent的以牙还牙的标准很容易受到一些剥削性带宽共享策略的影响。PropShare[8]是一种不同的对等带宽分配策略,它更好地抵抗剥削性策略,提高集群的性能。
2.3. 版本控制系统 – Git
版本控制系统为随时间变化的文件建模和有效分发不同版本提供了设施。流行的版本控制系统Git提供了强大的默克尔有向无环图(Merkle DAG)2 对象模型,它以分布式友好的方式控制文件系统树的变更。
- 不可变的对象表示文件(
blob
)、目录(tree
)和更改(commit
). - 对象通过内容的加密哈希进行内容寻址。
- 与其他对象的链接是嵌入的,形成了一个Merkle DAG。这提供了许多有用的完整性和工作流属性。
- 大多数版本元数据(分支、标签等)都只是指针引用,因此创建和更新的代价非常小。
- 版本变更只是更新引用或者添加对象。
- 分发版本变更给其他用户只是简单的传输对象和更新远程引用。
2.4 自我认证认文件系统 – SFS
SFS[12,11]提出的关于(a)分布式信任链和(b)全局对等共享命名空间的实现方案令人信服。SFS引入了文件自认证技术,使用以下方案寻址远程文件系统
/sfs/:‹Location›:‹HostID›
其中 Location 就是网络地址,而
HostID = hash(public_key || Location)
因此,SFS文件系统的名称证明了它的服务器。用户可以验证服务器提供的公钥,协商共享秘密,并保证所有的通信。所有SFS实例都共享一个全局命名空间,其中的名称分配是加密的,而不是由任何集中主体设置的。
3. IPFS设计
IPFS是一个分布式文件系统,它从之前的 DHTs、BitTorrent、Git和SFS等对等系统中吸取成功的想法。IPFS的贡献在于通过简化和演化的方式将已被验证的技术整合成在一个内聚系统,而不只是简单的组合。IPFS提供了一个编写和部署应用的新平台,以及一个用于分发和版本化大量数据的新系统。IPFS甚至可以进化网络本身。
IPFS 是点对点的;没有特权节点。IPFS 的节点在本地存储对象。节点连接其他节点并交换对象。这些对象表示文件和其他数据结构。IPFS 协议划分为一组负责不同功能的子协议:
- 身份层 – 管理节点身份生成和验证, 在3.1节描述。
- 网络层 – 管理与其他节点的连接,使用各种底层网络协议。配置化。在3.2节描述。
- 路由层 – 维护信息以定位指定节点和对象的信息。响应本地和远程的查询。默认为DHT,但可更换。在3.3节描述。
- 交换层 – 一种支持有效块分配的新型块交换协议(BitSwap)。模拟市场,弱化数据复制。贸易策略可替换。在3.4节描述。
- 对象层 – 具有链接的内容寻址不可变对象的默克尔有向无环图(Merkle DAG)。用于表示任意数据结构,例如文件层次和通信系统。在3.5节描述。
- 文件层 – 由Git启发的版本化文件系统层次结构。在3.6节描述。
- 命名层 – 自我认证的可变名称系统。在3.7节描述。
这些子系统不是孤立的,它们结合在一起,并相互利用各自的属性,相辅相成。但是,对它们进行分开描述是实用的,自底向上地构建协议栈。
注意:以下的数据结构和函数用Go语言表示。
3.1 身份层
节点由一个节点ID(NodeID)标识,它是一个公钥的加密哈希 3,是由S/Kademlia的静态密码难题[1]生成的。节点存储其公私钥(用密码加密)。用户可以在每次启动时自由地设置一个“新”节点身份,尽管这会损失积累的网络利益。激励节点保持不变。
type NodeId Multihash type Multihash []byte // self-describing cryptographic hash digest type PublicKey []byte type PrivateKey []byte // self-describing keys type Node struct { NodeId NodeID PubKey PublicKey PriKey PrivateKey }
IPFS基于S/Kademlia生成身份:
difficulty = ‹integer parameter› n = Node{} do { n.PubKey, n.PrivKey = PKI.genKeyPair() n.NodeId = hash(n.PubKey) p = count_preceding_zero_bits(hash(n.NodeId)) }
第一次连接时,节点相互交换公钥,并进行检查:节点分钥的哈希是否与节点ID相等。如果不是,终止连接。
加密函数的注意事项:
IPFS更喜欢自描述的值,而不是锁定系统到一组特定的函数选择中。哈希摘要的值被存储在一个多重哈希格式中,它包括一个指明所使用的哈希函数的短头部,以及摘要长度。例如:
‹function code›‹digest length›‹digest bytes›
它允许系统(a)为用例选择最佳函数(例如:更强的安全性VS更快的性能),(b)随着功能选择的变化而演化。自描述的值允许使用合适的不同的参数选择。
3.2 网络层
IPFS 节点节点定期在网络上的其他节点通信,跨越广域网。IPFS网络的特点:
- 传输: IPFS可以使用任何传输协议,它最适合WebRTC DataChannels [?] (浏览器连接)或 uTP(LEDBAT [14])。
- 可靠性: 如果底层网络不提供,IPFS可以通过uTP (LEDBAT [14])或SCTP [15]提供可靠性。
- 连通性: IPFS还使用ICE NAT遍历技术[13]。
- 完整性: 可选使用哈希校验和检查消息的完整性。
- 真实性: 可选使用HMAC和发件人的公钥来检查消息的真实性。
3.2.1 对等节点寻址注意事项
IPFS可以使用任何网络; 但它不承担对IP的获取以及不直接依赖于ip层。这允许在覆盖网络中使用IPFS。IPFS将地址存储为多重地址( multiaddr
),这个多层地址是由字节字符串组成的,以便于给底层网络使用。 multiaddr
提供了一种方式来表示地址及其协议,可以封装成好解析的格式。例如:
# an SCTP/IPv4 connection /ip4/10.20.30.40/sctp/1234/ # an SCTP/IPv4 connection proxied over TCP/IPv4 /ip4/5.6.7.8/tcp/5678/ip4/1.2.3.4/sctp/1234/
3.3 路由层
IPFS节点需要一个路由系统, 这个路由系统可用于查找:(a)其他同伴的网络地址,(b)专门用于服务特定对象的对等节点。IPFS使用基于S / Kademlia和Coral的DSHT,在2.1节中具体介绍过。在对象大小和使用模式方面, IPFS类似于Coral [5] 和Mainline [16],因此,IPFS DHT根据其大小对存储的值进行区分。小的值(等于或小于1KB
)直接存储在DHT上。对于更大的值,DHT只存储值索引,这个索引就是一个对等节点的NodeIds
,该对等节点可以提供对该类型的值的具体服务。
DSHT的接口如下:
type IPFSRouting interface { FindPeer(node NodeId) // gets a particular peer’s network address SetValue(key []bytes, value []bytes) // stores a small metadata value in DHT GetValue(key []bytes) // retrieves small metadata value from DHT ProvideValue(key Multihash) // announces this node can serve a large value FindValuePeers(key Multihash, min int) // gets a number of peers serving a large value }
注意:不同的用例将要求基本不同的路由系统(例如广域网中使用DHT,局域网中使用静态HT)。因此,IPFS路由系统可以根据用户的需求替换的。只要使用上面的接口就可以了,系统都能继续正常运行。
3.4 区块交换 – Bitswap协议
在IPFS中,数据分布通过受BitTorrent启发的协议与点对点交换块实现。例如BitTorrent,点对点Bitswap正寻求一组块(want_list),并在交换时提供另一组块(have_list)。与BitTorrent不同,Bitswap不局限于某个Torrent中的块。作为一个持续市场,节点可以在Bitswap获取它们需要的块,无论那些块是属于哪个文件,无论那些文件相不相关。在市场上,节点聚集在一起进行交换。虽然易货系统意味着可以创建虚拟货币,但创建虚拟货币需要一个全面的分类账来跟踪和转移货币所有权。这是一种比特交换策略,在下文中会进一步阐述。
在基础案例中,Bitswap节点需要以块的形式提供直接价值。块在节点之间的分布呈互补状态(它们相互之间拥有对方没有的东西),这时的节点可顺畅运行。但通常来说,情况并非如此。某些时候,节点必须为其块工作。若某个节点没有它的对等节点想要的东西,此节点便会以(比其想要的更低优先级的方式)寻找它的对等方想要的东西。这样一来,便促进了节点缓存和传播稀有片段。
3.4.1 Bitswap 信用
因为某个节点可能拥有其他节点需要的块,所以协议必须鼓励节点播种(尤其是当没有其他附加条件时)。这样一来,Bitswap节点向其对等节点发送块,以偿还债务,同时,必须防止水蛭(非共享的自由加载节点)。一个简单的、与信用系统类似的系统解决了这个问题:
- 对等机跟踪其与其他节点的平衡(以验证的字节为单位)。
- 概率上来说,节点根据某个随债务增加而下降的函数,向债方节点发送数据块。
注意,如果一个节点没有发送到其对等节点,那么该节点随后会忽略其对等节点以获得ignore_cooldown超时。这样就可以防止发送者仅仅通过增加骰子掷骰子来尝试博弈概率。(Bitswap拖欠时间为10秒)。
3.4.2 Bitswap 策略
Bitswap节点采用的不同策略会对交易的整体表现有截然不同的影响。在BitTorrent中,虽然指定了一个标准策略(以牙还牙),但已经实施了其他各种策略,从BitTarrant[8](尽可能共享),到BitTraft[8](利用漏洞而从不共享),到Propshare[8](按比例共享)。一系列策略(好的和恶意的)同样可以由Bitswap对等端实现。因此,功能选择应旨在:
- 最大化节点和整个交易的的绩效
- 防止某节点只下载不上传
- 有效应对和抵抗其他未知策略
- 对可信节点要宽容
未来,我们将对这些战略空间进行探索。在实践工作的一种功能选择是由Debt Retio缩放的Sigmoid:某节点和其对等节点之间的负债比率r为:
假设r,发送给债务人的概率为:
图1所示,当节点的债务比率超过已建立信贷的两倍时,此应变量会迅速下降。
图像1:随着r增加发送的概率
债务比率是一种信用度量:对以前有大量数据成功交换过的节点之间的债务的宽容,以及对未知、不受信任的节点的严格。(a)可能抵抗创建大量新节点(sybill攻击)的攻击者;(b)即使其中的一个节点暂时没有价值,也会保护以前成功的交易关系,;(c)不断阻止关系的恶化直到情况改善。
3.4.3比特交换分类账
Bitswap节点可以核算分类账与其他节点的传输。这让节点记录下历史信息以避免他人篡改。连接激活时,Bitswap节点交换其Ledger信息。如果不完全匹配,对于丢失应计的信贷或债务进行重新初始化分类账。恶意节点有可能故意“丢失”分类账以消除债务。节点不太可能累积足够的债务去保证同时失去的累计信用;但是配对节点可以将其视为不当行为,并拒绝交易。
type Ledger struct { owner NodeId partner NodeId bytes_sent int bytes_recv int timestamp Timestamp }
节点可以自由选择保存或者不保存分类账信息,是否操作正确同样无关紧要,因为只有目前的分类账项是有用的。如有必要,nodes也能从不太有用的Ledger开始免费收集垃圾:旧的(不存在节点)分类账和小分类账。
3.4.4比特交换规格
比特交换节点采用简单协议
// Additional state kept type Bitswap struct { ledgers map[NodeId]Ledger // Ledgers known to this node, inc inactive active map[NodeId]Peer // currently open connections to other nodes need_list []Multihash // checksums of blocks this node needs have_list []Multihash // checksums of blocks this node has } type Peer struct { nodeid NodeId ledger Ledger // Ledger between the node and this peer last_seen Timestamp // timestamp of last received message want_list []Multihash // checksums of all blocks wanted by peer // includes blocks wanted by peer’s peers } // Protocol interface: interface Peer { open (nodeid :NodeId, ledger :Ledger); send_want_list (want_list :WantList); send_block (block :Block) -> (complete :Bool); close (final :Bool); }
对等连接的生命周期草图:
1.开放:节点发送分类账(ledgers)直到其对等点接受。
2.发送:节点交换want_lists和块。
3.关闭:节点连接停用。
4.忽略: (特殊)如果节点的策略是避免发送,则忽略对等节点(在超时期间)。
Peer.Open(节点ID,Ledger)
在连接状态下,无论是从过去的连接存储的,还是新的连接归零的,节点都要初始化与Ledger的连接。然后,向对等节点发送一条有Ledger的公开消息。
收到Open消息时,对等节点可选择是否激活连接。如果-根据接收者Ledger-发送者不是可信任的代理(无传输次数或有大额未偿债务),接收者可以忽略请求。这应该以ignore_cooldown超时的概率完成,以便纠正错误并阻止攻击者。
如果激活连接,接收器将使用Ledger的本地版本初始化对等节点,并设置last_seen时间戳,然后,将收到的Ledger与自己的分类账进行比较。如果它们完全匹配,则可以与对方连接上。如果它们不匹配,对等方将创建一个新的清零Ledger并发送它。
对等。
对等节点。发送“想要”清单(want list)。
在连接是打开状态下,节点向所有连接的对等节点公布它们的want_list。当(a)在打开连接时,(b)在随机的周期性超时之后,(c)在want_list中更改之后,(d)在接收到新的块之后。
节点会储存接收到的want_list并检查是否有任何想要块,如果有,此节点会根据上文提到的Bitswap策略发送它们。
对等节点。发送块(blocks)
发送块很简单,节点只需要传输数据块就可以了。接收完所有数据后,为了验证其是否与预期的校验匹配,接收器要计算multihash校验,,随后,返回确认。
在正确传输块后,接收器将块从 need_list移动到have_list,为了反映传输的额外字节,接收器和发送者都会更新其分类账。
如果传输验证失败,发送方要么会出现故障,要么会攻击接收方(接管人可拒绝进一步交易)。注意:Bitswap需要在可靠的传输通道上运行,传输错误——可能错误惩罚可信任发送者——在数据进行Bitswap之前捕获传输错误。
对等节点。关闭(bool)
关闭的最后一个参数表示断开连接的是否是发送方。如果为false,那么接收器可以立即重新打开连接,以避免过早关闭。
对等连接在以下两种情况下断开:
- silence_wait时机超时,从对等节点无消息接受(Bitswap未履行时间到达30秒),节点会发出peer.close(false)的信息。
- 在节点退出、Bitswap关闭的情况下,节点发出peer.close(true)的信息。
收到close消息后,接收器和发送器都会断开连接并清除已存储数据。如果这样做有用的话,Ledger会保存以做备用。
注意
非活动连接上的未open消息应被忽略。如果是send_block消息,接收器可以检查块是否需要和正确,如果需要,使用它。无论如何,所有这样的无序消息都会触发来自接收器的close(false)消息,以强制重新初始化连接。
3.5目标Merkle DAG
DHT和Bitswap让IPFS成为了一个庞大的点对点系统,可快速、可靠地存储和分发块。除此之外,IPFS还构建了Merkle DAG:在一幅有向非循环图中,对象之间的链接是源中目标的加密散列。这是对Git数据结构的概括。Merkle DAG可为IPFS提供许多有用的属性,如:
- 内容寻址:所有内容,包括连接,都要经过multihash校验。
- 防篡改:所有内容都要经过校验。IPFS可以检测到经篡改或损坏的数据。
- 重复数据消除:包含完全相同内容的所有对象都一样,并且只存储一次。这一属性主要针对索引对象(如git trees和commits)或数据的公共部分。
IPFS目标格式为:
type IPFSLink struct { Name string // name or alias of this link Hash Multihash // cryptographic hash of target Size int // total size of target } type IPFSObject struct { links []IPFSLink // array of links data []byte // opaque content data }
IPFS merkle dag是一种非常灵活的数据存储方式。唯一的要求是对象查阅需要(a)内容寻址,和(b)按上述格式编码。IPFS授予应用程序对数据字段的完全控制权;应用程序可自定义数据格式,对此,IPFS可能无法理解。分离对象的链表让IPFS可以: 列出对象中的所有对象引用。例如:
> IPFS ls /XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzb XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x 189458 less XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5 19441 script XLF4hwVHsVuZ78FZK6fozf8Jj9WEURMbCX4 5286 template ‹object multihash› ‹object size› ‹link name›
解析字符串路径查找,例如foo/bar/baz。给定一个对象,IPFS将第一个路径组件解析为对象链接表中的哈希,获取第二个对象,并与下遍历merkle-dag。 解析递归引用的所有对象:
> IPFS refs --recursive /XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzb XLLxhdgJcXzLbtsLRL1twCHA2NrURp4H38s XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5 XLWVQDqxo9Km9zLyquoC9gAP8CL1gWnHZ7z ...
若在IPFS之上构建任意数据结构,原始数据字段和公共链路结构是的必要组件。虽然Git对象模型如何适应DAG是显而易见的,但是考虑到其他潜在的数据结构:(a)键值存储(b)传统关系数据库(c)链接数据三重存储(d)链接文档发布系统(e)链接通信平台(f)加密货币区块链。这些都可以在IPFS merkle dag的基础上建模,而且,那些系统中的任意一个系统都可以采用IPFS,以此作为更加复杂的应用程序的传输协议。
3.5.1路径
/IPFS 对象可以使用字符串路径API进行遍历。路径就像在传统的UNIX文件系统和Web中一样。merkle-dag链接使遍历变得容易。注意: IPFS中的完整路径的形式如下:
# format /IPFS/‹hash-of-object›/‹name-path-to-object› # example /IPFS/XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x/foo.txt
/IPFS前缀允许在标准装入点装入现有系统,而且不会发生冲突(当然,装入点名称是可配置的)。第二个路径组件(IPFS中的第一个)是对象的哈希。因为没有全局根,所以情况总是这样。一个根对象将有一项不可能的任务,即在分布式(可能是断开连接的)环境中做数百万个对象的一致性处理。相反,我们用内容寻址来模拟根目录。所有对象总是可以通过其哈希访问。注意,这意味着给定path/bar/baz中的三个对象,且所有人都可以访问最后一个对象:
/IPFS/‹hash-of-foo›/bar/baz /IPFS/‹hash-of-bar›/baz /IPFS/‹hash-of-bar›
3.5.2局部对象
IPFS客户机需要一些本地存储,这是一个外部系统,用于存储和检索IPFS管理对象的本地原始数据。存储类型取决于节点的用例。在大多数情况下,这只是磁盘空间的一部分(要么由本机文件系统管理,要么由键值存储区(如LevelDB[4])管理,要么直接由IPFS客户机管理)。还有其他情况,例如,只是RAM一部分的非持久性缓存。 最终,IPFS中可用的所有块都在某个节点的本地存储中。当有请求对象时,用户会在本地找到(或者临时找到)、下载和存储这些对象,同时也为以后的可配置时间提供了快速查找功能。
3.5.3对象固定
希望确保特定对象存活的节点可以通过固定对象来实现这一点。这样可以确保对象保存在节点的本地存储中。为了固定所有链接的子对象可以递归Pinning。所有的指向对象都在本地存储对持久化文件(包括引用)来说很有用。同时,对象可以保证其指向的其他对象处于存在状态,这使得IPFS成为了一个永久性的网络链接。
3.5.4发布对象
IPFS是全球分布的,让数百万用户的文件可以共存。具有内容散列寻址的DHT允许以公平、安全和完全分布式的方式发布对象。只需将其密钥添加到DHT中,将自己添加为对等方,并为其他用户提供对象的路径,任何人都可以发布对象。注意:就像在Git中一样,对象本质上是不变的。新版本的散列方式不同,是新对象,而跟踪版本是附加版本控制对象需要进行的的工作。
3.5.5对象级加密
IPFS可以处理对象级的加密操作。加密或签名的对象在一个可以对原始字节进行加密或验证特殊的框架中。
type EncryptedObject struct { Object []bytes // raw object data encrypted Tag []bytes // optional tag for encryption groups } type SignedObject struct { Object []bytes // raw object data signed Signature []bytes // hmac signature PublicKey []multihash // multihash identifying key }
加密操作更改对象的哈希并定义不同的对象。IPFS自动验证签名,并可以使用用户指定的密钥链解密数据。加密对象的链接也受到保护,使得没有解密密钥就无法进行遍历。父对象在一个密钥下加密,子对象可以在另一个密钥下加密,或者根本不加密。这样一来,就可以保护共享对象的链接。
3.6文档
IPFS还定义了一组对象,用于在Merkle DAG上建模版本控制的文件系统。此对象模型类似于Git:
1.Block:大小可变更的数据块。
2.List:块或其他list的集合。
3.tree:块、list或其他trees的集合。
4.commits:一个tree的版本历史记录中的快照。
我希望准确地使用git对象格式,但不得不开始介绍分布式文件系统中的某些功能,即(a)快速大小查找(已将聚合字节大小添加到对象中)、(b)大型文件重复数据消除(添加list对象)和(c)将commits嵌入到trees中。但是,IPFS文件对象与Git之间的距离足够近,因此可以在两者之间进行转换。此外,可以引入一组Git对象进行转换,而不会丢失任何信息(Unix文件权限等)。 注释:下面的文件对象格式使用JSON。注意:尽管IPFS包括导入/导出到json,但这个结构实际上是使用protobufs进行二进制编码的。
3.6.1文件对象:blob
BLOB对象包含一个可寻址的数据单元和文件。IPFS块类似于git blobs或文件系统数据块,可以存储用户的数据。注意:IPFS文件可以同时由list和无连接的blob表示。
{ "data": "some data here", // blobs have no links }
3.6.2文件对象:列表
List对象表示一个大型或重复数据消除文件,该文件由连接在一起的多个IPFS blobs组成。list包含blob或lists对象的有序序列。在某种意义上,IPFSlist的功能类似于带有间接块的文件系统文件。由于lists可以囊括其他lists,因此可以使用包含链接list和平衡trees的拓扑。同一节点出现在多个位置的定向图允许文件重复数据消除。当然,因为哈希寻址是强制的,所以不可能循环。
{ "data": ["blob", "list", "blob"], // lists have an array of object types as data "links": [ { "hash": "XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x", "size": 189458 }, { "hash": "XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5", "size": 19441 }, { "hash": "XLWVQDqxo9Km9zLyquoC9gAP8CL1gWnHZ7z", "size": 5286 } // lists have no names in links ] }
3.6.3文件对象:trees
IPFS的trees对象类似于Git:它表示一个目录,一个名称到哈希的映射。散列引用blob、list、其他trees或commits记录。注意:传统的路径由merkle dag命名。
{ "data": ["blob", "list", "blob"], // trees have an array of object types as data "links": [ { "hash": "XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x", "name": "less", "size": 189458 }, { "hash": "XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5", "name": "script", "size": 19441 }, { "hash": "XLWVQDqxo9Km9zLyquoC9gAP8CL1gWnHZ7z", "name": "template", "size": 5286 } // trees do have names ] }
3.6.4文件对象:commit
IPFS的commit对象表示任何对象版本的历史记录的快照,类似于Git,但可以引用任何类型的对象,包括链接到作者。
{ "data": { "type": "tree", "date": "2014-09-20 12:44:06Z", "message": "This is a commit message." }, "links": [ { "hash": "XLa1qMBKiSEEDhojb9FFZ4tEvLf7FEQdhdU", "name": "parent", "size": 25309 }, { "hash": "XLGw74KAy9junbh28x7ccWov9inu1Vo7pnX", "name": "object", "size": 5198 }, { "hash": "XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm", "name": "author", "size": 109 } ] }
图2:示例对象图
>ipfs file-cat ‹ccc111-hash› --json { "data": { "type": "tree", "date": "2014-09-20 12:44:06Z", "message": "This is a commit message." }, "links": [ { "hash": "‹ccc000-hash›", "name": "parent", "size": 25309 }, { "hash": "‹ttt111-hash›", "name": "object", "size": 5198 }, { "hash": "‹aaa111-hash›", "name": "author", "size": 109 } ] } > ipfs file-cat ‹ttt111-hash› --json { "data": ["tree", "tree", "blob"], "links": [ { "hash": "‹ttt222-hash›", "name": "ttt222-name", "size": 1234 }, { "hash": "‹ttt333-hash›", "name": "ttt333-name", "size": 3456 }, { "hash": "‹bbb222-hash›", "name": "bbb222-name", "size": 22 } ] } > ipfs file-cat ‹bbb222-hash› --json { "data": "blob222 data", "links": [] }
图3:示例对象
3.6.5版本控制
commit对象表示对象版本历史记录中的特定快照。比较两个不同的commits对象(和子对象)可以发现文件系统的两个版本之间的差异。只要单个commit及其引用的所有子对象都是可访问的,就可以检索先前所有的版本和文件系统更改的完整历史记录。这不属于Merkle DAG对象模型。 IPFS用户可以使用Git版本控制工具的全部功能。尽管对象模型不同,但是兼容。可以(a)构建一个修改为使用IPFS对象图的git工具版本,(b)构建一个挂载的fuse文件系统,该文件系统将IPFStree挂载为git repo,将git文件系统读/写转换为IPFS格式。
3.6.6文件系统路径
正如我们在merkle dag看到的,IPFS对象可以通过字符串路径API进行遍历。IPFS文件对象旨在使IPFS装入UNIX文件系统更简单。为了使它们表示为目录得形式,限制trees没有数据。commits可以表示为目录,也可以完全隐藏在文件系统中。
3.6.7将文件拆分为列表和blob
对大型文件进行版本控制和分发的主要困难之一是以正确方法将它们拆分为独立块的。与其假设它可以对每种类型的文件做出正确的决定,不如试试IPFS提供的以下替代方案:
1.使用拉宾指纹[?就像在LBFS中一样?]选择合适的块边界。
2.使用rsync[?]滚动校验和算法,以检测版本之间已更改的块。
3.允许用户为特定文件指定高度优化的分块函数。
3.6.8路径查找性能
基于路径的访问遍历对象图。检索每个对象需要在DHT中查找其密钥,连接到对等机,并检索其块,这是相当大的开销,尤其是在查找包含许多组件的路径时,但可以通过以下方式缓解: tree缓存:由于所有对象都是散列寻址的,因此可以无限期地缓存它们。此外,trees往往很小,所以IPFS比Blobs缓存优先。 Flattened trees:对于任何给定的tree,都可以构建一个特殊的flattened tree来列出从tree中可以到达的所有对象。Flattened tree中的名称实际上是与原始tree分离的路径,带有斜线。 例如,上面TTT111的flattened tree:
{ "data": ["tree", "blob", "tree", "list", "blob" "blob"], "links": [ { "hash": "‹ttt222-hash›", "size": 1234 "name": "ttt222-name" }, { "hash": "‹bbb111-hash›", "size": 123, "name": "ttt222-name/bbb111-name" }, { "hash": "‹ttt333-hash›", "size": 3456, "name": "ttt333-name" }, { "hash": "‹lll111-hash›", "size": 587, "name": "ttt333-name/lll111-name"}, { "hash": "‹bbb222-hash›", "size": 22, "name": "ttt333-name/lll111-name/bbb222-name" }, { "hash": "‹bbb222-hash›", "size": 22 "name": "bbb222-name" } ] }
3.7 IPN:命名和可变状态
到目前为止,IPFS堆栈形成了一个对等块交换,构建了一个内容寻址的对象DAG。它用于发布和检索不可变的对象,也可以跟踪这些对象的版本历史,但是,缺少一个关键组件:可变命名。没有可变命名,所有新内容的通信都必须在带外进行,发送IPFS链接。所需的是在同一路径上检索可变状态的某种方法。 值得确定的是,如果最终需要的是可变数据,为什么我们要努力构建一个不变的merkle dag。考虑到Merkle DAG中的IPFS属性:可以(a)通过散列检索对象,(b)检查完整性,(c)链接到其他对象,以及(d)无限期缓存对象。在某种意义上: 对象是永久的 这些都是高性能分布式系统的关键属性,在这些系统中,数据在网络链路间移动是很昂贵的。对象内容寻址构造一个具有以下功能的Web:(a)显著的带宽优化;(b)不可信任的内容服务;(c)永久链接;(d)对任何对象及其引用进行完全永久备份的能力。 Merkle DAG是不可变的内容寻址对象,它的命名和Merkle DAG的可变指针实例化了许多成功的分布式系统中的二分法。其中包括Git版本控制系统及其不可变对象和可变引用;以及Plan9[?,Unix的分布式继承者,其mutable Fossil[?]和immutable Venti[?文件系统。LBFS?]还使用可变索引和不可变块。
3.7.1自认证名称
使用sfs[12,11]中的命名方案,我们可以在加密分配的全局命名空间中构造可变的自认证名称。IPFS方案如下。 回想一下在IPFS中:nodeid=hash(node.pubkey) 我们在以下位置给每个用户一个可变命名空间: /ipns/‹NodeId› 用户可以将由其私钥签名的对象发布到此路径,例如:at:/ipns/xlf2ipq4jd3udex5xp1kbgehremutaa8vm 当其他用户检索对象时,他们可以检查签名是否与公钥和nodeid匹配,以便验证用户发布的对象的真实性,从而实现可变状态检索。 请注意以下详细信息: IPNS(星际名称空间)单独的前缀是方便程序和人类读者区别可变路径和不可变路径。
- 由于这不是内容寻址对象,所以发布它依赖于IPFS中唯一可变的状态分发系统,即路由系统。该过程是(1)将对象发布为常规的不可变IPFS对象,(2)将其哈希作为元数据值发布到路由系统上
routing.setValue(NodeId, ‹ns-object-hash›)
- 已发布对象中的任何链接在命名空间中充当子名称:
/ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm/ /ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm/docs /ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm/docs/IPFS
- 建议发布有commits或版本历史记录的对象,以便客户端能够找到旧名称。因为很少用到,所以作为用户选项保留。 注意:当用户发布此对象时,它不能以相同的方式发布。
3.7.2人性化名称
虽然IPNS确实是一种分配和重新分配名称的方法,但它对用户不太友好,因为它将长哈希值作为名称k公开,众所周知,长哈希值是难以记住的。这些功能适用于URL,但不适用于多种离线传输。因此,IPFS通过以下技术提高了IPNS的用户友好性。
点对点
在sfs的促进下,用户可以将其他用户的对象直接链接到自己的对象(名称空间、主对象等),同样有利于创建信任网络(并支持旧的证书颁发机构模型):
# Alice links to bob Bob ipfs link /‹alice-pk-hash›/friends/‹bob-pk-hash›/ # Eve links to Alice ipfs link /‹eve-pk-hash›/friends/‹alice-pk-hash›/ # Eve also has access to Bob /‹eve-pk-hash›/friends/alice/friends/bob # access Verisign certified domains /‹verisign-pk-hash›/foo.com
DNS TXT IPNS记录
如果/ipns/是有效的域名,IPFS会在其dns txt记录中查找密钥ipn。IPFS将该值解释为对象哈希或其他IPNS路径:
# this DNS TXT record ipfs.benet.ai. TXT "ipfs=XLF2ipQ4jD3U ..." # behaves as symlink ln -s /ipns/XLF2ipQ4jD3U /ipns/fs.benet.ai
Proquint可发音标识符
一直以来都有将二进制编码为可发音词的方案。IPNS支持ProQuint[?]因此:
# this proquint phrase /ipns/dahih-dolij-sozuk-vosah-luvar-fuluh # will resolve to corresponding /ipns/KhAwNprxYVxKqpDZ
为了向用户提供名称空间,名称缩短的服务必然会出现。这与我们今天的DNS和Web URL类似:
# User can get a link from /ipns/shorten.er/foobar # To her own namespace /ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm
3.8使用IPFS
将IPFS设计成以多种不同的方式以供使用。我将列举一些用例:
- 1.作为已安装的全局文件系统,位于/IPFS和/ipn
- 作为一个挂载的个人同步文件夹,自动同步版本、发布和录入。
- 作为加密文件或数据共享系统。
- 作为所有软件的版本化包管理器。
- 作为虚拟机的根文件系统。
- 作为虚拟机的启动文件系统(在管理程序下)。
- 作为数据库:应用程序可以直接写入Merkle DAG数据模型,并获得IPFS提供的所有版本控制、缓存和分发功能。
- 作为一个链接(和加密)的通信平台。
- 作为一个完整性检查大型文件(没有SSL)的cdn。
- 作为加密的cdn。
- 在网页上,作为网络cdn。
- 作为一个新的链接不会消失的永久性网站。
IPFS的目标:
- 要在自己的应用程序中导入的IPFS库。
- 直接操作对象的命令行工具。
- 安装的文件系统,使用fuse[?]或作为内核模块。
4.未来
IPFS背后的思想是学术界和开源领域数十年来成功的分布式系统的研究成果。IPFS综合了迄今为止最成功的系统中的许多最佳想法。撇开Bitswap不谈,IPFS是一种新的协议,其主要贡献是系统的耦合和设计的综合。 IPFS是一个雄心勃勃的新的去中心化互联网基础设施的愿景,许多不同类型的应用程序可以在此基础上构建。至少,IPFS可以用作一个全局的、安装的、版本控制的文件系统和名称空间或者下一代文件共享系统。若一切顺利,IPFS可以给我们一种新的互联网视野,在那里,发布有价值的信息不会把它强加给出版商,而是散布给那些感兴趣的人,用户可以信任他们接收到的信息(而不是信任对等节点),以及那些旧的但重要的文件不会丢失。IPFS有望把我们带进永久网络。
5.致谢
IPFS是许多伟大思想和系统的综合。如果不站在这些巨人的肩上,我们就不敢言能够实现如此宏伟的目标。感谢David Darrymple、Joe Zimmerman和Ali Yahya就这些想法进行了长时间的讨论,特别是:Merkle Dag将军(David,Joe)、Rolling Hash Blocking(David)和S/Kademlia Sybill Protection(David,Ali)。特别感谢大卫·马西耶斯,他有着永恒辉煌的想法。
6.参考文献
- Baumgart and S. Mies. S/kademlia: A practicable approach towards secure key-based routing. In Parallel and Distributed Systems, 2007 International Conference on, volume 2, pages 1–8. IEEE, 2007.
- BitTorrent. Bittorrent and A¸ttorrent software ˆ surpass 150 million user milestone, Jan. 2012.
- Cohen. Incentives build robustness in bittorrent. In Workshop on Economics of Peer-to-Peer systems, volume 6, pages 68–72, 2003.
- Dean and S. Ghemawat. leveldb–a fast and lightweight key/value database library by google, 2011.
- J. Freedman, E. Freudenthal, and D. Mazieres. Democratizing content publication with coral. In NSDI, volume 4, pages 18–18, 2004.
- H. Howard, M. L. Kazar, S. G. Menees, D. A. Nichols, M. Satyanarayanan, R. N. Sidebotham, and M. J. West. Scale and performance in a distributed file system. ACM Transactions on Computer Systems (TOCS), 6(1):51–81, 1988.
- Kubiatowicz, D. Bindel, Y. Chen, S. Czerwinski, P. Eaton, D. Geels, R. Gummadi, S. Rhea, H. Weatherspoon, W. Weimer, et al. Oceanstore: An architecture for global-scale persistent storage. ACM Sigplan Notices, 35(11):190–201, 2000.
- Levin, K. LaCurts, N. Spring, and B. Bhattacharjee. Bittorrent is an auction: analyzing and improving bittorrent’s incentives. In ACM SIGCOMM Computer Communication Review, volume 38, pages 243–254. ACM, 2008.
- J. Mashtizadeh, A. Bittau, Y. F. Huang, and D. Mazieres. Replication, history, and grafting in the ori file system. In Proceedings of the Twenty-Fourth ACM Symposium on Operating Systems Principles, pages 151–166. ACM, 2013.
- Maymounkov and D. Mazieres. Kademlia: A peer-to-peer information system based on the xor metric. In Peer-to-Peer Systems, pages 53–65. Springer, 2002.
- Mazieres and F. Kaashoek. Self-certifying file system. 2000.
- Mazieres and M. F. Kaashoek. Escaping the evils of centralized control with self-certifying pathnames. In Proceedings of the 8th ACM SIGOPS European workshop on Support for composing distributed applications, pages 118–125. ACM, 1998.
- Rosenberg and A. Keranen. Interactive connectivity establishment (ice): A protocol for network address translator (nat) traversal for offer/answer protocols. 2013.
- Shalunov, G. Hazel, J. Iyengar, and M. Kuehlewind. Low extra delay background transport (ledbat). draft-ietf-ledbat-congestion-04. txt, 2010.
- R. Stewart and Q. Xie. Stream control transmission protocol (SCTP): a reference guide. Addison-Wesley Longman Publishing Co., Inc., 2001.
- Wang and J. Kangasharju. Measuring large-scale distributed systems: case of bittorrent mainline dht. In Peer-to-Peer Computing (P2P), 2013 IEEE Thirteenth International Conference on, pages 1–10. IEEE, 2013.