星际文件系统(IPFS)一瞥,及其可能的用途(未完)

# 新事物 | Rerum novarum: 对等网络 星际理论
本文更新计划和进度
IPFS 项目的历史
Content-based Addressing
Peer-to-peer sharing
  • DHT
  • Bitswap
  • IPNS
  • IPFS Gateway
  • DNSLink(待考虑)
笔者按

IPFS 与加密货币如胶似漆的样子让笔者不禁冷颤,似乎 P2P 注定走上主观价值的道路,成为投机家的禁脔,但是 P2P 的诞生却秉持着与其结果截然相反的理想精神。IPFS 也是如此,弗论其商业行为,它的理念和原理,在许多层面有着积极意义。

IPFS 项目的历史 [1]

A(1999~2003)

1999年,Napster 的出现改变了网络,以它提供的免费且无限制的音乐档案服务,震撼了世界,尤其是改变了(那时的)大学生们使用互联网的方式。与此同时,唱片公司并没有适应互联网这种新兴事物,还在固守传统的商业模式。这给了乔布斯和 Napster 机遇,前者选择了建立中心式分发平台 iTunes,而后者则开启一个崭新的时代。彼时 peer-to-peer(P2P) 网络对于大多数人还是一个全新的模式,尽管他这个概念早在1969年4月7日的 RFC 1 文档中就有描述,但是直到 Napster 才开始让这个概念在网络用户中普及。Napster 作为第一个被广泛应用的 P2P 音乐共享服务,扫清了人们自由分享媒体文件的最后一道屏障。接下来就是P2P科技竞相登场的夏天,新奇和令人振奋的想法和公司像雨后春笋一般登上历史的舞台:Gnutella, Kazaa, MojoNation, BitTorrent, Skype 等等。

Napster 官方客户端,Mac OS 9,iBook<sup id=fnref:2><a href=#fn:2 rel=footnote><span class=hint--top hint--medium hint--rounded hint--bounce aria-label=[Napster running on an original iBook](https://en.wikipedia.org/wiki/Napster#/media/File:Napster_running_on_an_original_iBook_(2001-03-11).png)>[2]</span></a></sup>
Napster 官方客户端,Mac OS 9,iBook[2]

它们中的一些项目对于技术的理想主义者们有着莫大的吸引力,所以它们很快就赢得了巨大的市场。像 Napster, Skype 和 BitTorrent 在 P2P 技术上的突破开启了许多很新奇并且后来被认为具有重要价值的服务。但是,这个时代在法律审查的重压之下不得不走向衰落。在 P2P 网络中大量的分享都是版权内容,其引起的各种版权纠纷事件成为了压垮 P2P 创新的最后一根稻草。在这过程中,竞争的力量始终扮演着重要的角色。P2P 或许是一个理想的网络架构,然而 C/S(客户端/服务器)的架构能让那些项目更好的进行集中控制和商业化,它们的中心化的服务不断从网络中集中价值,其中的利润使得投资像飞轮一样驱使着来年不断的超规模的扩增。

这些项目之所以能够成功是因为他们的 P2P 架构,而不是因为项目本身有多么大的吸引力,使用 C/S 架构以后,它们依然可以发展得风生水起。尽管如此,那些项目本身也由于架构的转变而发生了潜移默化的变化——它们的着力点从“自由分享”变成了“高质量的内容”——人们或许可以有更好的体验,但是失去了选择和自由的权利。这些过往的 P2P 项目向我们昭示了一种可能性,P2P 凭借着它独特的魅力和秉性,随着科技的发展和时间推移,它将如闪电般归来。

B(2013~2017)

Juan Benet[3] 成长在世纪之交,亲身体验过 P2P 网络的魅力。当他在斯坦福学习计算科学的时候,他将他的专业兴趣定为分布式网络。2013年,Juan 正在进行一个项目时有了灵感。他发现当时用于分享和版本控制大型数据集的工具非常的低效且错误频发。更糟糕的是,这种知识前往往横亘着高昂的价格壁垒。他想,有没有一种可能,利用自己在软件开发和分布式系统——尤其是P2P系统——的背景,提出一种更好解决这些问题的方法。

二叉哈希树
图中最下部的 L1, L2, L3, L4 可以被称为叶结点,它们通常存储着数据,即 Data Blocks。而它们的父节点,以至于所有非叶子节点(中间节点和顶节点——图中的 Hash * 和 Top Hash),存储着他们两个子节点内容的哈希值。例如我们看最左支,Top Hash 节点存储着 Hash 0 节点和 Hash 1 节点(通过某种方式)相加后的哈希值。以此类推,Hash 0 节点存储着 Hash 0-0 和 Hash 0-1 节点的哈希值,如果它还有子节点那么就重复上述操作,直至最底层叶节点,正如 Hash 0-0 和 Hash 0-1 直接存储着 L1 和 L2 数据块的哈希值。

哈希树会逐层记录数据的哈希值,会使任何最底层数据的变动传导至其父节点,并延及树根。我们可以把哈希树看作对数据的分层摘要。只需要比较各级的哈希值就可以在不暴露数据内容的情况下得知数据的完整性。当两个哈希树的根节点哈希值一致时,两棵树代表的数据一定相同,而且 Hash 计算可以十分快速,因此在比较大量数据时,使用哈希树具有较大的性能优势。同时,如图中的 L1 数据变动,会逐层传导至 Hash 0-0, Hash 0 直到 Top Hash,因此一旦发生根节点数值发生变动,沿着 Top Hash -> Hash 0 -> Hash 0-0 这条路径,定位的复杂度只有 $O(lgN) $ 。

Git 管理软件的版本控制和协作利用的是一种被称为 Merkle tree (即默克尔树、哈希树)的数据连接结构。Git的方法对于涉及多种数据类型的情况十分有效,而且不只是代码,Juan 意识到这种方法与 BitTorrent 的 P2P 文件共享结构的概念结合后会更为强大:实用、安全的信息共享方法,而且不会有集中化的壁垒——它或许能够超越科学数据集,改变世界。

怀揣着这个想法,Juan 创立了 IPFS 项目。

InterPlanetary File System 这个名字显得十分宏大,这让笔者想起来 Paul Krugman 的“星际贸易理论”。这种出于幻想而进行的严肃讨论,未免不是学术界的一种幽默的底色,恰是这种理想主义建构了我们所处的现代社会。正如 IPFS 的踌躇满志一样,Juan 不打算止步于此。他在2014年5月成立了 Protocal Labs,用于支持开放式网络基础设施的基础研究、开发和部署,并把 IPFS 和与相补充的奖励层 Filecoin 作为第一批项目。Protocal Labs 是以独立的“贝尔实验室”为模版打造的(IPFS 生态系统之外,Protocol Labs 后来还曾孵化了包括 Coinlist, The SAFT Project 和 SourceCred 等一众项目)。Protocal Labs 进入了 Y Combinator Summer 2014 Class (不知道怎么翻译,大概意思是获得了 Y Combinator 的初创投资)。Juan 开始着手编写程序以及——最为重要的——IPFS 白皮书。

IPFS 白皮书在2014年7月公布。它很快就引起了 P2P 和网络爱好者的关注,其中就包括 Jeromy Johnson。Jeromy 和其他早期贡献者支持 Juan 的关于分布式、不可审查、无需许可的文件系统的构想。于是,他们在夜以继日、废寝忘食地工作(并且摄入了大量咖啡)后,在 Juan 的客厅里鼓捣出来了第一个 alpha 发行版 Kubo。

在2015年的夏天,有着五六个全职贡献者的小团队进驻了西雅图的一个共享空间。在经过激烈讨论之后,IPFS 团队一致认为当务之急是做出来 Go 和 Js 的 IPFS 实现。2009年,中本聪的比特币白皮书重新掀起了 P2P 文艺复兴的浪潮,又一个 P2P 之夏正如火如荼地进行。IPFS 在以太坊和更广泛的区块链社区中获得了使用。在2015年9月,Neocites 成为首个在生产环境中应用 IPFS 的主流站点。西雅图的工作和 Neocities 的合作收获颇丰,并在2016年4月发布的 Kubo 0.4.0 版本中得以体现。0.4.0的改进使 IPFS 从一个“令人兴奋的 demo”过渡成一个对早期使用者真正有用的工具。

IPFS 项目的技术和社区在2016年有了长足进步。Multiformats, libp2p, IPLD 作为独立项目从 IPFS 中分离出去。IPFS 团队参加并主持了许多开发社区聚会,其中有着被团队认为是“高光时刻”的 Dencentralized Web Summit。

在2017年,有几件事情印证了 IPFS 的日益高涨的热度。一个是 IPFS的软件工程师 Jakub Sztandera 为了抵抗土耳其国家的审查制度,将土耳其语版的维基百科快照放到了 IPFS 上。二是在2017年9月至10月间的举办的2017年加泰罗尼亚独立公投,因被西班牙宪法法院认定违法而使网站被屏蔽。此后,加泰罗尼亚海盗党将网站整个镜像到 IPFS 上以回避加泰罗尼亚高等法院的屏蔽命令[4]。 三是 Filecoin 在发布后的三十分钟内募集了超过2亿美元的资金[5]

C(2018至今)

2019年6月,Protocol Labs 在巴塞罗那举办了第一次 IPFS Camp,聚集了150名分布式网络的爱好者和技术人员参加,并其促成了与网飞的合作。截止2019年底,IPFS 网络规模增长了30x以上,开源贡献者社区的人数也超过了4000人。2020年4月 Kubo 0.5.0 发布,大幅度优化了性能,并发布了 Testground 测试系统。IPFS团队声称,与 Oprea, Mircosoft ION 和 Cloudflare 的合作只是触及 IPFS 可能性的表面,2020年下半年启动的 Filecoin 主网才是与 C/S 传统架构对抗的基石,并且将在根本上改变 P2P IPFS 网络的经济动机。

IPFS 的概念

基于内容的寻址(Content-based Addressing)

我们平时在网络上接触最多的大概就是基于 TCP 协议的 HTTP(S) 协议了。而 IPFS 声称要补充/取代 HTTP[6]

If built right, it could complement or replace HTTP. It could complement or replace even more.

而 IPFS 和 HTTP 最大的区别在于,HTTP 是 location-based addressing,即基于地址的寻址,而 IPFS (主要)是 content-based addressing,即基于内容的寻址。

传统的 URL 大概都是这个样子:

https://en.wikipedia.org/static/images/project-logos/enwiki.png

传统的 URL 由协议://域名/目录/文件名组成。如果考虑到服务端可以对 HTTP 的返回内容进行眼花缭乱的操作,真实情况可能比看起来复杂。

事实上,几乎上所有有一定规模网页都并不是像 协议://域名/目录/文件名 这样的请求返回的,而是 协议://域名/目录/关键字,毕竟不是所有人都希望每次在 URL 机械地敲上 html, php… HTTP 服务端会处理好关键字所对应的内容,并返回给浏览器。网页是我们最为常见的资源类型,但并不是最多的。大量充斥在互联网上的静态媒体文件,并不都像网页地址那样有个性,几乎都遵循着传统的基于地址的寻址方式,即 协议://域名/目录/文件名。这种差别主要是因为网页提供者们更期望动态地更新部分信息,所以重要的不在于 index.html 诸如此类的网页文件,而是可被浏览器渲染的数据;而静态媒体文件,由于更大的数据量和几乎没有余地的整体性(总不能期望每次都对一个图片或者视频进行编辑,这样的性能要求对服务器来说过于痛苦,所以更倾向于将这些问题交给客户端-浏览器处理),内容提供者们更青睐于静态存放、引用。

尽管如此,传统的 URL 基本上秉承着通过文件的位置来寻找文件的思想。文件被存储在可以有层级的目录(directories)之中,域名后的/即根目录(root)。

这样是符合人类上千年阅读习惯的,前有图书索引(index),后有 index.html,但这也是反直觉的,主要体现在两个问题上:

  • 如果有两张图片存储在网络上的不同位置上,根据基于地址的寻址,即使这两张图片一模一样,也需要占用两份空间。
  • 即使网络上有若干媒体文件的拷贝,但是如果你所知道的 URL 由于各种原因无法访问,你就下载不了这份媒体文件。

CID (Content Identifiers)

所以许多 P2P 网络为了避免这些问题,包括 IPFS, BitTorrent ,采用了 content-based addressing,即基于内容的寻址。如常见的磁力链接(在 magnet: 统一磁力链接标准之前有许多私有协议,如 ed2k:, freenet:,以及现在仍有在使用的迅雷私有协议 thunder:)。

以(随便找的)Ubuntu 22.04 LTS 为例
magnet:?xt=urn:btih:2C6B6858D61DA9543D4231A71DB4B1C9264B0685

这一串 2C6B6858D61DA9543D4231A71DB4B1C9264B0685 被称为 BTIH, BitTorrent Info Hash,也就是我们想要下载资源文件的哈希值。对于 BT 网络来说,它代表着我们想要下载的 BT 种子。基于类似的考虑,IPFS 也有这样的一串标识符,被称为 CID, Content Identifiers,通常看起来像这个样子 QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco

正如 BTIH 的值是指向内容的 SHA-1 散列的 Base32 编码,CID 的值是指向其内容的哈希树的 SHA-256 (默认)的 Base58 编码。值得注意的是 Content Identifiers are not file hashes ——CID并不是像BTIH指向的是文件内容的散列,而是前文所说的哈希树(默克尔树、有向无环图(DAG)…)的顶部哈希值(Top Hash)。

不变性 (Immutability)

存储在 IPFS 的数据具有不变性,即每当数据内容被修改时,原数据对应的哈希树不变,而是对于新的数据新建新的哈希树。

官方的例子[7]或许更生动一些

   +-----------+
| Pointer |
+-----------+

+-----+
+--| C |-+
| +-----+ |
| |
+-----+ +-----+
| A | | B |
+-----+ +-----+
"hello" "world"

这是一个哈希树,叶节点存储了两个字符串 "hello""world",它们各自对应着他们的哈希值 A=Hash("hello")B=Hash("world"),而 C=Hash(A+B) 。当 "world" 发生改变时,比如变成 "IPFS",原本的这棵树不会发生修改 A, B 还有 C 都不会发生变化,而是新建了一个全新的哈希树。

  +-----------+
| Pointer | --------------+
+-----------+ |

+-----+ +-----+
+--| C |-+ +-- | E | --+
| +-----+ | | +-----+ |
| | | |
+-----+ +-----+ +-----+ +-----+
| A | | B | | A | | D |
+-----+ +-----+ +-----+ +-----+
"hello" "world" "hello" "IPFS!"

原有的 A 加入进来,与修改后的 D=Hash("IPFS") 组合成新的哈希树,它的顶部哈希值就变成了 E=Hash(A+D) 亦即其CID。原有的 C 依然存在,只要 IPFS 网络上还有 "hello world",那么 C 仍然是可以访问的。


官网也举了一个更具体的例子

<body>
<h1 id="header_1"></h1>
<h1 id="header_2"></h1>
</body>
<script>
let string_1 = 'hello'
let string_2 = 'world'
document.getElementById('header_1').textContent = string_1
document.getElementById('header_2').textContent = string_2
</script>

这个页面的 CID 是 QmWLdyFMUugMtKZs1xeJCSUKerWd9M627gxjAtp6TLrAgP

当我们将 string_2 修改成 'IPFS' ,页面的 CID 会变成 Qme1A6ofTweQ1JSfLLdkoehHhpbAAk4Z2hWjyNC7YJF9m5

+--------+      +---------+      +----------+
| User | ---> | Pointer | | QmWLd... |
+--------+ +---------+ +----------+
|
| +----------+
+ --------> | Qme1A... |
+----------+

旧的 hello world 页面仍然能够通过最开始的 CID 访问。

这样就产生了一个问题,CID 尽管能够规避一开始提出的两个问题,但是正如 ipv4 和 ipv6 地址对于人类的记忆能力来说过于困难一样,人们仍然有使用基于地址的寻址的需求。所以官方给的图例中涉及到了一个指针(Pointer)概念,并且它的具体实践也不是什么我们陌生的事物,而是互联网中最常见的域名。

IPNS(InterPlantery Naming Servcie)与 DNS 的功用几乎一样,都是将便于人们记忆的域名映射到网络系统更容易处理的标识符上。

+--------+      +----------------+      +-------------------------------------------------------------+
| User | ---> | docs.ipfs.tech | ---> | bafybeigsddxhokzs3swgx6mss5i3gm6jqzv5b45e2xybqg7dr3jmsykrku |
+--------+ +----------------+ +-------------------------------------------------------------+

内容提供者可以调整指针/域名所指向的对象,向用户提供一个稳定的访问入口,而非内容一旦更改就会变化的 CID。

这一部分我们将在下面的 IPNS 小节详细介绍。

永久化(Permanence)、持久化(Persistence)与固定(Pinning)

IPFS 的目标是力图使人类的数据永久化,但是这对于一个现实的系统来说是矛盾的,因为存储空间是有限的。所以 IPFS 选择了一个折中的方案:由用户选择那些数据是值得永久化的,通过固定(Pining)操作,使得这些数据不会被 IPFS 的垃圾回收机制清理掉,在 IPFS 上持久存在。

在 IPFS 的节点客户端(Kubo)的配置文件中,有三个参数

1
2
3
"StorageMax": "10GB",
"StorageGCWatermark": 90,
"GCPeriod": "1h"

StorageMax 用来设置 IPFS 缓存的空间大小,默认是 10 GB;StorageGCWatermark 用来设置触发垃圾回收机制的空间占用比例,默认是 90%;CGCPeriod 用来设置垃圾回收的周期,默认是 1 小时。

手动清理

ipfs repo gc

> removed QmPZhyTu8D7NqR5NvgkgNYsSYD4CNjnyuFejB8i23itJvA
> removed QmSYQFVAZgEnpa6NxiW5agyj3XU9VR4CbERShXiLhuPPPE
> removed QmS6SJXApoi59hqD8Naktgakc6UNHK1XDhqhtMg9sBhY8g

自动清理

ipfs daemon --enable-gc

> Initializing daemon...
> Kubo version: 0.9.0
> Repo version: 10
> ...
Tip

IPFS Desktop 可以通过选择 Advanced(高级) → Run Garbage Collector(运行垃圾回收器)来进行垃圾回收。

具体操作以及更多细节(3个pin类型)详情查看:Pin files using IPFS

如果不希望数据被垃圾回收掉,用户就需要在命令行或者客户端中手动“固定”(pin)文件。

垃圾回收机制会造成的结果,就像 BitTorrent 下载一样,下载的人越多下载速度越快,IPFS pin 的数量越多缓存对内容的访问速度越快,没有被 pin 的缓存就会随着垃圾回收被清理掉。

如果想用 IPFS 搭建网站的话,可以参考这位博主的文章 @zu1k

Pin 优化

在发布内容后,马上通过公开的 IPFS 网关访问,通常会很慢很慢,甚至到超时都无法访问,这是由 IPFS 的寻址过程导致的。随着访问内容的用户越来越多,他们的 IPFS 节点上会缓存你内容的数据,这个时候新节点再访问同一份内容,通常就会很快。这就是 IPFS 的特性,就跟 BT 下载的原理类似,数据在网络中存在的副本越多,就越能利用 P2P 网络的性能。

但是一个 IPFS 节点也不会无限期的缓存你的数据,默认配置下 GC 频率是 1 个小时一次,也就是说你的数据如果用户不访问,在一个小时后就会从他们的节点中被清理掉。为了能够让我们的数据长久的留在 IPFS 网络中,就需要用户 Pin 住你的数据,以防被 GC 掉。我的做法是利用闲置的服务器搭建 IPFS 节点用来 Pin 自己的数据,然后朋友之间互相 Pin 住,算是合作共赢。

所以大家不妨 Pin 一下我的博客:ipfs pin add /ipns/zu1k.com

如果你使用 IPNS 或者域名的方式对外公开经常修改的内容,就需要设置定时任务来不断 Pin 住新的数据,因为 IPFS 在 Pin 一个 IPNS 的时候,只会 Pin 当前状态对应的 CID ,后面不会自己去更新。


未完待续。。。

### DHT

这部分暂时挖个坑。DHT网络是大部分 P2P 架构的核心组件。

### Bitswap

### IPNS

### IPFS Gateway

### DNSLink


实际上国内各类云盘也使用了类似的基于内容的寻址技术以降低存储空间占用,以及便于反向封禁资源。 如果采用基于地址的寻址,那么在不便于用户检索的同时,也不便与监管机构的封禁。但是如果采用基于内容的寻址,虽然便于用户充分利用整个网络的资源,但是当监管机构封禁掉 CID 入口时,同一哈希值的内容就会在全网遭到封禁。

然而这种封禁的有效性在于网关的唯一性,如百度云只能通过官方的网页和客户端访问,对于用户来说,访问百度云内网的软件和网关是一个黑箱,没有任何控制权限。但是 IPFS 的网关是开放的,可镜像的,甚至是可自建的,可以在本地配置,所以一旦,例如官方的 ipfs.io 由于某种原因无法访问或者限制访问某些资源,其他的第三方网关如 cf-ipfs.com 或者临时搭建的网关同样可以访问整个 IPFS 网络。

不过这一点也是有争议的,即最为广泛使用的网关 ipfs.io 或者 cf-ipfs.com 依然是中心化的,尽管路由表是可以镜像的,但是依然不能阻挡少数网关越来越集中网络上大多数的使用流量的趋势。


  1. 1.History of the IPFS project
  2. 2.Napster running on an original iBook
  3. 3.Juan Benet(音译为胡安·贝内特)是 IPFS 和 Filecoin 的发明者,Protocal Labs(意译为协议实验室)的创始人和CEO,曾在斯坦福大学计算机科学专业就读。
  4. 4.星际文件系统
  5. 5.与 IPO(Inital Public Offering) 类似的 Inital Coin Offering. What are initial coin offerings?
  6. 6.ipfs/ipfs#quick-summary
  7. 7.Immutability | IPFS Docs

本站由 @anonymity 使用 Stellar 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。