![]() IPFS(中文白皮书) IPFS - 可快速索引的版本化的点对点文件系统 作者: Juan Benet 译者: 郭光华 整理:赛道科技 摘要 星际文件系统是一种点对点的分布式文件系统,旨在连接所有有相同的文件系统的计算机设备。在某些方面,IPFS类似于web, 但web 是中心化的,而IPFS是一个单一的Bittorrent 群集,用git 仓库分布式存储。换句话说,IPFS 提供了高吞吐量的内容寻址块存储模型,具有内容寻址的超链接。这形成了一个广义的Merkle DAG 数据结构,可以用这个数据结构构建版本文件系统,区块链,甚至是永久性网站。IPFS 结合了分布式哈希表,带有激励机制的块交换和自我认证命名空间。IPFS没有单故障点,节点不需要相互信任。 1. 介绍 在全球分布式文件系统这领域,已经有许多人的尝试。一些系统已经取得了重大的成功,而很多却完全失败了。在学术尝试中,AFS【6】就是成功的例子,如今已经得到广泛的应用,然而,其他的【7,?】却没有得到相同的结果。在学术界之外,应用最广泛的是面向音视频媒体的点对点文件共享系统。最值得注意的是,Napster, KaZaA 和BitTorrent[2]部署的文件分发系统支持1亿用户的同时在线。即使在今天,BitTorrent 也维持着每天千万节点的活跃数。基于这些学术文件系统理论而实现的应用程序有很多的用户量,然而,这些系统理论是在应用层,而没有放在基础层。以致没有出现通用的文件系统基础框架,给全球提供低延迟的分发。 也许是因为HTTP这样“足够好“的系统已经存在。到目前为止,HTTP已经作为“分布式文件系统“的协议,并且已经大量部署,再与浏览器相结合,具有巨大的技术和社会影响力。在现在,它已经成为互联网传输文件的事实标准。然而,他没有采用最近15年的发明的数十种先进的文件分发技术。从一方面讲,由于向后兼容的限制和当前新模式的投入,不断发展httpweb 的基础设施几乎是不可能的。但从一个角度看,从http 出现以来,已经有许多新协议出现并被广泛使用。升级http协议虽然能引入新功能和加强当前http协议,但会降低用户的体验。 有些行业已经摆脱使用HTTP这么久,因为移动小文件相对便宜,即使对拥有大流量的小组织也是如此。但是,随着新的挑战,我们正在进入数据分发的新纪元。 · (a)托管和分发PB级数据集, · (b)跨组织的大数据计算, · (c)大批量的高清晰度按需或实时媒体流, · (d)大规模数据集的版本化和链接, · (e)防止意外丢失重要文件等。其中许多可以归结为“大量数据,无处不在”。由于关键功能和带宽问题,我们已经为不同的数据放弃了HTTP 分销协议。下一步是使它们成为web自己的一部分。 · 正交于有效的数据分发,版本控制系统,已经设法开发重要的数据协作工作流程。Git是分布式源代码版本控制系统,开发了许多有用的方法来建模和实现分布式数据操作。Git工具链提供了灵活的版本控制功能,这正是大量的文件分发系统所严重缺乏的。由Git启发的新解决方案正在出现,如Camlistore [?],个人文件存储系统,Dat [?]数据协作工具链和数据集包管理器。Git已经影响了分布式文件系统设计[9],因为其内容涉及到Merkle DAG数据模型,能够实现强大的文件分发策略。还有待探讨的是,这种数据结构如何影响面向高吞吐量的文件系统的设计,以及如何升级Web本身。 · 本文介绍了IPFS,一种新颖的对等版本控制的文件系统,旨在调和这些问题。IPFS综合了许多以前成功的系统的优点。IPFS产生了突出的效果,甚至比参考的这些系统的总和还要好。IPFS的核心原则是将所有数据建模为同一Merkle DAG的一部分。 2. 背景 本节回顾了IPFS所采用成功的点对点系统技术的重要属性。 2.1 分布式哈希表(DHT) 分布式散列表(DHT)被广泛用于协调和维护关于对等系统的元数据。比如,MainlineDHT 是一个去中心化哈希表,他可追踪查找所有的对等节点。 2.1.1KADEMLIA DHT Kademlia[10] 是受欢迎的DHT, 它提供: 1.通过大量网络进行高效查询:查询平均联系人O(log2N)节点。(例如,20跳10万个节点的网络) 2.低协调开销:优化数量的控制消息发送到其他节点。 3.抵抗各种攻击,喜欢长寿节点。 4.在对等应用中广泛使用,包括Gnutella和BitTorrent,形成了超过2000万个节点的网络[16]。 2.1.2 CORALDSHT 虽然一些对等文件系统直接在DHT中存储数据块,这种“数据存储在不需要的节点会乱费存储和带宽”[5]。Coral DSHT扩展了Kademlia三个特别重要的方式: 1.Kademlia在ids为“最近”(使用XOR-distance)的关键节点中存储值。这不考虑应用程序数据的局部性,忽略“远”可能已经拥有数据的节点,并强制“最近”节点存储它,无论它们是否需要。这浪费了大量的存储和带宽。相反,Coral 存储了地址,该地址的对等节点可以提供相应的数据块。 2.Coral将DHT API从get_value(key)换成了get_any_values(key)(DSHT中的“sloppy”)中。这仍然是因为Coral用户只需要一个(工作)的对等体,而不是完整的列表。作为回报,Coral可以仅将子集分配到“最近”的节点,避免热点(当密钥变得流行时,重载所有最近的节点)。 3.另外,Coral根据区域和大小组织了一个称为群集的独立DSHT层次结构。这使得节点首先查询其区域中的对等体,“查找附近的数据而不查询远程节点”[5]并大大减少查找的延迟。 2.1.3S/KADEMLIA DHT S/Kademlia[1] 扩展了Kademlia, 用于防止恶意的攻击。有如下两方面的方法: 1.S/Kad 提供了方案来保证NodeId的生成已经防止Sybill攻击。它需要节点产生PKI公私钥对。从中导出他们的身份,并彼此间签名。一个方案使用POW工作量证明,使得生成Sybills成本高昂。 2.S/Kad 节点在不相交的路径上查找直,即使网络中存在大量的不诚实节点,也能确保诚实节点可以互相链接。即使网络中存在一半的不诚实节点,S/Kad 也能达到85%的成功率。 2.2 块交换 - BitTorrent BitTorrent[3] 是一个广泛成功应用的点对点共享文件系统,它可以在存在不信任的对等节点(群集)的协作网络中分发各自的文件数据片。从BitTorrent和它的生态系统的关键特征,IPFS得到启示如下: 1.BitTorrent的数据交换协议使用了一种bit-for-tat的激励策略,可以奖励对其他方面做贡献的节点,惩罚只榨取对方资源的节点。 2.BitTorrent对等体跟踪文件的可用性,优先发送稀有片段。这减轻了seeds节点的负担,让non-seeds节点有能力互相交易。 3.对于一些剥削带宽共享策略,BitTorrent的标准tit-for-tat策略是非常脆弱的。然而,PropShare[8]是一种不同的对等带宽分配策略,可以更好的抵制剥削战略,提高群集的表现。 2.3. 版本控制系统- Git 版本控制系统提供了对随时间变化的文件进行建模的设施,并有效地分发不同的版本。流行版本控制系统Git提供了强大的Merkle DAG对象模型,以分布式友好的方式捕获对文件系统树的更改。 1.不可更改的对象表示文件(blob),目录(树)和更改(提交)。 2.通过加密hash对象的内容,让对象可寻址。 3.链接到其他对象是嵌入的,形成一个Merkle DAG。这提供了很多有用的完整和work-flow属性。 4.很多版本元数据(分支,标示等等)都只是指针引用,因此创建和更新的代价都小。 5.版本改变只是更新引用或者添加对象。 6.分布式版本改变对其他用户而言只是转移对象和更新远程引用。 2.4 自我认证认文件系统-SFS SFS [ 12,11 ]提出了两个引人注目的实现(a)分布式信任链,和(b)平等共享的全局命名空间。SFS引入了一种自我建构技术—注册文件:寻址远程文件系统使用以下格式: 1 2 3 /sfs/ Location:代表的是服务网络地方 HostID = hash(public_key || Location) 因此SFS文件系统的名字认证了它的服务,用户可以通过服务提供的公钥来验证,协商一个共享的私钥,保证所有的通信。所有的SFS实例都共享了一个全局的命名空间,这个命名空间的名称分配是加密的,不被任何中心化的body控制。 3. IPFS设计 IPFS是一个分布式文件系统,它综合了以前的对等系统的成功想法,包括DHT,BitTorrent,Git和SFS。IPFS的贡献是简化,发展和将成熟的技术连接成一个单一的内聚系统,大于其部分的总和。IPFS提供了编写和部署应用程序的新平台,以及一个新的分发系统版本化大数据。IPFS甚至可以演进网络本身。 IPFS是点对点的;没有节点是特权的。IPFS节点将IPFS对象存储在本地存储中。节点彼此连接并传输对象。这些对象表示文件和其他数据结构。IPFS协议分为一组负责不同功能的子协议: 1. 身份 - 管理节点身份生成和验证。描述在3.1节。 2.网络 - 管理与其他对等体的连接,使用各种底层网络协议。可配置的。详见3.2节。 3.路由 - 维护信息以定位特定的对等体和对象。响应本地和远程查询。默认为DHT,但可更换。在3.3节描述。 4.交换 - 一种支持有效块分配的新型块交换协议(BitSwap)。模拟市场,弱化数据复制。贸易策略可替换。描述在3.4节。 5.对象 - 具有链接的内容寻址不可更改对象的MerkleDAG。用于表示任意数据结构,例如文件层次和通信系统。详见第3.5节。 6.文件 - 由Git启发的版本化文件系统层次结构。详见3.6节。 7.命名 - 自我认证的可变名称系统。详见3.7节。 这些子系统不是独立的;它们是集成在一起,互相利用各自的属性。但是,分开描述它们是有用的,从下到上构建协议栈。符号:Go语言中指定了以下数据结构和功能 3.1 身份 节点由NodeId标识,这是使用S / Kademlia的静态加密难题[1]创建的公钥的密码散列。节点存储其公私钥(用密码加密)。用户可以在每次启动时自由地设置一个“新”节点身份,尽管这会损失积累的网络利益。激励节点保持不变。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type NodeId Multihash type Multihash []byte // 自描述加密哈希摘要 type PublicKey []byte type PrivateKey []byte// 自描述的私钥 type Node struct { NodeId NodeID PubKey PublicKey PriKey PrivateKey } 基于S / Kademlia的IPFS身份生成: difficulty = n = Node{} do { n.PubKey, n.PrivKey = PKI.genKeyPair() n.NodeId = hash(n.PubKey) p = count_preceding_zero_bits(hash(n.NodeId)) } while (p < difficulty) 首次连接时,对等体交换公钥,并检查:hash(other.PublicKey)等于other.NodeId。如果没有,则连接被终止 关于加密函数的注意事项: IPFS不是将系统锁定到一组特定的功能选择,而是支持自我描述的值。哈希摘要值以多重哈希格式存储,其包括指定使用的哈希函数的头和以字节为单位的摘要长度。例如: 1 这允许系统 (a)选择最佳功能用例(例如,更强的安全性与更快的性能), (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将地址存储为多层地址,这个多层地址是由字节字符串组成的,以便于给底层网络使用。多层地址提供了一种方式来表示地址及其协议,可以封装成好解析的格式。例如: 1 2 3 4 # 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只存储值索引,这个索引就是一个对等节点的NodeId, 该对等节点可以提供對该类型的值的具体服务。 DSHT的接口如下: 1 2 3 4 5 6 7 type IPFSRouting interface { FindPeer(node NodeId) // 获取特定NodeId的网络地址。 SetValue(key []bytes, value []bytes) // 往DHT存储一个小的元数据。 GetValue(key []bytes) // 从DHT获取元数据。 ProvideValue(key Multihash) // 声明这个节点可一个提供一个大的数据。 FindValuePeers(key Multihash, min int) // 获取服务于该大数据的节点。 } 注意:不同的用例将要求基本不同的路由系统(例如广域网中使用DHT,局域网中使用静态HT)。因此,IPFS路由系统可以根据用户的需求替换的。只要使用上面的接口就可以了,系统都能继续正常运行。 3.4块交换 - BitSwap协议 IPFS 中的BitSwap协议受到BitTorrent 的启发,通过对等节点间交换数据块来分发数据的。像BT一样,每个对等节点在下载的同时不断向其他对等节点上传已下载的数据。和BT协议不同的是,BitSwap 不局限于一个torrent文件中的数据块。BitSwap 协议中存在一个永久的市场。这个市场包括各个节点想要获取的所有块数据。而不管这些块是哪些如.torrent文件中的一部分。这些快数据可能来自文件系统中完全不相关的文件。这个市场是由所有的节点组成的。 虽然易货系统的概念意味着可以创建虚拟货币,但这将需要一个全局分类账本来跟踪货币的所有权和转移。这可以实施为BitSwap策略,并将在未来的论文中探讨。 在基本情况下,BitSwap节点必须以块的形式彼此提供直接的值。只有当跨节点的块的分布是互补的时候,各取所需的时候,这才会工作的很好。通常情况并非如此,在某些情况下,节点必须为自己的块而工作。在节点没有其对等节点所需的(或根本没有的)情况下,它会更低的优先级去寻找对等节点想要的块。这会激励节点去缓存和传播稀有片段,即使节点对这些片段不感兴趣。 3.4.1 -BITSWAP 信用 这个协议必须带有激励机制,去激励节点去seed 其他节点所需要的块,而它们本身是不需要这些块的。因此,BitSwap的节点很积极去给对端节点发送块,期待获得报酬。但必须防止水蛭攻击(空负载节点从不共享块),一个简单的类似信用的系统解决了这些问题: 1,对等节点间会追踪他们的平衡(通过字节认证的方式)。 2,随着债务增加而概率降低,对等者概率的向债务人发送块。 注意的是,如果节点决定不发送到对等体,节点随后忽略对等体的ignore_cooldown超时。这样可以防止发送者尝试多次发送(洪水攻击)(BitSwap默认是10秒)。 3.4.2BITSWAP的策略 BitSwap 对等节点采用很多不同的策略,这些策略对整个数据块的交换执行力产生了不同的巨大影响。在BT 中,标准策略是明确规定的(tit-for-tat),其他不同的策略也已经被实施,从BitTyrant [8](尽可能分享)到BitThief [8](利用一个漏洞,从不共享),到PropShare [8](按比例分享)。BitSwap 对等体可以类似地实现一系列的策略(良好和恶意)。对于功能的选择,应该瞄准: 1.为整个交易和节点最大化交易能力。 2.为了防止空负载节点利用和损害交易。 3.高效抵制未知策略。 4.对可信任的对等节点更宽容。 探索这些策略的空白是未来的事情。在实践中使用的一个选择性功能是sigmoid,根据负债比例进行缩放: 让负债比例在一个节点和它对等节点之间: 1 r = bytes_sent / bytes_recv + 1 根据r,发送到负债节点的概率为: 1 P(send | r ) = 1 �6�1 ( 1/ ( 1 + exp(6 �6�1 3r) ) ) 正如你看到的图片1,当节点负债比例超过节点已建立信贷的两倍,发送到负债节点的概率就会急速下降。 图片1 当r增加时发送的概率 负债比是信任的衡量标准:对于之前成功的互换过很多数据的节点会宽容债务,而对不信任不了解的节点会严格很多。这个(a)给与那些创造很多节点的攻击者(sybill 攻击)一个障碍。(b)保护了之前成功交易节点之间的关系,即使这个节点暂时无法提供数据。(c)最终阻塞那些关系已经恶化的节点之间的通信,直到他们被再次证明。 3.4.3BITSWAP 账本 BitSwap节点保存了一个记录与所有其他节点之间交易的账本。这个可以让节点追踪历史记录以及避免被篡改。当激活了一个链接,BitSwap节点就会互换它们账本信息。如果这些账本信息并不完全相同,分类账本将会重新初始化,那些应计信贷和债务会丢失。恶意节点会有意去失去“这些“账本,从而期望清除自己的债务。节点是不太可能在失去了应计信托的情况下还能累积足够的债务去授权认证。伙伴节点可以自由的将其视为不当行为,拒绝交易。 1 2 3 4 5 6 7 type Ledger struct { owner NodeId partner NodeId bytes_sent int bytes_recv int timestamp Timestamp } 节点可以自由的保留分布式账本历史,这不需要正确的操作,因为只有当前的分类账本条目是有用的。节点也可以根据需要自由收集分布式帐本,从不太有用的分布式帐开始:老(其他对等节点可能不存在)和小。 3.4.4BITSWAP 详解 BitSwap 节点有以下简单的协议。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 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 peers 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.Open: 对等节点间发送ledgers 直到他们同意。 2.Sending: 对等节点间交换want_lists 和blocks。 3.Close: 对等节点断开链接。 4.Ignored: (特殊)对等体被忽略(等待时间的超时)如果节点采用防止发送策略。 Peer.open(NodeId,Ledger). 当发生链接的时候,节点会初始化链接的账本,要么保存一个份链接过去的账本,要么创建一个新的被清零的账本。然后,发送一个携带账本的open信息给对等节点。 接收到一个open信息之后,对等节点可以选择是否接受此链接。如果,根据接收者的账本,发送者是一个不可信的代理(传输低于零或者有很大的未偿还的债务),接收者可能会选择忽略这个请求。忽略请求是ignore_cooldown超时来概率性实现的,为了让错误能够有时间改正和攻击者被挫败。 如果链接成功,接收者用本地账本来初始化一个Peer对象以及设置last_seen时间戳。然后,它会将接受到的账本与自己的账本进行比较。如果两个账本完全一样,那么这个链接就被Open,如果账本并不完全一致,那么此节点会创建一个新的被清零的账本并且会发送此账本。 Peer.send_want_list(WantList) 当链接已经Open的时候,节点会广发它们的want_list给所有已经链接的对等节点。这个是在(a)open链接后(b)随机间歇超时后(c)want_list改变后(d)接收到一个新的块之后完成的。 当接收到一个want_list之后,节点会存储它。然后,会检查自己是否拥有任何它想要的块。如果有,会根据上面提到的BitSwap策略来将want_list所需要的块发送出去。 Peer.send_block(Block) 发送一个块是直接了当的。节点只是传输数据块。当接收到了所有数据的时候,接收者会计算多重hash校验和来验证它是否是自己所需数据,然后发送确认信息。 在完成一个正确的块传输之后,接受者会将此块从need_list一到have_list,最后接收者和发送者都会更新它们的账本来反映出传输的额外数据字节数。 如果一个传输验证失败了,发送者要么会出故障要么会攻击接收者,接收者可以选择拒绝后面的交易。注意,BitSwap是期望能够在一个可靠的传输通道上进行操作的,所以传输错误(可能会引起一个对诚实发送者错误的惩罚)是期望在数据发送给BitSwap之前能够被捕捉到。 Peer.close(Bool) 传给close最后的一个参数,代表close链接是否是发送者的意愿。如果参数值为false,接收者可能会立即重新open链接,这避免链过早的close链接。 一个对等节点close链接发生在下面两种情况下: silence_wait超时已经过期,并且没有接收到来自于对等节点的任何信息(BitSwap默认使用30秒),节点会发送Peer.close(false)。 在节点退出和BitSwap关闭的时候,节点会发送Peer.close(true). 接收到close消息之后,接收者和发送者会断开链接,清除所有被存储的状态。账本可能会被保存下来为了以后的便利,当然,只有在被认为账本以后会有用时才会被保存下来。 注意点: 非open信息在一个不活跃的连接上应该是被忽略的。在发送send_block信息时,接收者应该检查这个块,看它是否是自己所需的,并且是否是正确的,如果是,就使用此块。总之,所有不规则的信息都会让接收者触发一个close(false)信息并且强制性的重初始化此链接。 3.5 Merkle DAG对象 DHT和BitSwap允许IPFS构造一个庞大的点对点系统用来快速稳定的分发和存储。最主要的是,IPFS建造了一个Merkle DAG,一个无回路有向图,对象之间的links都是hash加密嵌入在源目标中。这是Git数据结构的一种推广。Merkle DAGS给IPFS提供了很多有用的属性,包括: 1.内容可寻址:所有内容都是被多重hash校验和来唯一识别的,包括links。 2.防止篡改:所有的内容都用它的校验和来验证。如果数据被篡改或损坏,IPFS会检测到。 3.重复数据删除:所有的对象都拥有相同的内容并只存储一次。这对于索引对象非常有用,比如git的tree和commits,或者数据的公共部分。 IPFS对象的格式是: 1 2 3 4 5 6 7 8 9 10 type IPFSLink struct { Name string // 此link的别名 Hash Multihash // 目标的加密hash Size int // 目标总大小 } type IPFSObject struct { links []IPFSLink //links数组 data []byte //不透明内容数据 } IPFS Merkle DAG是存储数据非常灵活的一种方式。只要求对象引用是(a)内容可寻址的,(b)用上面的格式编码。IPFS允许应用完全的掌控数据域;应用可以使用任何自定义格式的数据,即使数据IPFS都无法理解。单独的内部对象link表允许IPFS做: 用对象的形式列出所有对象引用,例如: 1 2 3 4 5 6 > ipfs ls /XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzb XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x 189458 less XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5 19441 script XLF4hwVHsVuZ78FZK6fozf8Jj9WEURMbCX4 5286 template |
| 本文出处: https://www.toutiao.com/a6617223477558510083/ |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|