JuiceFS 是一款面向云原生设计的高性能分布式文件系统,在 Apache 2.0 开源协议下发布。提供完备的 POSIX 兼容性,可将几乎所有对象存储接入本地作为海量本地磁盘使用,亦

JuiceFS 是一款面向云原生设计的高性能分布式文件系统,在 Apache 2.0 开源协议下发布。提供完备的 POSIX 兼容性,可将几乎所有对象存储接入本地作为海量本地磁盘使用,亦可同时在跨平台、跨地区的不同主机上挂载读写。

使用 JunicsFS 将云厂商的 S3 对象存储挂载到本地,就得到一个几乎无限容量的 VPS 空间了。目前 Juice 支持大部份主流厂商提供的 s3 服务,具体请查阅官方文档。

本文以 腾讯云 COS + 腾讯云轻量服务器,演示一下基本使用。

挂载 COS 到本地

使用以下命令即可创建一个基于 COS 的文件系统,下面演示基于 sqlite 和 redis 的创建、挂载、卸载命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Jfs With Redis
juicefs format \
--storage cos \
--bucket jfs-redis-******** \
--access-key ******** \
--secret-key ******** \
"redis://127.0.0.1:6379/1" \
jfs-redis
# 挂载
juicefs mount -d "redis://127.0.0.1:6379/1" /mnt/jfs-redis/
# 卸载
juicefs umount /mnt/jfs-redis/

# Jfs With sqlite
juicefs format \
--storage cos \
--bucket jfs-******** \
--access-key ******** \
--secret-key ******** \
"sqlite3:///opt/jfs/jfs.db" \
jfs
# 挂载
juicefs mount -d "sqlite3:///opt/jfs/jfs.db" /mnt/jfs/
# 卸载
juicefs umount /mnt/jfs/

自动挂载

具体使用时,可以配置一下自动挂载,方法如下。

首先创建一个从 /sbin/mount.juicefsjuicefs 可执行文件的软链接,操作系统解析 fstab 时会调用 /sbin/mount.juicefs 命令。

1
2
3
$ which juicefs
/usr/local/bin/juicefs
$ ln -s /usr/local/bin/juicefs /sbin/mount.juicefs

新增以下内容到 /etc/fstab 使得开机自动挂载,这里以上文 sqlite 为例:

1
sqlite3:///opt/jfs/jfs.db    /mnt/jfs       juicefs     _netdev,max-uploads=50,writeback,cache-size=204800     0  0

使用 mount -a 使配置生效

限制容量和文件数

没有限制的行为可想而知,JuicsFS 的默认限制较高,可以手动限制一下文件系统的容量和文件数量。

1
2
3
4
# 限制文件系统容量 (GiB)
$ juicefs config "sqlite3:///opt/jfs/jfs.db" --capacity 102400
# 限制文件数量 (inode 数)
$ juicefs config "sqlite3:///opt/jfs/jfs.db" --inodes 100000

限制容量举例,可以看到设定前后可以看到挂载点容量的变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 示例
$ df -h | grep jfs
Filesystem Size Used Avail Use% Mounted on
JuiceFS:jfs 1.0P 8.0K 1.0P 1% /mnt/jfs

# 设定容量上限为 128 GiB
$ juicefs config "sqlite3:///opt/jfs/jfs.db" --capacity 128
2022/11/20 21:07:08.832094 juicefs[2253158] <INFO>: Meta address: sqlite3:///opt/jfs/jfs.db [interface.go:402]
capacity: 0 GiB -> 128 GiB

# 再次查看发现大小为 128GiB
$ df -h | grep jfs
JuiceFS:jfs 128G 8.0K 128G 1% /mnt/jfs

限制文件 inodes 数量举例,可以看到设定前后可以看到挂载点容量的变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 示例
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/vda2 3901440 367127 3534313 10% /
JuiceFS:jfs 10485762 2 10485760 1% /mnt/jfs

$ juicefs config "sqlite3:///opt/jfs/jfs.db" --inodes 3901440
2022/11/20 21:13:30.977616 juicefs[2255902] <INFO>: Meta address: sqlite3:///opt/jfs/jfs.db [interface.go:402]
inodes: 0 -> 3901440
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/vda2 3901440 367128 3534312 10% /
JuiceFS:jfs 3901440 2 3901438 1% /mnt/jfs

性能测试

文件系统怎么能没有性能测试呢,下面分别使用 dd 和自带 bench 演示性能。

dd 简单读写测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 本地文件系统 io 性能
$ sync; dd if=/dev/zero of=/tmp/tempfile-12138 bs=1M count=1024; sync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.563 s, 193 MB/s

# JuicfFS sqlite 元数据驱动性能
$ sync; dd if=/dev/zero of=/mnt/jfs/tmpfile bs=1M count=1024; sync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 6.97672 s, 154 MB/s

# JuicfFS redis 元数据驱动性能
$ sync; dd if=/dev/zero of=/mnt/jfs-redis/tmpfile-12138 bs=1M count=1024; sync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.59675 s, 192 MB/s

juicefs bench 测试

本地文件系统成绩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# juicefs bench -p 4 /tmp/
Write big blocks count: 4096 / 4096 [==============================================================] done
Read big blocks count: 4096 / 4096 [==============================================================] done
Write small blocks count: 400 / 400 [==============================================================] done
Read small blocks count: 400 / 400 [==============================================================] done
Stat small files count: 400 / 400 [==============================================================] done
Benchmark finished!
BlockSize: 1 MiB, BigFileSize: 1024 MiB, SmallFileSize: 128 KiB, SmallFileCount: 100, NumThreads: 4
+------------------+------------------+--------------+
| ITEM | VALUE | COST |
+------------------+------------------+--------------+
| Write big file | 153.98 MiB/s | 26.60 s/file |
| Read big file | 148.60 MiB/s | 27.56 s/file |
| Write small file | 2064.9 files/s | 1.94 ms/file |
| Read small file | 3150.8 files/s | 1.27 ms/file |
| Stat file | 111847.4 files/s | 0.04 ms/file |
+------------------+------------------+--------------+

juicefs + sqlite 成绩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ juicefs bench -p 4 /mnt/jfs
Write big blocks count: 4096 / 4096 [==============================================================] done
Read big blocks count: 4096 / 4096 [==============================================================] done
Write small blocks count: 400 / 400 [==============================================================] done
Read small blocks count: 400 / 400 [==============================================================] done
Stat small files count: 400 / 400 [==============================================================] done
Benchmark finished!
BlockSize: 1 MiB, BigFileSize: 1024 MiB, SmallFileSize: 128 KiB, SmallFileCount: 100, NumThreads: 4
Time used: 72.0 s, CPU: 35.5%, Memory: 704.1 MiB
+------------------+------------------+---------------+
| ITEM | VALUE | COST |
+------------------+------------------+---------------+
| Write big file | 148.25 MiB/s | 27.63 s/file |
| Read big file | 144.29 MiB/s | 28.39 s/file |
| Write small file | 40.5 files/s | 98.83 ms/file |
| Read small file | 715.9 files/s | 5.59 ms/file |
| Stat file | 3759.0 files/s | 1.06 ms/file |
| FUSE operation | 71735 operations | 2.99 ms/op |
| Update meta | 4773 operations | 27.18 ms/op |
| Put object | 1424 operations | 443.33 ms/op |
| Get object | 0 operations | 0.00 ms/op |
| Delete object | 0 operations | 0.00 ms/op |
| Write into cache | 1424 operations | 281.82 ms/op |
| Read from cache | 1428 operations | 556.68 ms/op |
+------------------+------------------+---------------+

juicefs + redis 成绩

试着跑了一次,结果跑崩了,想玩的自己跑一跑吧。

由于 redis 是内存数据库,跑这种没有上限的测试一定要谨慎。在实际使用中,也要根据自己的需要选择,否则机器很容易 gg。

垃圾清理

juicefs 默认有回收站机制,删除文件默认在回收站保留一天。

可以去挂载目录下执行这条命令彻底删除:

1
$ find .trash -name '*.tmp' | xargs rm -f

总结

本文介绍了 JuiceFS 的基本用法,为“大盘鸡”需求提供一种新的思路,展示了使用对象存储挂载到机器作为文件系统的基本效果。

目前看来是解决系统盘过小问题的好方案,但具体是不是采纳这种方案,等我明天看看账单再做决定。

第二天看了下账单,跑了大概 10 轮测试,账单 0.02¥ ,初步看还能接受:

至于元数据引擎的选择,在单节点服务器的需求上我还是偏向 sqlite 或 mysql 集群的方案,redis 虽然性能强劲,但实在有点吃不消。

最后,这一定是一个很棒的项目,在对接 docker、k8s 之类的容器设施非常方便,提供了插件,可以像操作默认存储卷一样使用,还可以直接使用挂载在本地的路径,总之,在一些方面 JuiceFS 做的已经很好了,下面就是等待时间的检验了。

参考文献