JuiceFS 是一款高性能 POSIX 文件系统,针对云原生环境特别优化设计,在 GNU Affero General Public License v3.0 开源协议下发布。使用 JuiceFS 存储数据,数据本身会被持久化在对象存储(例如,Amazon S3),而数据所对应的元数据可以根据场景需求被持久化在 Redis、MySQL、SQLite 等多种数据库引擎中。JuiceFS 可以简单便捷的将海量云存储直接接入已投入生产环境的大数据、机器学习、人工智能以及各种应用平台,无需修改代码即可像使用本地存储一样高效使用海量云端存储。
核心特性
- POSIX 兼容:像本地文件系统一样使用,无缝对接已有应用,无业务侵入性;
- HDFS 兼容:完整兼容 HDFS API,提供更强的元数据性能;
- S3 兼容:提供 S3 网关 实现 S3 协议兼容的访问接口;
- 云原生:通过 Kubernetes CSI Driver 可以很便捷地在 Kubernetes 中使用 JuiceFS;
- 多端共享:同一文件系统可在上千台服务器同时挂载,高性能并发读写,共享数据;
- 强一致性:确认的修改会在所有挂载了同一文件系统的服务器上立即可见,保证强一致性;
- 强悍性能:毫秒级的延迟,近乎无限的吞吐量(取决于对象存储规模),查看性能测试结果;
- 数据安全:支持传输中加密(encryption in transit)以及静态加密(encryption at rest),查看详情;
- 文件锁:支持 BSD 锁(flock)及 POSIX 锁(fcntl);
- 数据压缩:支持使用 LZ4 或 Zstandard 压缩数据,节省存储空间;
一、安装go运行环境
juice是使用go语言编写的,首先我们要安装一下go运行环境。
安装方式一(直接使用官方编译好的二进制文件)。
全新安装:
将go的最新版安装包go1.17.4.linux-amd64.tar.gz下载到节点上,解压压缩包,导入go的环境变量。
[root@node112 ~]# wget https://go.dev/dl/go1.17.4.linux-amd64.tar.gz
# 备份go旧版本二进制文件
[root@node112 ~]# mv /usr/local/bin/go /usr/local/bin/go1.12.2
[root@node112 ~]# tar -C /usr/local -zxvf go1.17.4.linux-amd64.tar.gz
[root@node112 ~]# ln -s /usr/local/go/bin/go /usr/local/bin/go
[root@node112 ~]# export GOROOT=/usr/local/go
[root@node112 ~]# export PATH=$PATH:/usr/local/go/bin
[root@node112 ~]# go version
go version go1.17.4 linux/amd64
升级安装:
[root@node112 ~]# rm -rf /usr/local/go/
[root@node112 ~]# rm -f /usr/local/bin/go
[root@node112 ~]# tar -C /usr/local -zxvf go1.16.11.linux-amd64.tar.gz
[root@node112 ~]# ln -s /usr/local/go/bin/go /usr/local/bin/go
[root@node112 ~]# go version
go version go1.16.11 linux/amd64
安装方式二(使用源码进行编译安装)。
首先将最新版go源码压缩包go1.17.4.src.tar.gz下载到节点上,解压压缩包,然后按照下面的步骤进行安装。
[root@node112 ~]# cd go/src/
[root@node112 src]# ./all.bash ##这里会比较耗时
如果出现下面错误。
[root@node112 ~]# go version
go: error while loading shared libraries: libgo.so.14: cannot open shared object file: No such file or directory
查找libgo.so.14文件的路径然后将路径导入环境变量LD_LIBRARY_PATH中,就不会报错了。
[root@node112 ~]# find / -depth -name "libgo.so.14" -print
/root/gcc-9.1.0/gcc-build-9.1.0/x86_64-pc-linux-gnu/libgo/.libs/libgo.so.14
/usr/local/lib64/libgo.so.14
[root@node112 ~]# export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH
[root@node112 ~]# echo $LD_LIBRARY_PATH
/usr/local/lib64:
[root@node112 ~]# go version
go version go1.12.2 gccgo (GCC) 9.1.0 linux/amd64
二、编译JuiceFS二进制文件
下载JuiceFS源码包。
[root@node101 ~]# git clone https://gitee.com/juicedata/JuiceFS.git
[root@node101 ~]# cd JuiceFS/
开始编译安装juicefs。
[root@node101 JuiceFS]# export GOPROXY=https://github.com/goproxy/goproxy.cn 或 export GOPROXY=https://goproxy.io
[root@node101 JuiceFS]# make -j4
[root@node101 ~]# juicefs --version
juicefs version 0.17.2 (2021-11-19T06:58:44Z d820726)
三、将ceph的s3对象存储挂载为本地目录
使用juicefs可以将ceph的s3对象存储接口挂载为本地目录。
[root@node101 ~]# juicefs format redis://localhost:6379/3 --storage s3 --bucket http://bucket2.192.168.30.114:7480 --access-key C1DK1Y9WGP65MGXJ49FU --secret-key mDRf2unXMZqUrVGIpg2UGsvt4JmZSl76apYKGZ5f test
# 注意 这里bucket参数实际上是 http://[bucket].[endpoint] 格式,最后一个参数test是bucket下的目录名; redis的连接地址如果需要密码的话,注意把密码补上
[root@node101 ~]# juicefs mount -d redis://localhost:6379/3 ~/test/
对挂载目录执行基准性能测试。
[root@node101 test]# juicefs bench -p 4 /root/test/
四、编译juicefs.ceph二进制文件
为 Ceph 编译 JuiceFS支持rados接口(要求 Go 1.16+ 和 GCC 5.4+)
因为我们的环境中GCC版本是4.8.5,所以首先要升级gcc,注意编译gcc时在参数-enable-languages后面添加go让gcc支持go语言。
[root@node101 ~]# wget http://ftp.gnu.org/gnu/gcc/gcc-9.1.0/gcc-9.1.0.tar.gz
[root@node101 ~]# tar -xzvf gcc-9.1.0.tar.gz
[root@node101 ~]# cd gcc-9.1.0
[root@node101 gcc-9.1.0]# ./contrib/download_prerequisites
[root@node101 gcc-9.1.0]# mkdir gcc-build-9.1.0
[root@node101 gcc-9.1.0]# cd gcc-build-9.1.0
[root@node101 gcc-build-9.1.0]# ../configure -enable-checking=release -enable-languages=c,c++,go -disable-multilib
[root@node101 gcc-build-9.1.0]# make -j4 ##这个时间有点长,我的环境花了将近5个小时
[root@node101 gcc-build-9.1.0]# sudo make install
# 重启节点,待重启完成后查看gcc版本,显示升级成功
[root@node101 ~]# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure -enable-checking=release -enable-languages=c,c++,go -disable-multilib
Thread model: posix
gcc version 9.1.0 (GCC)
开始编译juicefs.ceph二进制文件。
[root@node101 JuiceFS]# make -j4 juicefs.ceph ##这一步有点慢,要下载一些依赖包,耐心等待
# 如果下载失败了执行下面的命令,然后重新执行命令下载
[root@node101 JuiceFS]# go env
[root@node101 JuiceFS]# export GOPROXY=https://github.com/goproxy/goproxy.cn
继续执行,报错如下:
[root@node101 JuiceFS]# make -j4 juicefs.ceph
go build -tags ceph -ldflags="-s -w -X github.com/juicedata/juicefs/pkg/version.revision=d51194d -X github.com/juicedata/juicefs/pkg/version.revisionDate=2021-12-06" -o juicefs.ceph ./cmd
# github.com/ceph/go-ceph/rados
/root/go/pkg/mod/github.com/ceph/go-ceph@v0.4.0/rados/command.go:5:11: fatal error: rados/librados.h: No such file or directory
5 | // #include <rados/librados.h>
| ^~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [juicefs.ceph] Error 2
安装dnf包管理工具
[root@node101 rados]# yum install epel-release -y
[root@node101 rados]# yum install dnf -y
使用dnf查找rados/librados.h对应的包
[root@node101 rados]# dnf whatprovides *rados/librados.h
Extra Packages for Enterprise Linux 7 - x86_64 4.1 MB/s | 17 MB 00:04
CentOS-7 - Base 2.2 MB/s | 10 MB 00:04
CentOS-7 - Updates 20 MB/s | 15 MB 00:00
CentOS-7 - Extras 209 kB/s | 310 kB 00:01
Last metadata expiration check: 0:00:01 ago on Tue 07 Dec 2021 05:43:47 PM CST.
librados2-devel-1:10.2.5-4.el7.i686 : RADOS headers
Repo : base
Matched from:
Other : *rados/librados.h
librados2-devel-1:10.2.5-4.el7.x86_64 : RADOS headers
Repo : base
Matched from:
Other : *rados/librados.h
从上面可以看出这个文件是在librados2-devel这个包里面,我们把这个包装一下。
[root@node101 rados]# dnf install librados2-devel -y
手动执行安装程序,又报错。
[root@node101 rados]# go get github.com/ceph/go-ceph/rados
# github.com/ceph/go-ceph/rados
./command.go:106:9: could not determine kind of name for C.rados_mgr_command
查看编译目录下的Makefile文件,发现有个地方跟官方描述有出入,下面这个官方描述的大致意思就是说go-ceph为了支持不同版本的ceph,对应了不同版本的go-ceph,在编译的时候要加上-tags这个参数来指定你要编译的juicefs.ceph的版本,但如果不确定直接用的是哪个版本的ceph,那么可以在编译的时候使用-tags Ceph标签来禁用这个选项。
go-ceph tries to support different Ceph versions. However some functions might only be available in recent versions, and others may be deprecated. In order to work with non-current versions of Ceph, it is required to pass build-tags to the
go
command line. A tag with the named Ceph release will enable/disable certain features of the go-ceph packages, and prevent warnings or compile problems. For example, to ensure you select the library features that match the "pacific" release,use:go build -tags pacific .... go test -tags pacific ....
Supported Ceph Versions
go-ceph version Supported Ceph Versions Deprecated Ceph Versions v0.12.0 octopus, pacific nautilus v0.11.0 nautilus, octopus, pacific v0.10.0 nautilus, octopus, pacific v0.9.0 nautilus, octopus v0.8.0 nautilus, octopus v0.7.0 nautilus, octopus v0.6.0 nautilus, octopus mimic v0.5.0 nautilus, octopus luminous, mimic v0.4.0 luminous, mimic, nautilus, octopus v0.3.0 luminous, mimic, nautilus, octopus v0.2.0 luminous, mimic, nautilus (pre release) luminous, mimic (see note)
[root@node101 JuiceFS]# cp Makefile Makefile_bak
[root@node101 JuiceFS]# vi Makefile
# 找到juicefs.ceph: Makefile这一行,把go build -tags ceph行中的ceph改成Ceph,也就是小写c改成大写的C。
juicefs.ceph: Makefile cmd/*.go pkg/*/*.go
go build -tags Ceph -ldflags="$(LDFLAGS)" -o juicefs.ceph ./cmd
# 这里要手动下载指定版本的go-ceph
[root@node112 ceph]# go get github.com/ceph/go-ceph@v0.4.0
# 手动执行编译juicefs.ceph命令,添加-n参数打印编译时用到的所有命令,但不真正执行
[root@node112 juicefs]# export GO111MODULE=on
[root@node112 JuiceFS]# go build -n -tags Ceph -ldflags="-s -w -X github.com/juicedata/juicefs/pkg/version.revision=d51194d -X github.com/juicedata/juicefs/pkg/version.revisionDate=2021-12-06" -o juicefs.ceph3 ./cmd
修改完成之后再次编译成功。
[root@node101 JuiceFS]# make -j4 juicefs.ceph
go build -tags Ceph -ldflags="-s -w -X github.com/juicedata/juicefs/pkg/version.revision=5e57a10 -X github.com/juicedata/juicefs/pkg/version.revisionDate=2021-12-07" -o juicefs.ceph ./cmd
[root@node101 JuiceFS]# ls
ADOPTERS_CN.md check-changed.sh CODE_OF_CONDUCT.md docs go.mod hack juicefs.ceph Makefile pkg README.md
ADOPTERS.md cmd CONTRIBUTING.md fstests go.sum integration LICENSE Makefile_bak README_CN.md sdk
[root@node101 JuiceFS]# ./juicefs.ceph
NAME:
juicefs - A POSIX file system built on Redis and object storage.
USAGE:
juicefs.ceph [global options] command [command options] [arguments...]
VERSION:
1.0-dev (2021-12-07 5e57a10)
COMMANDS:
format format a volume
mount mount a volume
umount unmount a volume
gateway S3-compatible gateway
sync sync between two storage
rmr remove directories recursively
info show internal information for paths or inodes
bench run benchmark to read/write/stat big/small files
gc collect any leaked objects
fsck Check consistency of file system
profile analyze access log
stats show runtime statistics
status show status of JuiceFS
warmup build cache for target directories/files
dump dump metadata into a JSON file
load load metadata from a previously dumped JSON file
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--verbose, --debug, -v enable debug log (default: false)
--quiet, -q only warning and errors (default: false)
--trace enable trace log (default: false)
--no-agent Disable pprof (:6060) and gops (:6070) agent (default: false)
--help, -h show help (default: false)
--version, -V print only the version (default: false)
COPYRIGHT:
AGPLv3
但是通过编译成功的juicefs.ceph挂载集群存储池为本地目录时报错了,目前暂时查不到关于这个错误的信息(这里官方挖了个坑,可直接略过下面的内容查看第六部分的解决方案)。
[root@node101 ~]# ./juicefs.ceph format --storage ceph --bucket ceph://data --access-key ceph --secret-key client.admin redis://localhost:6379/1 ceph-volume
2021/12/08 16:26:02.634338 juicefs[282500] <INFO>: Meta address: redis://localhost:6379/1
2021/12/08 16:26:02.637043 juicefs[282500] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly.
2021/12/08 16:26:02.637398 juicefs[282500] <INFO>: Ping redis: 246.692µs
2021/12/08 16:26:02.637841 juicefs[282500] <FATAL>: object storage: invalid storage: ceph
临时解决办法,将go-ceph目录下的command.go和omap.go这两个文件重命名后再编译(目前暂时不清楚修改后有没有其他问题)。
[root@node101 JuiceFS]# go build -tags Ceph /root/go/pkg/mod/github.com/ceph/go-ceph@v0.4.0/rados
# github.com/ceph/go-ceph/rados
../go/pkg/mod/github.com/ceph/go-ceph@v0.4.0/rados/command.go:106:9: could not determine kind of name for C.rados_mgr_command
[root@node101 JuiceFS]# go build -tags luminous /root/go/pkg/mod/github.com/ceph/go-ceph@v0.4.0/rados
# github.com/ceph/go-ceph/rados
../go/pkg/mod/github.com/ceph/go-ceph@v0.4.0/rados/omap.go:94:2: could not determine kind of name for C.rados_read_op_omap_get_vals2
[root@node101 JuiceFS]# go build -tags luminous /root/go/pkg/mod/github.com/ceph/go-ceph@v0.4.0/rados
[root@node101 ~]# cd /root/go/pkg/mod/github.com/ceph/go-ceph@v0.4.0/rados
[root@node101 rados]# mv command.go command.go_bak
[root@node101 rados]# mv omap.go omap.go_bak
修改编译命令中的-tags ceph参数(把ceph修改为小写),然后重新编译,这次没有再出现“could not determine kind of name for C.rados_mgr_command”的报错。
[root@node101 JuiceFS]# go build -tags ceph -ldflags="-s -w -X github.com/juicedata/juicefs/pkg/version.revision=5e57a10 -X github.com/juicedata/juicefs/pkg/version.revisionDate=2021-12-07" -o juicefs.ceph ./cmd
[root@node101 JuiceFS]# ls
ADOPTERS_CN.md check-changed.sh CODE_OF_CONDUCT.md docs go.mod hack juicefs LICENSE pkg README.md
ADOPTERS.md cmd CONTRIBUTING.md fstests go.sum integration juicefs.ceph Makefile README_CN.md sdk
五、将ceph的存储池挂载为本地目录使用
使用juicefs.ceph将集群存储池data挂载为本地目录。
[root@node101 JuiceFS]# ./juicefs.ceph format --storage ceph --bucket ceph://data --access-key ceph --secret-key client.admin redis://localhost:6379/1 ceph-volume
2021/12/09 09:22:38.234224 juicefs[3165225] <INFO>: Meta address: redis://localhost:6379/1
2021/12/09 09:22:38.237536 juicefs[3165225] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly.
2021/12/09 09:22:38.237847 juicefs[3165225] <INFO>: Ping redis: 205.011µs
2021/12/09 09:22:41.319756 juicefs[3165225] <INFO>: Data use ceph://data/ceph-volume/
2021/12/09 09:22:41.444859 juicefs[3165225] <INFO>: Volume is formatted as {Name:ceph-volume UUID:46fdfd9a-53e3-4482-bb0d-d8b9b7ff7f82 Storage:ceph Bucket:ceph://data AccessKey:ceph SecretKey:removed BlockSize:4096 Compression:none Shards:0 Partitions:0 Capacity:0 Inodes:0 EncryptKey: TrashDays:1}
挂载使用,往挂载目录中写入数据。
[root@node101 ~]# cd JuiceFS/
[root@node101 JuiceFS]# ./juicefs.ceph mount -d redis://localhost:6379/1 ~/ceph-volume/
2021/12/09 09:25:42.291904 juicefs[3172685] <INFO>: Meta address: redis://localhost:6379/1
2021/12/09 09:25:42.295030 juicefs[3172685] <WARNING>: AOF is not enabled, you may lose data if Redis is not shutdown properly.
2021/12/09 09:25:42.295429 juicefs[3172685] <INFO>: Ping redis: 271.549µs
2021/12/09 09:25:42.374197 juicefs[3172685] <INFO>: Data use ceph://data/ceph-volume/
2021/12/09 09:25:42.374797 juicefs[3172685] <INFO>: Disk cache (/var/jfsCache/46fdfd9a-53e3-4482-bb0d-d8b9b7ff7f82/): capacity (1024 MB), free ratio (10%), max pending pages (15)
2021/12/09 09:25:42.879324 juicefs[3172685] <INFO>: OK, ceph-volume is ready at /root/ceph-volume/
[root@node101 JuiceFS]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.7G 0 3.7G 0% /dev
tmpfs 3.7G 0 3.7G 0% /dev/shm
tmpfs 3.7G 8.9M 3.7G 1% /run
tmpfs 3.7G 0 3.7G 0% /sys/fs/cgroup
/dev/mapper/centos-root 28G 18G 10G 65% /
/dev/sda1 1014M 187M 828M 19% /boot
tmpfs 747M 0 747M 0% /run/user/0
tmpfs 3.7G 48K 3.7G 1% /var/lib/ceph/osd/ceph-1
tmpfs 3.7G 48K 3.7G 1% /var/lib/ceph/osd/ceph-4
tmpfs 3.7G 48K 3.7G 1% /var/lib/ceph/osd/ceph-7
192.168.30.101,192.168.30.102,192.168.30.103:/ 69G 0 69G 0% /vcluster/cephfs
JuiceFS:test 1.0P 0 1.0P 0% /root/test
JuiceFS:ceph-volume 1.0P 0 1.0P 0% /root/ceph-volume
[root@node101 JuiceFS]# cd /root/ceph-volume/
[root@node101 ceph-volume]# ls
[root@node101 ceph-volume]# dd if=/dev/zero of=1024m bs=1024k count=1024 conv=fdatasync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 38.8907 s, 27.6 MB/s
查看dada存储池的容量使用信息,可以看到数据已经写入data存储池里面了。
[root@node102 ~]# ceph df
GLOBAL:
SIZE AVAIL RAW USED %RAW USED
102GiB 93.9GiB 8.06GiB 7.91
POOLS:
NAME ID USED %USED MAX AVAIL OBJECTS
data 1 1.00GiB 1.48 66.4GiB 257
metadata 2 3.05KiB 0 44.2GiB 21
六、解决编译时出现出现“could not determine kind of name for C.rados_mgr_command”的报错”的问题
在编译节点上安装对应版本的ceph客户端包。
[root@node112 ~]# yum -y install centos-release-ceph-luminous.noarch
[root@node112 ~]# yum -y install ceph-common
[root@node113 ~]# ceph -v
ceph version 12.2.11 (26dc3775efc7bb286a1d6d66faee0ba30ea23eee) luminous (stable)
再编译就成功了。
[root@node112 juicefs]# go build -tags ceph -ldflags="-s -w -X github.com/juicedata/juicefs/pkg/version.revision=5e57a10 -X github.com/juicedata/juicefs/pkg/version.revisionDate=2021-12-07" -o juicefs.ceph ./cmd
[root@node112 juicefs]# ll -h
total 70M
-rw-r--r--. 1 root root 2.9K Dec 8 16:59 ADOPTERS_CN.md
-rw-r--r--. 1 root root 3.5K Dec 8 16:59 ADOPTERS.md
-rw-r--r--. 1 root root 358 Dec 8 16:59 check-changed.sh
drwxr-xr-x. 2 root root 4.0K Dec 8 16:59 cmd
-rw-r--r--. 1 root root 0 Dec 8 16:59 CODE_OF_CONDUCT.md
-rw-r--r--. 1 root root 2.5K Dec 8 16:59 CONTRIBUTING.md
drwxr-xr-x. 4 root root 46 Dec 8 16:59 docs
drwxr-xr-x. 2 root root 22 Dec 8 16:59 fstests
-rw-r--r--. 1 root root 3.9K Dec 8 16:59 go.mod
-rw-r--r--. 1 root root 132K Dec 8 16:59 go.sum
drwxr-xr-x. 5 root root 63 Dec 8 16:59 hack
drwxr-xr-x. 2 root root 49 Dec 8 16:59 integration
-rwxr-xr-x. 1 root root 70M Dec 9 11:09 juicefs.ceph
-rw-r--r--. 1 root root 34K Dec 8 16:59 LICENSE
-rw-r--r--. 1 root root 2.2K Dec 8 17:29 Makefile
drwxr-xr-x. 16 root root 190 Dec 8 16:59 pkg
-rw-r--r--. 1 root root 12K Dec 8 16:59 README_CN.md
-rw-r--r--. 1 root root 13K Dec 8 16:59 README.md
drwxr-xr-x. 3 root root 18 Dec 8 16:59 sdk
[root@node112 juicefs]#
七、性能调优
juicefs挂载选项中有一些参数可以作为性能调优选项。
--cache-dir: 缓存目录路径,将缓存路径换成内存可明显提高数据带宽和IOPS(建议该选项在内存比较充裕的时候使用。)
writeback_cache: 缓存模式,在参数-o选项后面加上这个参数,可以提升小文件数据的IOPS和带宽速率,当频繁写入非常小的数据(如 100 字节左右)时,建议启用此挂载选项。(注意:该挂载选项仅在 Linux 3.15 及以上版本内核上支持。)
[root@node113 ~]# ./juicefs.ceph mount --cache-dir /dev/shm/cache -d -o allow_other redis://localhost:6379/1 /ceph-volume/
测试性能命令。
[root@node113 ~]# ./juicefs bench /ceph-volume/ -p 4
查看性能数据。
[root@node113 ~]# ./juicefs stats /ceph-volume/ --verbosity 1