Alluxio(/əˈlʌksio/)是大数据和机器学习生态系统中的数据访问层。最初作为研究项目「Tachyon」,它是在加州大学伯克利分校的 AMPLab 作为创建者 2013 年的博士论文创建的。Alluxio 于 2014 年开源。
下表显示了 Alluxio 和 JuiceFS 之间的主要功能差异。
特性 | Alluxio | JuiceFS |
---|---|---|
存储格式 | Object | Block |
缓存粒度 | 64MiB | 4MiB |
多级缓存 | ✓ | ✓ |
Hadoop 兼容 | ✓ | ✓ |
S3 兼容 | ✓ | ✓ |
Kubernetes CSI Driver | ✓ | ✓ |
Hadoop 数据本地性 | ✓ | ✓ |
完全兼容 POSIX | ✕ | ✓ |
原子元数据操作 | ✕ | ✓ |
一致性 | ✕ | ✓ |
数据压缩 | ✕ | ✓ |
数据加密 | ✕ | ✓ |
零运维 | ✕ | ✓ |
开发语言 | Java | Go |
开源协议 | Apache License 2.0 | Apache License 2.0 |
开源时间 | 2014 | 2021.1 |
JuiceFS 中一个文件的存储格式包含三个层级:chunk、slice 和 block。一个文件将被分割成多个块,并被压缩和加密(可选)存储到对象存储中。
Alluxio 将文件作为「对象」存储到 UFS。文件不会像 JuiceFS 那样被拆分成 block。
JuiceFS 的默认块大小为 4MiB,相比 Alluxio 的 64MiB,粒度更小。较小的块大小更适合随机读取(例如 Parquet 和 ORC)工作负载,即缓存管理将更有效率。
JuiceFS 完整兼容 HDFS。不仅兼容 Hadoop 2.x 和 Hadoop 3.x,还兼容 Hadoop 生态系统中的各种组件。
JuiceFS 提供了 Kubernetes CSI Driver 来帮助在 Kubernetes 中便捷使用 JuiceFS。Alluxio 也提供了 Kubernetes CSI Driver,但是这个项目维护得不够活跃,也没有得到 Alluxio 的官方支持。
JuiceFS 完全兼容 POSIX。来自京东的一个 pjdfstest 显示 Alluxio 没有通过 POSIX 兼容性测试,例如 Alluxio 不支持符号链接、truncate、fallocate、append、xattr、mkfifo、mknod 和 utimes。除了 pjdfstest 涵盖的东西外,JuiceFS 还提供了关闭再打开(close-to-open)一致性、原子元数据操作、mmap、fallocate 打洞、xattr、BSD 锁(flock)和 POSIX 记录锁(fcntl)。
Alluxio 中的元数据操作有两个步骤:第一步是修改 Alluxio master 的状态,第二步是向 UFS 发送请求。可以看到,元数据操作不是原子的,当操作正在执行或发生任何故障时,其状态是不可预测的。Alluxio 依赖 UFS 来实现元数据操作,比如重命名文件操作会变成复制和删除操作。
感谢 Redis 事务,JuiceFS 的大部分元数据操作都是原子的,例如重命名文件、删除文件、重命名目录。您不必担心一致性和性能。
Alluxio 根据需要从 UFS 加载元数据,并且它在启动时没有关于 UFS 的信息。默认情况下,Alluxio 期望对 UFS 的所有修改都通过 Alluxio 进行。如果直接对 UFS 进行更改,则需要手动或定期在 Alluxio 和 UFS 之间同步元数据。正如「原子元数据操作」部分所说,两步元数据操作可能会导致不一致。
JuiceFS 提供元数据和数据的强一致性。JuiceFS 的元数据服务是唯一的真实来源(single source of truth),不是 UFS 的镜像。 元数据服务不依赖对象存储来获取元数据。对象存储只是被视为无限制的块存储。JuiceFS 和对象存储之间没有任何不一致之处。
JuiceFS 支持使用 LZ4 或 Zstandard 来压缩您的所有数据。Alluxio 没有这个功能。
JuiceFS 支持传输中加密(encryption in transit)以及静态加密(encryption at rest)。Alluxio 社区版没有这个功能,但是企业版有。
Alluxio 的架构可以分为 3 个组件:master、worker 和客户端。一个典型的集群由一个主节点(master)、多个备用主节点(standby master)、一个作业主节点(job master)、多个备用作业主节点(standby job master)、多个 worker 和 job worker 组成。您需要自己运维这些节点。
JuiceFS 使用 Redis 或者其它系统作为元数据引擎。您可以轻松使用由公有云提供商托管的服务作为 JuiceFS 的元数据引擎,没有任何运维负担。
两者都是高可靠,高性能的弹性分布式文件系统,且均有良好的 POSIX 兼容性,在各种文件系统使用场景都可一试。
两者都采用了数据和元数据分离的架构,但在组件实现上有很大区别。
是一套完整且独立的系统,倾向于私有云部署;所有数据和元数据都会持久化在 Ceph 自己的存储池(RADOS Pool)中。
kcephfs
),用户态客户端(ceph-fuse
)以及基于 libcephfs 实现的 C++、Python 等 SDK;近来社区也提供了 Windows 客户端(ceph-dokan
)。同时生态中也有与 Samba 对接的 VFS object 和与 NFS-Ganesha 对接的 FSAL 模块可供考虑。JuiceFS 主要实现一个 libjfs 库和 FUSE 客户端程序、Java SDK 等,支持对接多种元数据引擎和对象存储,适合在公有云、私有云或混合云环境下部署。
CephFS | JuiceFS | |
---|---|---|
文件分块 [1] | ✓ | ✓ |
元数据事务 | ✓ | ✓ |
强一致性 | ✓ | ✓ |
Kubernetes CSI Driver | ✓ | ✓ |
Hadoop 兼容 | ✓ | ✓ |
数据压缩 [2] | ✓ | ✓ |
数据加密 [3] | ✓ | ✓ |
快照 | ✓ | ✕ |
客户端数据缓存 | ✕ | ✓ |
Hadoop 数据本地性 | ✕ | ✓ |
S3 兼容 | ✕ | ✓ |
配额 | 目录级配额 | 文件系统(Volume)级配额 |
开发语言 | C++ | Go |
开源协议 | LGPLv2.1 & LGPLv3 | Apache License 2.0 |
虽然两者都做了大文件的分块,但在实现原理上有本质区别。CephFS 会将文件按 object_size
(默认为 4MiB)拆分,每个分块对应一个 RADOS object。而 JuiceFS 则将文件先按 64MiB Chunk 拆分,每个 Chunk 在写入时根据实际情况进一步拆分成一个或多个逻辑 Slice,每个 Slice 在写入对象存储时再拆分成默认 4MiB 的 Block,Block 与对象存储中 object 一一对应。在处理覆盖写时,CephFS 需要直接修改对应的 objects,流程较为复杂;尤其是冗余策略为 EC 或者开启数据压缩时,往往需要先读取部分 object 内容,在内存中修改后再写入,这个流程会带来很大的性能开销。而 JuiceFS 在覆盖写时将更新数据作为新 objects 写入并修改元数据即可,性能大幅提升;此外,过程中出现的冗余数据会异步完成垃圾回收。
严格来讲,CephFS 本身并未提供数据压缩功能,其实际依赖的是 RADOS 层 BlueStore 的压缩。而 JuiceFS 则可以在 Block 上传到对象存储之前就进行一次数据压缩,以减少对象存储中的容量使用。换言之,如果用 JuiceFS 对接 RADOS,是能做到在 Block 进 RADOS 前后各进行一次压缩。另外,就像在文件分块中提到的,出于对覆盖写的性能保障,CephFS 一般不会开启 BlueStore 的压缩功能。
Ceph Messenger v2 支持网络传输层的数据加密,存储层则与压缩类似,依赖于 OSD 创建时提供的加密功能。JuiceFS 是在上传对象前和下载后执行加解密,在对象存储侧完全透明。
S3FS 是一个 C++ 开发的开源工具,可以将 S3 对象存储通过 FUSE 挂载到本地,像本地磁盘一样进行读写访问。除了 Amazon S3,它还支持所有兼容 S3 API 的对象存储。
在基本功能方面,S3FS 与 JuiceFS 都能通过 FUSE 将对象存储 Bucket 挂载到本地并以 POSIX 接口使用。但在功能细节和技术实现上,二者有着本质的不同。
S3FS 是一种实用工具,可以方便地将对象存储 Bucket 挂载到本地,以用户熟悉的方式进行读写,面向那些对性能和网络延迟不敏感的一般使用场景。
JuiceFS 是分布式文件系统,具有独特的数据管理方式以及一系列针对高性能、可靠性和安全性等方面的技术优化,主要解决海量数据的存储需求。
S3FS 没有针对文件做特别的优化处理,它就像一个本地与对象存储之间的访问通道,本地挂载点看到的内容与对象存储浏览器上看到的一致,这样可以很方便地实现在本地使用云端存储。但从另一个角来看,正是因为这种简单的架构,使得 S3FS 对文件的检索和读写都需要与对象存储直接交互,网络延迟对性能和用户体验都会有较大的影响。
JuiceFS 采用数据和元数据分离的技术架构,任何文件都会先按照特定规则拆分成数据块再上传到对象存储,相应的元数据会存储在独立的数据库中。这样带来的好处是对文件的检索以及文件名等元信息的修改可以直接与响应速度更快的数据库交互,避开了与对象存储交互的网络延迟影响。
另外,在大文件的处理方面,虽然 S3FS 可以通过分块上传解决大文件的传输问题,但对象存储的特性决定了追加和改写文件需要重写整个对象。对于几十几百 GB 甚至 TB 级的大文件来说,重复上传势必会浪费大量的时间和带宽资源。
JuiceFS 则规避了此类问题,不论单个文件尺寸多大,在上传之前都会预先在本地按照特定规则拆分成数据块(默认 4MiB)。对任何文件的改写和追加最终都会变成生成新的数据块,而不是修改已生成的数据块,大大减少了时间和带宽资源的浪费。
有关 JuiceFS 的详细架构介绍请参考文档。
S3FS 支持磁盘缓存,但默认不启用。可以通过 -o use_cache
指定一个缓存路径来启用本地缓存。启用缓存后,任何文件的读写都会先写入缓存,然后再执行操作。S3FS 通过 MD5 来检测数据变化,确保数据正确性,同时降低文件的重复下载。由于 S3FS 涉及的所有操作都需要与 S3 交互,因此是否启用缓存对其应用体验有显著的影响。
S3FS 默认不限制缓存空间上限,对于较大的 Buket 可能导致缓存把磁盘写满,需要通过 -o ensure_diskfree
定义为磁盘保留的空间。另外,S3FS 没有缓存过期和清理机制,用户需要定期手动清理缓存,一旦缓存空间被存满,未缓存文件操作则需要直接与对象存储交互,处理大规模文件会有一定影响。
在缓存方面,JuiceFS 与 S3FS 完全不同,首先,JuiceFS 是保证数据一致性的。其次,JuiceFS 默认定义了 100GiB 的磁盘缓存使用上限,用户可以根据需要自由调整该值,而且默认会确保磁盘剩余空间低于 10% 时不再使用更多空间。当缓存用量达到上限,JuiceFS 会采用类似 LRU 的算法自动进行清理,确保后续的读写操作始终有缓存可用。
有关 JuiceFS 缓存的更多内容请参考文档。
S3FS | JuiceFS | |
---|---|---|
数据存储 | S3 | S3、其他对象存储、WebDAV、本地磁盘 |
元数据存储 | 无 | 独立数据库 |
系统 | Linux、macOS | Linux、macOS、Windows |
访问接口 | POSIX | POSIX、HDFS API、S3 Gateway、CSI Driver |
POSIX 兼容 | 部分兼容 | 完全兼容 |
共享挂载 | 支持但不保证数据的完整性和一致性 | 保证强一致性 |
本地缓存 | ✓ | ✓ |
符号链接 | ✓ | ✓ |
标准 Unix 权限 | ✓ | ✓ |
强一致性 | ✕ | ✓ |
扩展属性 | ✕ | ✓ |
硬链接 | ✕ | ✓ |
文件分块 | ✕ | ✓ |
原子操作 | ✕ | ✓ |
数据压缩 | ✕ | ✓ |
客户端加密 | ✕ | ✓ |
开发语言 | C++ | Go |
开源协议 | GPL v2.0 | Apache License 2.0 |
OSSFS、COSFS、OBSFS 等都是基于 S3FS 开发的衍生品,功能特性和用法与 S3FS 基本一致。
与 JuiceFS 类似,S3QL 也是一款由对象存储和数据库组合驱动的开源网络文件系统,所有存入的数据会被分块后存储到亚马逊 S3、Backblaze B2、OpenStack Swift 等主流的对象存储中,相应的元数据会存储在数据库中。
注意
S3QL 已于 2022 年 11 月 9 日停止维护,详见 S3QL 仓库。
S3QL | JuiceFS | |
---|---|---|
项目状态 | 停止维护 | 活跃开发 |
元数据引擎 | SQLite | Redis、MySQL、SQLite、TiKV |
存储引擎 | 对象存储、本地磁盘 | 对象存储、WebDAV、本地磁盘 |
操作系统 | Unix-like | Linux、macOS、Windows |
压缩算法 | LZMA, bzip2, gzip | LZ4, zstd |
加密算法 | AES-256 | AES-GCM, RSA |
POSIX 兼容 | ✓ | ✓ |
硬链接 | ✓ | ✓ |
符号链接 | ✓ | ✓ |
扩展属性 | ✓ | ✓ |
标准 Unix 权限 | ✓ | ✓ |
数据分块 | ✓ | ✓ |
本地缓存 | ✓ | ✓ |
空间弹性伸缩 | ✓ | ✓ |
元数据备份 | ✓ | ✓ |
数据去重 | ✓ | ✕ |
只读目录 | ✓ | ✕ |
快照 | ✓ | ✕ |
共享挂载 | ✕ | ✓ |
Hadoop SDK | ✕ | ✓ |
Kubernetes CSI Driver | ✕ | ✓ |
S3 网关 | ✕ | ✓ |
开发语言 | Python | Go |
开源协议 | GPLv3 | Apache License 2.0 |
开源时间 | 2011 | 2021.1 |
这部分主要评估两个产品在安装和使用上的的易用程度。
在安装过程中,我们使用 Rocky Linux 8.4 操作系统(内核版本 4.18.0-305.12.1.el8_4.x86_64)。
S3QL 采用 Python 开发,在安装时需要依赖 python-devel
3.7 及以上版本。另外,还需要至少满足以下依赖:fuse3-devel
、gcc
、pyfuse3
、sqlite-devel
、cryptography
、defusedxml
、apsw
、dugong
。另外,需要特别注意 Python 的包依赖和位置问题。
S3QL 会在系统中安装 12 个二进制程序,每个程序都提供一个独立的功能,如下图。
JuiceFS 客户端采用 Go 语言开发,直接下载预编译的二进制文件即可直接使用。JuiceFS 客户端只有一个二进制程序 juicefs
,将其拷贝到系统的任何一个可执行路径下即可,比如:/usr/local/bin
。
S3QL 和 JuiceFS 都使用数据库保存元数据,S3QL 仅支持 SQLite 数据库,JuiceFS 支持 Redis、TiKV、MySQL、MariaDB、PostgreSQL 和 SQLite 等数据库。
这里使用本地创建的 MinIO 对象存储,使用两款工具分别创建文件系统:
S3QL 使用 mkfs.s3ql
工具创建文件系统:
mkfs.s3ql --plain --backend-options no-ssl -L s3ql s3c://127.0.0.1:9000/s3ql/
挂载文件系统使用 mount.s3ql
:
mount.s3ql --compress none --backend-options no-ssl s3c://127.0.0.1:9000/s3ql/ mnt-s3ql
S3QL 在创建和挂载文件系统时都需要通过命令行交互式的提供对象存储 API 的访问密钥。
JuiceFS 使用 format
子命令创建文件系统:
juicefs format --storage minio \
--bucket http://127.0.0.1:9000/myjfs \
--access-key minioadmin \
--secret-key minioadmin \
sqlite3://myjfs.db \
myjfs
挂载文件系统使用 mount
子命令:
sudo juicefs mount -d sqlite3://myjfs.db mnt-juicefs
JuiceFS 只在创建文件系统时设置对象存储 API 访问密钥,相关信息会写入元数据引擎,之后挂载使用无需重复提供对象存储地址、密钥等信息。
S3QL 采用对象存储 + SQLite 的存储结构,数据分块存储既能提高文件的读写效率,也能降低文件修改时的资源开销。贴心的提供了快照、数据去重、数据保持等高级功能,加之默认的数据压缩和数据加密,让 S3QL 非常适合个人在云存储上用较低的成本、更安全的存储文件。
JuiceFS 支持对象存储、HDFS、WebDAV、本地磁盘作为数据存储引擎,支持 Redis、TiKV、MySQL、MariaDB、PostgreSQL、SQLite 等流行的数据作为元数据存储引擎。除了通过 FUSE 提供标准的 POSIX 文件系统接口以外,JuiceFS 还提供 Java API,可以直接替代 HDFS 为 Hadoop 提供存储。同时还提供 Kubernetes CSI Driver,可以作为 Kubernetes 的存储层做数据持久化存储。JuiceFS 是为企业级分布式数据存储场景设计的文件系统,广泛应用于大数据分析、机器学习、容器共享存储、数据共享及备份等多种场景。