目录
- 1 什么是IPFS
- 2 为什么有IPFS
- 3 IPFS的目标
- 4 IPFS包含哪些内容
- 5 IPFS与Filecoin
- 6 IPFS开发入门
- 6.1 部署私有IPFS
- 6.1.1 环境准备
- 6.1.2 配置 golang 环境
- 6.1.3 IPFS部署
- 6.1.4 生成共享key
- 6.1.5 添加网络节点
- 6.1.6 启动IPFS
- 6.1.7 测试文本传输
- 6.2 架构说明
- 6.2.1 IPFS 总体架构图
- 6.2.2 CLI、HTTP-API架构图
- 6.3 Spingboot使用IPFS上传、下载文件
- 6.4 相关开源代码
- 7 遗憾
1 什么是IPFS
IPFS的全称是星际文件系统(InterPlanetary File System),它是一个点对点的分布式文件系统,通过底层协议用户可以在这个网络里上传文件并下载文件。它将区块链技术与互联网进行了完美的融合,可以让我们的互联网速度更快, 更加安全, 并且更加开放。 IPFS协议的目标是取代传统的互联网协议HTTP。
IPFS与云存储的区别
IPFS看上去可能和云储存有点相似,都是分布式存储。但是二者内在逻辑完全不同。云储存通常是由云服务厂商提供,存储提供方与使用方是一对多的模式。IPFS则是点对点,存储做到了去中心化,存储提供方与使用方是多对多的模式,并且由于数据是加密存储,因此数据也不会被云服务厂商盗用。
2 为什么有IPFS
互联网是建立在HTTP协议上的,但发展到了今天HTTP逐渐显示出不足。
HTTP的中心化是低效的, 并且成本很高
使用HTTP协议每次需要从中心化的服务器下载完整的文件(网页, 视频, 图片等), 速度慢,效率低。 如果改用P2P的方式下载,可以节省近60%的带宽。P2P将文件分割为小的块, 从多个服务器同时下载, 速度非常快。
Web文件经常被删除
http的页面平均生存周期大约只有100天。Web文件经常被删除(由于存储成本太高), 无法永久保存。IPFS提供了文件的历史版本回溯功能(就像git版本控制工具一样), 可以很容易的查看文件的历史版本, 数据可以得到永久保存。
中心化限制了web的成长
互联网是一个高度中心化的网络,DDOS等黑客攻击对互联网的功能造成了严重威胁, 分布式的IPFS可以克服这些缺点。
互联网应用高度依赖主干网
IPFS将内容分发到边缘端,可以极大地降低互联网应用对主干网的依赖。
3 IPFS的目标
IPFS不仅仅是为了加速web,而是为了最终取代HTTP协议, 使互联网更加美好。
4 IPFS包含哪些内容
IPFS是一个协议,类似http协议
- 定义了基于内容的寻址文件系统
- 内容分发
- 使用的技术分布式哈希、p2p传输、版本管理系统
IPFS是一个文件系统
- 有文件夹和文件
- 可挂载文件系统
IPFS是一个web协议
- 可以像http那样查看互联网页面
- 未来浏览器可以直接支持 ipfs:/ 或者 fs:/ 协议
IPFS是模块化的协议
- 连接层:通过其他任何网络协议连接
- 路由层:寻找定位文件所在位置
- 数据块交换:采用BitTorrent技术
IPFS是一个p2p系统
- 世界范围内的p2p文件传输网络
- 分布式网络结构
- 没有单点失效问题
IPFS天生是一个CDN
- 文件添加到IPFS网络,将会在全世界进行CDN加速
- bittorrent的带宽管理
IPFS拥有命名服务
- IPNS:基于SFS(自认证系统)命名体系
- 可以和现有域名系统绑定
5 IPFS与Filecoin
行业内很多人将IPFS等同于Filecoin,实际上两者有严格区分,PFS是非区块链项目,Filecoin是区块链项目,二者都可以独立存在。
为激励云服务厂商、IDC资源提供商以及其他投资者提供高性能、高稳定的服务器加入到IPFS网络中,Filecoin作为激励代币而诞生。资源提供方(矿工)通过为客户提供数据存储和检索来获得原生代币,存储方(客户)需要支付Filecoin作为存储、分发和检索数据费用。
Filecoin不是无限量发行的,发行总量20亿,其中70%即14亿枚用于奖励贡献者,每6年减半。
6 IPFS开发入门
6.1 部署私有IPFS
6.1.1 环境准备
系统要求
至少需要2G内存,2 核 CPU。
实验环境
共计两个节点,192.168.159.102、192.168.159.103,系统采用centos7
环境准备后,按照如下步骤部署ipfs,每个节点都要部署。
6.1.2 配置 golang 环境
下载go
$ cd /home
$ wget https://golang.google.cn/dl/go1.17.1.linux-amd64.tar.gz
$ tar -zxvf go1.17.1.linux-amd64.tar.gz -C /usr/local
配置 golang 环境变量
$ vim /etc/profile
文件末尾追加
# golang env
export GOROOT=/usr/local/go
export GOPATH=/data/gopath
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
$ source /etc/profile
# 创建工作目录:
$ mkdir -p /data/gopath && cd /data/gopath
$ mkdir -p src pkg bin
6.1.3 IPFS部署
所有节点上都需要部署ipfs:
1、安装
# 下载
$ cd /home
$ wget https://download.fastgit.org/ipfs/go-ipfs/releases/download/v0.9.1/go-ipfs_v0.9.1_linux-amd64.tar.gz
# 解压缩
$ tar xvfz go-ipfs_v0.9.1_linux-amd64.tar.gz
# 安装
$ cd go-ipfs/
$ ./install.sh
2、指定IPFS的存储位置
$ export IPFS_PATH="/opt/ipfs"
3、初始化
$ ipfs init
该操作执行后,默认会在/root/目录下生成一个隐藏目录.ipfs
,作为ipfs的local存储。可用ls -a
查看。如果输出以下代码则表示初始化成功了:
generating ED25519 keypair...done
peer identity: 12D3KooWPVtCiwDTbf8L8B5pV5PWpW1C4yfzAZaqZpjz3pyzMEig
initializing IPFS node at /opt/ipfs
to get started, enter:
ipfs cat /ipfs/QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc/readme
6.1.4 生成共享key
1、生成Key
选择任意一个节点执行以下操作:
1)下载key生成工具
$ git clone https://hub.fastgit.org/Kubuxu/go-ipfs-swarm-key-gen.git
2)编译go-ipfs-swarm-key-gen
$ go build -o ipfs-swarm-key-gen go-ipfs-swarm-key-gen/ipfs-swarm-key-gen/main.go
3)此时在当前目录下会成一个ipfs-swarm-key-gen的可执行二进制文件。我们使用该文件来生成一个swarm.key文件
$ ./ipfs-swarm-key-gen > swarm.key
2、将生成的swarm.key文件传输到所有节点的 ~/.ipfs/
文件夹内。
102上:
$ cp swarm.key ~/.ipfs/
103上:
$ scp root@192.168.159.102:~/.ipfs/swarm.key ~/.ipfs
6.1.5 添加网络节点
所有节点上都移除默认的IPFS节点(此为私有化的关键步骤):
$ ipfs bootstrap rm all
查看节点ID:
$ ipfs id
系统会输出以下内容,记住ID部分:
# 102
{
"ID": "12D3KooWP4avEe4hX3XVsbaWMHHuTZcXP5A5kCUf91BhRd9yy1Zb",
"PublicKey": "CAESIMTMekjuLE276A/3lr++zJqDGzkOYDqJulm6+VyEqVGi",
"Addresses": null,
"AgentVersion": "go-ipfs/0.9.1/",
"ProtocolVersion": "ipfs/0.1.0",
"Protocols": null
}
# 103
{
"ID": "12D3KooWDQL6EigoCsx6EjM4mSpz7Vqq9RHCZzPoshVFS8bdxrXh",
"PublicKey": "CAESIDVGdYIAdJfI6eZ6mAbrJo8RNn4baXsR4Wb1GZsc6Ocw",
"Addresses": null,
"AgentVersion": "go-ipfs/0.9.1/",
"ProtocolVersion": "ipfs/0.1.0",
"Protocols": null
}
在102服务器上添加103:
$ ipfs bootstrap add /ip4/192.168.159.103/tcp/4001/ipfs/12D3KooWDQL6EigoCsx6EjM4mSpz7Vqq9RHCZzPoshVFS8bdxrXh
在103服务器上添加102:
$ ipfs bootstrap add /ip4/192.168.159.102/tcp/4001/ipfs/12D3KooWP4avEe4hX3XVsbaWMHHuTZcXP5A5kCUf91BhRd9yy1Zb
6.1.6 启动IPFS
所有的节点都添加完毕后使用命令启动IPFS,显示如下输出说明启动成功,配置文件没有问题。
$ nohup ipfs daemon > ipfs.log 2>&1 &
......
API server listening on /ip4/127.0.0.1/tcp/5001
WebUI: http://127.0.0.1:5001/webui
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready
IPFS Daemon启动过程包含8个步骤:
- 检查是否已经初始化
- 打开初始化根目录 /.ipfs
- 读取配置
- 根据配置生成一个新节点
- 连接到IPFS网络
- 开启IPFS API服务
- 开启Gateway网关服务
- 输出IPFS Daemon ready
网络启动后,可以测试网络的连通性,使用如下命令查看IPFS连接了多少节点:
$ ipfs stats bitswap
bitswap status
provides buffer: 0 / 256
blocks received: 0
blocks sent: 0
data received: 0
data sent: 0
dup blocks received: 0
dup data received: 0
wantlist [0 keys]
partners [1]
其中partners
就是连接到的节点数量,因为我们现在只有两个节点,所以partners
是1
。
6.1.7 测试文本传输
在102新建一个文本文件:
$ echo "hello world" >> test.txt
将其添加到ipfs网络:
$ ipfs add test.txt
输出以下字符就说明文件已经上传上去了:
added QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o test.txt
12 B / 12 B [==================================================================================================================] 100.00%
查看文件:
$ ipfs cat QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o
在子节点重复上面的操作,输出都是hello world
说明私有网络已经联通。
6.2 架构说明
6.2.1 IPFS 总体架构图
6.2.2 CLI、HTTP-API架构图
6.3 Spingboot使用IPFS上传、下载文件
1、pom文件引入相应的jar包
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.ipfs</groupId>
<artifactId>java-ipfs-http-client</artifactId>
<version>v1.3.3</version>
</dependency>
</dependencies>
2、读取文件
/**
* @param id
* 文件的hash值
* @return 文件内容
* */
@RequestMapping("/{id}")
public String getFileContent(@PathVariable String id) {
String content = null;
// 连接任一节点(本例中连的不是文件上传的节点)
IPFS ipfs = new IPFS("/ip4/192.168.159.103/tcp/5001");
Multihash filePointer = Multihash.fromBase58(id);
try {
// 获取文件内容
byte[] fileContents = ipfs.cat(filePointer);
content = new String(fileContents);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return content;
}
验证:(读取部署时上传验证的文件)
3、上传文件
/**
* @param fileName
* 文件名
* @param content
* 文件内容
* @return 文件的hash值
* */
@PostMapping("/upload")
public String uploadFile(@RequestParam("fileName") String fileName,
@RequestParam("content") String content) {
String hash = null;
try {
// 连接
IPFS ipfs = new IPFS("/ip4/192.168.159.102/tcp/5001");
NamedStreamable.ByteArrayWrapper file = new NamedStreamable.ByteArrayWrapper(
fileName, content.getBytes());
MerkleNode addResult = ipfs.add(file).get(0);
hash = addResult.hash.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return hash;
}
验证:
服务器上查看:
6.4 相关开源代码
组件 | 代码 | 开发语言 |
---|---|---|
IPFS项目 | https://hub.fastgit.org/ipfs/ipfs | |
IPFS Go版本 | https://hub.fastgit.org/go-ipfs | go |
IPFS 前端 | https://hub.fastgit.org/ipfs/ipfs-webui | js |
IPFS API | https://hub.fastgit.org/ipfs/go-ipfs-api | go |
客户端 | https://hub.fastgit.org/ipfs/ipfs-desktop | js |
PS:hub.fastgit.org 为github.com 的加速域名
7 遗憾
本文未说明私有IPFS如何支持客户端浏览器访问节点的webui