引言

以前归档文件,我使用文件夹对文件分类,当一切都组织好之后,使用 sha256 对整个目录中每个文件做运算,存储在根目录下,并且在每次传输后(网络或拷贝)校验文件完整性。整个目录被存储在我的两块移动硬盘和 OneDrive 上。

之前,我的归档文件较小,只有 100 GiB 左右,但在三个月后的今天,它来到了 400 GiB。每一次校验文件完整性逐渐成为了负担,最糟糕的是,有的文件校验过不去了,这时我必须从另一块移动硬盘上,或者从 OneDrive 寻找没有出错的文件。另一方面,当我把一些文件送入归档时,我并不知道它是否曾经已经归档过了,如果它曾经归档过,我很可能需要改变那个文件的命名方式(因为如果我不知道那个文件是否存在,那大概说明它被存放在未分类的部分)。但目前组织文件的方式,在我将新文件放入归档时,既很难做到去重,存放进去后,又需要大量的时候计算 sha256 值。

这足以说明我需要一种新的方式组织归档的文件了。

组织文件的方式

使用对象存储 + hash 值

想要做到文件去重,最简单的方法,就是使用对象存储。文件名使用文件的 sha256 值,这样,当我们添加文件前,查询该文件的 hash 值,就能立刻知道该文件是否存在。

但这么做的一个显著的缺点就是,你将会丢失文件的目录结构,寻找文件将会变得几乎不可能。

KV 数据库保留目录信息

其中一个权宜之计就是使用 KV 数据库,key 为文件路径 + 文件名,value 为文件 hash 值。这样每个文件你知道文件名就可以找到它了。但你还需要类似列出某个目录下的文件的功能,这也很简单,回头看一下文件系统,将文件夹也视为一个文件,内容为它包含的文件的文件名即可。

该系统的缺点

这个系统几乎满足了我们添加文件时的全部需求,但该系统删除文件的代价极大。因为你无法根据 value 查询 key,因此当你删除文件时,你其实没法知道是否有其他目录下某个文件指向这个 hash,最终你只能在 KV 数据库里逻辑删除该文件。

在另一只手,这其实是可以接受的,因为我的归档文件数十分有限,只有不到 30000 文件 + 文件夹数。我们从根目录开始,遍历所有的文件,就可以找到存在 KV 数据库中,但不存在对象存储中的文件。而我 4 TiB 的硬盘,相对于 400 GiB 的数据,还可以存储相当大量的无用文件,而在缺少存储空间前,我们其实没有必要急着删掉逻辑删除的文件。更何况,这个系统中的文件,都是归档文件了,我也肯定也不会删嘛,新增和移动才是主要的操作。

终极文件系统

在我修建博客前,我构想过一个最终文件归档系统,它可以拥有几乎无限的文件数,文件体积和存储器数,它被设计成分布式的,操作存储器的 worker 都是无状态的,并且支持使用 tag 标记文件。但它实在是太复杂了,而且没有基金会/科技公司给我钱去做这件事。

前一段时间,我阅读了一篇文章,里面有这样的段落:

只是有一天当我又打算做一个新项目时,我突然问起自己:我真的会先做好完善的用例分析、决定系统功能模块、给每个功能决定需要用哪些类关系实现,最后再对着定好的框架一行行写代码吗?

而且到头来,我们发现 “优雅的架构” 没有解决什么本质的问题——谷歌、微软的架构师搞了这么多年,最后代码还是堆成了屎山。保证软件鲁棒性的其实是测试,成堆成吨的测试,而不是一开始优雅的架构——随着软件规模增长,任何一开始优雅的架构都会渐渐变成垃圾的架构,而且你这个架构最开始做得越复杂,你后边改起来反而越束手束脚。而如果你一开始就按当前全世界最复杂的软件作为应用场景去设计架构,以期望之后这个软件能变得足够“Scalable”,你只会得到一个一开始连代码都写不顺手的破烂东西,新来的程序员看了三天文档就告诉你这么复杂的东西根本没法干,老员工也被这傻逼东西给逼走了,觉得你简直是异想天开。

他说的对,这样只会得到一个一开始连代码都写不顺手的破烂东西,因此,我最终决定在这里简单提一下这个想法,表示它曾存在过。而这篇文章中的系统,很可能就会在不久的将来就被我用来解决文件的归档问题。


我开始写这篇博客前,就已经等了半个小时的拷贝进度条了,现在文章写完了,它还在拷贝。这也进一步说明了这个归档系统对我有多重要。