IPFS共享更新文件的效率

Efficiency of IPFS for sharing updated file

2019 年 10 月 30 日更新:

=> 请参阅以下有关 IPFS 功能请求的讨论:git-diff feature: Improve efficiency of IPFS for sharing updated file. Decrease file/block duplication

=> 请参阅以下讨论以获取更多信息。 Does IPFS provide block-level file copying feature?


例如 userA 添加了一个大小为 1 GB 的文件。 IPFS add file.txtuserB 通过 IPFS 将该文件放入他的存储中。后来 userA 发布了一个错误,只更改了文件上的一个字符,想与 userB 分享这个更新版本。

所以 userA 再次通过 ipfs add file 添加了相同的文件并做了一个小改动到 IPFS 中,并且 userB 必须获取该文件1 GB 的文件而不是更新那个单个字符。有没有更好的方法来解决这个问题,userB 应该只拉更新版本,就像我们 git pull 时 git 的工作方式一样?

Git 有更好的方法请看(). Does IPFS uses delta compression for storage (https://gist.github.com/matthewmccullough/2695758) 比如Git?或类似的方法?

进一步调查:

我做了一个小实验。 首先我在 IPFS 中添加了 1GB 的文件。后来,我更新了文件中的一小行,该文件已通过 IPFS 共享。我观察到 userA 再次推送完整的 1GB 文件,而不是只推送包含更改数据的块。在我看来,这是非常昂贵和耗时的。我已经共享了新更新文件的哈希值,并且通过 IPFS 在 userB 上再次下载完整文件,而不是只下载包含更改字符的块。

用户A

$ fallocate -l 1G gentoo_root.img
$ ipfs add gentoo_root.img
 920.75 MB / 1024.00 MB [========================================>----]  89. 92added QmdiETTY5fiwTkJeERbWAbPKtzcyjzMEJTJJosrqo2qKNm gentoo_root.img

用户B

$ ipfs get QmdiETTY5fiwTkJeERbWAbPKtzcyjzMEJTJJosrqo2qKNm
Saving file(s) to QmdiETTY5fiwTkJeERbWAbPKtzcyjzMEJTJJosrqo2qKNm
 1.00 GB / 1.00 GB [==================================] 100.00% 49s

用户A

$ echo 'hello' >> gentoo_root.img
$  ipfs add gentoo_root.img   # HERE node pushing 1 GB file into IPFS again. It took 1 hour for me to push it, instead only updated the changed block.
32.75 MB / 1.00 GB [=>---------------------------------------]   3.20% 1h3m34s
added Qmew8yVjNzs2r54Ti6R64W9psxYFd16X3yNY28gZS4YeM3 gentoo_root.img

用户B

# HERE complete 1 GB file is downloaded all over again.
ipfs get Qmew8yVjNzs2r54Ti6R64W9psxYFd16X3yNY28gZS4YeM3
[sudo] password for alper:
Saving file(s) to Qmew8yVjNzs2r54Ti6R64W9psxYFd16X3yNY28gZS4YeM3
 1.00 GB / 1.00 GB [=========================] 100.00% 45s

[Q] 此时通过 IPFS 共享更新文件而不重新共享更新文件的整个版本以及 IPFS 仅共享的最佳解决方案是什么文件的更新块?


除此之外;每当我做 ipfs cat <hash> 时,在同一个节点上它会再次下载相同的哈希值。

$ ipfs cat Qmew8yVjNzs2r54Ti6R64W9psxYFd16X3yNY28gZS4YeM3
 212.46 MB / 1.00 GB [===========>---------------------------------------------]  20.75% 1m48s

$ ipfs cat Qmew8yVjNzs2r54Ti6R64W9psxYFd16X3yNY28gZS4YeM3
 212.46 MB / 1.00 GB [===========>---------------------------------------------]  20.75% 1m48s

分析:

两者(更新后的文件和原始文件)的回购大小增加相同:

首先我创建了 100 MB 的文件 (file.txt)

NumObjects: 5303
RepoSize:   181351841
StorageMax: 10000000000
RepoPath:   /home/alper/.ipfs
Version:    fs-repo@6

   $ ipfs add file.txt
   added QmZ33LSByGsKQS8YRW4yKjXLUam2cPP2V2g4PVPVwymY16 file.txt
   $ ipfs pin add QmZ33LSByGsKQS8YRW4yKjXLUam2cPP2V2g4PVPVwymY16

此处对象数量增加了 4。更改了存储库大小 (37983)

$ ipfs repo stat
NumObjects: 5307
RepoSize:   181389824
StorageMax: 10000000000
RepoPath:   /home/alper/.ipfs
Version:    fs-repo@6

比我echo 'a' >> file.txt然后ipfs add file.txt

在这里我观察到对象的数量增加了 4 个,所以它添加了完整的文件,改变了 repo 大小 (38823)

$ ipfs repo stat
NumObjects: 5311
RepoSize:   181428647
StorageMax: 10000000000
RepoPath:   /home/alper/.ipfs
Version:    fs-repo@6

IPFS 目前并不支持您所描述的场景,因为这些文件是通过其内容的哈希索引的。由于文件被分解成块的方式,在某些情况下这会起作用 "accidentally"。如果更改发生在文件末尾,则文件开头可能具有与传输的 "blocks" 相同的哈希值。

可以分析当前存储的数据,看看您是否已经有了可以用于该块的东西(这是与 rsync 实现此目的的类似方法,尽管它使用设计的校验和算法对于那个过程)

IPFS 中的文件是按内容寻址且不可变的,它们可能会复杂到 edit.But 有 MFS(可变文件系统)可用于处理文件,就像处理普通的基于名称的文件系统一样 —您可以添加、删除、移动和编辑 MFS 文件,并为您完成更新链接和哈希的所有工作。

IPFS 支持 rabin 分块,这是一种将大文件分成块的神奇方法,其中块边界出现在任何相同数据序列的相同位置,而不管该数据的对齐方式如何。这意味着块大小是可变的,在大文件的开头添加一个字节通常会导致第一个块大一个字节,而所有其他块都相同。

所以 rabin 分块将导致 IPFS 有效地重用大文件中的块,只需要很小的更改。

但是,您还应该知道压缩之类的东西通常意味着输入文件中的单个字节更改会导致压缩输出文件中几乎每个字节都发生更改。这意味着压缩文件中的小改动通常不会有任何可重用块,无论您如何分块。

这就是rsync无法正常有效更新*.gz文件的原因。然而 gzip 有一个 --rsyncable 选项,它会牺牲少量压缩以最小化压缩输出的变化。有趣的是,它使用了与 rabin 分块非常相似的东西,但我认为它早于 rabin。对使用 rabin 分块添加到 IPFS 的压缩文件使用 gzip --rsyncable 将导致与其他类似 compressed/added 但略有不同的文件共享块。