Seafile 存储模型探索

1. Seafile 介绍

Seafile 是国内开源的网盘产品,目前有社区版和专业版。因为目前也在做网盘类产品的研发,所以对 Seafile 的部分源码进行了研究。

2.Seafile Git 模型

Seafile 采用了类似 Git 的模型来存储文件,主要有下面几个概念。

Repo: 资料库,可以理解为一个存储盘。每创建一个资料库,都会在 Repo 表插入一条记录。

Branch: 类似 Git 里的分支,每个 Repo 都默认有一条 master 分支。

Commit: 类似 Git 里的提交记录,每次上传、修改文件都会产生一条新的 commit,通过上图可见,master 分支指向了最新的一条 commit。

3. Seafile 文件存储模型

3.1 Seafile 存储结构

Seafile 没有采用 MySQL 存储 commit 和 file 相关的元数据,而是直接将这些元数据以 JSON 文本的方式,存储到了文件系统里。打开 Seafile 存储目录,可以看见有三个主文件夹:blocks、commits 和 fs。

blocks: 文件的真实数据,采用了 CDC 算法进行分块存储。

commits: 存储了 repo 的 commit 记录。每条 commit 记录对应一个文件,文件内容为 commit 数据结构的 json 字符串。

fs: 存储了 repo 中的目录层级信息及文件信息。所有的目录层级在 fs 目录下都是打平的,文件之间的层级关系表达在 fs 下的文件内容中。

3.2 Seafile 存储内容分析

(1)commit 记录

repo 下的每次变动,都会生成一次新的 commit,并写到 commits 文件夹下。

我们打开 commits 目录,以 repo(08455862-8513-4dcf-93ca-93db751881ba)为例,可以看见该 repo 下有四个文件,文件路径即为 commit id。

该 repo 当前最新的 commit id为 3b9518cbb12e55477f89c64a887a3c60e42e5093,我们根据 id 可以定位到文件 3b/9518cbb12e55477f89c64a887a3c60e42e5093 ,直接打开可以查看到其中的内容,是个 json 文本,内容如下:

{
"commit_id":"3b9518cbb12e55477f89c64a887a3c60e42e5093",
"root_id":"3cd9159af2cb49e0864e8e05f58919d32dd98119",
"repo_id":"08455862-8513-4dcf-93ca-93db751881ba",
"creator_name":"me@example.com",
"creator":"0000000000000000000000000000000000000000",
"description":"Added "[MS-PAC].pdf".",
"ctime":1608985761,
"parent_id":"2a8d9636f7a589da18b340b9d010d2dd563b6203",
"second_parent_id":null,
"repo_name":"test",
"repo_desc":"",
"repo_category":null,
"no_local_history":1,
"version":1
}

这里记录了本次 commit 的相关信息,其中部分字段含义如下:

parent_id: 这里的 parent_id 为 2a8d9636f7a589da18b340b9d010d2dd563b6203,它其实就是上一次 commit 的 id,我们同样可以根据该 commit id,定位到文件2a/8d9636f7a589da18b340b9d010d2dd563b6203,并查看其中的内容,它的 parent_id 为 8a4cb2ea24b35ed3094c410ee6af636a93b54e3a,也就是再上一次的 commit id。

这样通过 branch 的 head commit 和其中每条 commit 记录的 parent_id,我们就可以将 branch 下的所有提交记录按顺序串起来。

root_id: 在本次 commit 时,repo 的根目录 id,可以在 fs 目录下找到该 id 对应的 json 文本。

(2)fs 记录

fs 文件夹下存储的是每次 commit 的快照记录。拿最新的 commit 3b9518cbb12e55477f89c64a887a3c60e42e5093 来说,根据上次 3b/9518cbb12e55477f89c64a887a3c60e42e5093 中记录的 root_id:3cd9159af2cb49e0864e8e05f58919d32dd98119,我们可以在 fs 目录下定位到 3c/d9159af2cb49e0864e8e05f58919d32dd98119 文件,该文件通过 zlib 编码了,解码后的内容也是一个 json 文本:

{
"dirents":[
{
"id":"5b787cc5a7a64836fe3a00707db71005dd4652f7",
"mode":16384,
"mtime":1608985761,
"name":"A"
}
],
"type":3,
"version":1
}

这里记录了根目录下的文件信息,表示根目录下只有一个文件为 A,且 mode 是 16384,转成 8 进制也就是 0040000,表示文件夹。

A 文件夹的 id 为 5b787cc5a7a64836fe3a00707db71005dd4652f7,根据这个 id ,同样可以在 fs 目录下找到 A 目录的元数据描述文件 5b/787cc5a7a64836fe3a00707db71005dd4652f7,查看其中的内容为:

{
"dirents":[
{
"id":"b14c54950f33f99bf1face498445e886d536d07d",
"mode":33188,
"modifier":"me@example.com",
"mtime":1608985761,
"name":"[MS-PAC].pdf",
"size":1908956
},
{
"id":"44ede347ece2990da2cda35a5dbcb765d4e51cae",
"mode":33188,
"modifier":"me@example.com",
"mtime":1608985735,
"name":"38b57137ee7c64038f658a6485ac8ea7.jpeg",
"size":150713
}
],
"type":3,
"version":1
}

这里表示 A 目录下有两个文件,分别为 [MS-PAC].pdf 和 38b57137ee7c64038f658a6485ac8ea7.jpeg,这两个文件的 mode 都是 33188,表示他们是真实文件,而不是文件夹。

以 [MS-PAC].pdf 为例,它的大小是 1908956,id 是 b14c54950f33f99bf1face498445e886d536d07d,根据 id 在 fs 目录下再次定位到 b1/4c54950f33f99bf1face498445e886d536d07d 文件,查看其内容:

{
"block_ids":[
"d32f5687a0c2591e591abf40dbea06fbc0d2d422"
],
"size":1908956,
"type":1,
"version":1
}

这里记录的是文件 [MS-PAC].pdf 所有数据块的 id,对应到 blocks 目录下的文件。可以看见 [MS-PAC].pdf 只有一个数据块,id 为 d32f5687a0c2591e591abf40dbea06fbc0d2d422。

我们再来看看 seafile 资料库,可以看见和上面的分析一致。

(3)blocks 记录

blocks 目录下记录了文件的数据块,比如上面的 [MS-PAC].pdf,它的 block_ids 为[“d32f5687a0c2591e591abf40dbea06fbc0d2d422”],也就是只有一个 id 为 d32f5687a0c2591e591abf40dbea06fbc0d2d422 的数据块,我们在 blocks 目录下定位到 d3/2f5687a0c2591e591abf40dbea06fbc0d2d422 文件,它的大小刚好是 1.9 MB,也就是 [MS-PAC].pdf 的原始文件。

4.总结

通过上面对 Seafile 的存储结构分析,可以看出 Seafile 是通过 commits 、fs 和 blocks,将整个文件系统串起来了,并且每次修改,都会生成一个新的 commit,并将当前 commit 的 repo 快照,存储到了commits 、fs 和 blocks下。这样的好处是可以根据 commit id,快速回滚整个 repo 到某一个版本,而且 Seafile 基于 git 的模型设计,也天然的支持了多端同步的特性。但是凡事都有利有弊,这样设计带来的影响就是,在每次修改单个文件时,Seafile 都会将整颗文件树的信息存储下来,造成写放大,如果树很大的情况下,就不得不考虑写放大的性能损耗了。

半栈工程师
我还没有学会写个人说明!
上一篇

RL 101 - Tic Tac Toe(井字棋游戏)

下一篇

“秃”然崛起的脱发经济,靠什么撑起了千亿市场?

你也可能喜欢

评论已经被关闭。

插入图片