文件导入和转存
JuiceFS 默认会将文件进行分块存储,并将元数据与数据剥离。正是这样的存储格式和分离架构,让 JuiceFS 得以成为高性能、强一致性文件系统。
但是在某些非常特殊的场景下,用户更需要直接在对象存储上保存原始文件,让对象存储里的文件能够脱离 JuiceFS 元数据使用,或者直接将对象存储中已有的大量文件直接导入 JuiceFS,使其可以通过 POSIX 访问,并利用上 JuiceFS 的强大缓存能力。在对象存储里保存完整文件并在 JuiceFS 中使用,我们称为「兼容格式」。而默认的文件分块存储的高性能模式,则称为「优化格式」。
从 5.0 开始,JuiceFS 极大改善了对兼容格式的支持,提供以下功能,来满足上述要求:
- 对象存储的「导入」功能,也就是
juicefs import命令。确切地说,这个命令早已支持,但从 5.0 开始,导入的文件也支持读缓存。 - 「转存」功能,将 JuiceFS 中的分块格式文件,重新组合成完整文件上传至对象存储,让用户可以直接在对象存储中访问原始文件,一样支持读缓存。
导入对象存储已有文件
juicefs import 会扫描给定的对象存储地址,然后将目标文件的元数据信息写入 JuiceFS 元数据引擎,让这些文件在 JuiceFS 中也能访问,该操作并不会实际复制任何文件,文件仍原样保存在对象存储里,因此相较于 JuiceFS 原生的分块格式,这种存储格式称为「兼容格式」,意为和对象存储保持兼容。
导入的文件,使用上要注意:
- 导入的文件同样占用文件系统空间,会计入目录配额,并且参与计费;
- 可以修改文件名、权限,但无法修改对象存储数据。换言之,不论做何种操作,对象存储上的原始对象都不会变;
- 同样地,删除这些文件也只会删除其元数据,并不会真正删除对象存储中的源文件;
- 导入进 JuiceFS 的元数据,也不支持回收站,如果在 JuiceFS 中删除导入的文件,并不会在回收站找到他们,如果需要恢复,只能再次执行导入;
- 导入的文件和 JuiceFS 自身的文件没有明显区别,如果要辨别一个文件是否属于导入文件,可以使用
juicefs info,如果在info的输出中关注object字段(而没有chunks表格),来识别兼容格式。
缓存
从 JuiceFS 5.0 开始,导入的文件同样支持本地缓存和分布式缓存。虽然导入的文件并没有真正写入 JuiceFS 文件系统、经过 JuiceFS 的分块格式化,但实际缓存到本地盘时,仍然会被拆分为数据块(大小为文件系统的 block size),因此对于导入文件的缓存的使用和管理方式,和正常写入 JuiceFS 文件系统中的文件没有任何不同。
从外部桶导入的文件,不支持缓存。因此如果希望导入的文件能享受到缓存功能,文件系统和导入源必须使用同一个对象存储桶,并且导入命令必须使用以下格式:
# URI 中不包含 bucket 参数,则支持缓存
juicefs import / /jfs/imported
juicefs import /prefix /jfs
# 如果 URI 包含了 bucket,便不支持缓存
# 在下方例子中,即使 BUCKET 正是文件系统所使用的桶,也不支持缓存
juicefs import BUCKET/prefix /jfs
使用 JuiceFS 的缓存功能加速导入文件的读取时,需要注意一致性问题:由于导入的对象本身并不受 JuiceFS 管理,如果对象发生了修改,而没有重新导入到 JuiceFS 的话,因为可能存在旧版本的缓存,不确保能读到 最新的数据。因此如果导入 JuiceFS 以后,对象发生了变更,则需要再次导入。而已有的缓存数据,会根据导入的对象的修改时间自动失效。确保能读到修改过后的数据。
因此,对于需要反复修改的对象,建议将数据整体迁移到 JuiceFS,推荐用 juicefs sync 将数据写入 JuiceFS,但归功于 JuiceFS 的 POSIX 兼容性,你也可以用任意其他工具。
观测
取决于使用方式,一个文件系统可能同时包含通过 JuiceFS 的「原生格式」写入的分块存储的文件,也可能存在直接从对象存储导入的完整文件,我们建议将这两类文件妥善管理,用不同的目录加以区分、避免混淆。如果未能恰当管理,可以使用 juicefs info 命令加以判断。
原生格式的文件是分块存储的,因此 object 字段会详细罗列每一个关联的对象存储块,他们都组织在 chunks 目录下,就像这样:
$ juicefs info a
a :
inode: 51
files: 1
dirs: 0
length: 2 Bytes
size: 4.00 KiB (4096 Bytes)
path: /a
objects:
+------------+-------------------------------+------+--------+--------+
| chunkIndex | objectName | size | offset | length |
+------------+-------------------------------+------+--------+--------+
| 0 | poc/chunks/B5/54/54450357_0_2 | 2 | 0 | 2 |
...
+------------+-------------------------------+------+--------+--------+
如果文件是从对象存储直接导入而来,object 字段不会包含表格样式的数据块列表,而是只有一个对象存储文件路径。
$ juicefs info b
b :
inode: 26
files: 1
dirs: 0
length: 36 Bytes
size: 4.00 KiB (4096 Bytes)
path: /imported/b
object: /mybucket/b
mtime: 2025-02-12 14:52:19 +0800 CST
按需导入(实验性功能)
从 5.1.3 开始,JuiceFS 实验性地支持「按需导入」,该功能在上一小节 import 的基础上,允许用户将整个对象存储桶映射为一个 JuiceFS 文件系统,并且在访问时才 list 对象存储、导入元数据。相比定期 import 的流程,按需导入的模式有以下好处:
- 不再需要定期 list,仅在访问发生时才现场解析,能够大大减轻对象存储的 list 压力;
- 只有访 问过的部分,才会在 JuiceFS 文件系统建立元数据,未访问的路径,不会进行对象存储扫描并映射到 JuiceFS 中,因此也不会参与计费。计费策略上相当于「用多少,花多少」,
- 对象存储桶的文件量太大,完整导入整个桶会带来元数据较大内存压力,可以用按需导入的方式来兼顾。
按需导入是一个实验性功能,其用法和设计都有可能面临未来调整,如果你有意进行试用和评估,请务必联系 Juicedata 工程师,和我们充分沟通,并与我们一起开展测试。
使用流程
该功能只支持从文件系统关联的桶导入文件,因此必须在创建文件系统之初,就将待导入的桶设置为文件系统的关联桶(在 JuiceFS Web 控制台的文件系统设置页面操作)。满足这个前提以后,才能在服务器上操作挂载。
下方命令中,--source=/ 的含义是将对象存储的根路径映射到文件系统的根。目前这个参数的写法是固定的,不支持设为 / 以外的值。
juicefs mount myjfs /jfs --source=/
挂载完毕以后,ls 便能看到对象存储的顶级目录:
$ cd /jfs
$ ls -alh
...
drwxrwxrwx 2 root root 4.0K Nov 11 17:35 dir1
drwxrwxrwx 2 root root 4.0K Nov 11 17:35 dir2
drwxrwxrwx 2 root root 4.0K Nov 11 17:35 dir3
注意上方目录的 777 权限,JuiceFS 将目录权限赋予了特殊含义:凡是 777 的目录,都还没被实际访问过,因此并未完成元数据导入。但只要以任何形式访问这些目录下的内容,JuiceFS 就会立刻扫描对象存储、快速建立对应的文件目录结构。建立完成以后权限会发生变化:
# 用任何方式访问 dir1 下方的文件,既可以 cd 进入,也可以直接访问特定文件
$ ls dir1/file.txt
# 目录访问过以后,权限会从 777 变为 555
$ ls -alh
...
dr-xr-xr-x 5 root root 16K Nov 11 17:47 dir1
drwxrwxrwx 2 root root 4.0K Nov 11 17:35 dir2
drwxrwxrwx 2 root root 4.0K Nov 11 17:35 dir3
因此,在按需导入的工作流中,可以依据目录权限来判断加载的情况:777 代表尚未加载,如果不是 777,则说明目录已经导入元数据。可以读取或者运行预热。**请勿自行篡改目录权限,**否则会干扰按需导入的正常工作。
写入文件(不推荐)
和上方的 import 命令类似,你无法修改从对象存储中直接导入的文件。如果导入以后删除了这些文件,也只会删除他们在 JuiceFS 中的元数据索引,并不会对桶中数据产生任何影响。
不过事实上,一个按需导入的文件系统,仍然可以像正常的 JuiceFS 文件系统一样写入新文件,写入的文件并不是以完整文件格式直接上传对象存储,而是用 JuiceFS 标准的分块格式写入到对象存储桶的 /[volume-name]/chunks/ 目录下。因此如果确实进行了写入,对象存储桶里将会存在两种形式的数据:用于导入 JuiceFS 的完整文件,以及通过 JuiceFS 写入的分块格式数据块。
我们目前不推荐在按需导入的文件系统中写入文件,这不仅会增加管理复杂度,需要辨别哪些文件是导入的、不支持修改,哪些文件是通过原生的分块格式写入,还会有数据丢失的风险:待元数据过期,下次扫描、重建元数据的时候,将会删除多余的文件和目录,引发数据丢失。