JuiceFS 分布式 POSIX 文件系统:架构原理、快速上手与源码级解析
2026/9/14 19:02:37 网站建设 项目流程

JuiceFS 分布式 POSIX 文件系统:架构原理、快速上手与源码级解析

【免费下载链接】juicefsJuiceFS is a distributed POSIX file system built on top of Redis and S3.项目地址: https://gitcode.com/GitHub_Trending/ju/juicefs

本文基于 JuiceFS 仓库的中文 README 与配套文档,系统讲解 JuiceFS 的整体架构(客户端、数据存储、元数据引擎三大组成)与「Chunk / Slice / Block」文件存储原理,并给出从format格式化、mount挂载到对象存储接入的完整实操命令与参数解析。读完本文,你可以理解 JuiceFS 如何在对象存储之上实现 POSIX 兼容的分布式文件系统,并在本地或生产环境中独立完成一次完整的部署与验证。

一、JuiceFS 是什么

JuiceFS 是一款高性能 POSIX 文件系统,针对云原生环境特别优化设计,在 Apache 2.0 开源协议下发布。其核心设计思路是数据与元数据分离

  • 数据本身被持久化在对象存储(例如 Amazon S3、阿里云 OSS、MinIO 等);
  • 数据对应的元数据可以根据场景需求持久化在 Redis、MySQL、TiKV、PostgreSQL、SQLite 等多种数据库引擎中。

这种设计允许用户无需修改业务代码,将海量云存储像本地存储一样直接接入大数据、机器学习、AI 以及各类应用平台。仓库内的目录结构印证了这一设计:pkg/object/ 实现了对数十种对象存储后端(S3、OSS、COS、GCS、Azure、Ceph、MinIO、本地文件、HDFS、NFS 等)的统一抽象,而 pkg/meta/ 则实现了 Redis(redis.go)、SQL 系(sql.go、sql_mysql.go、sql_pg.go、sql_sqlite.go)、TiKV(tkv_tikv.go)、etcd、FoundationDB、Badger 等多种元数据引擎。

核心特性

官方 README 列出的十大核心特性如下:

  1. POSIX 兼容:像本地文件系统一样使用,无缝对接已有应用,无业务侵入性;
  2. HDFS 兼容:完整兼容 HDFS API,提供更强的元数据性能,可参考 Hadoop Java SDK 文档;
  3. S3 兼容:提供 S3 网关实现 S3 协议兼容的访问接口,实现位于 pkg/gateway/;
  4. 云原生:通过 Kubernetes CSI 驱动可以很便捷地在 Kubernetes 中使用 JuiceFS,参见 Kubernetes 使用指南;
  5. 多端共享:同一文件系统可在上千台服务器同时挂载,高性能并发读写,共享数据;
  6. 强一致性:确认的修改会在所有挂载了同一文件系统的服务器上立即可见;
  7. 强悍性能:毫秒级的延迟,吞吐上限取决于对象存储规模,测试方法见 性能测试;
  8. 数据安全:支持传输中加密(encryption in transit)以及静态加密(encryption at rest),实现见 pkg/object/encrypt.go;
  9. 文件锁:支持 BSD 锁(flock)及 POSIX 锁(fcntl);
  10. 数据压缩:支持使用 LZ4 或 Zstandard 压缩数据,节省存储空间,压缩算法实现位于 pkg/compress/compress.go。

二、架构:三大组成部分

JuiceFS 由三个部分组成:

  1. JuiceFS 客户端:协调对象存储和元数据存储引擎,并实现 POSIX、Hadoop、Kubernetes、S3 Gateway 等文件系统接口;
  2. 数据存储:存储数据本身,支持本地磁盘、对象存储;
  3. 元数据引擎:存储数据对应的元数据,支持 Redis、MySQL、SQLite 等多种引擎。

从 技术架构文档 可以进一步看到客户端支持的多种接入方式:通过FUSE以 POSIX 方式挂载(实现位于 pkg/fuse/)、通过Python SDK在进程内直接访问、通过Windows 客户端(WinFSP,实现位于 pkg/winfsp/)、通过Hadoop Java SDK替代 HDFS(sdk/java/)、通过Kubernetes CSI 驱动、通过S3 网关(cmd/gateway.go)以及WebDAV 服务(cmd/webdav.go)。

元数据引擎中存储的内容包括两类:

  • 常规文件系统的元数据:文件名、文件大小、权限信息、创建修改时间、目录结构、文件属性、符号链接、文件锁等;
  • 文件数据的索引:文件的数据分配和引用计数、客户端会话等。

文件如何被存储:Chunk、Slice 与 Block

任何存入 JuiceFS 的文件都会被拆分成固定大小的Chunk,默认容量上限是64 MiB。这一数值在源码中是硬编码的常量,见 pkg/meta/interface.go:

ChunkSize = 1 << ChunkBits // 64M

由此可以推导出单文件的最大长度:pkg/vfs/vfs.go 中定义了maxFileSize = meta.ChunkSize << 31,即 64 MiB × 2^31 =256 TiB

存储分层的完整逻辑是:

  • Chunk:每个文件由 1 个或多个 Chunk 组成,每个 Chunk 最大 64 MiB。无论文件多大,所有读写都会根据偏移量定位到对应的 Chunk;只要文件总长度不变,无论经历多少次修改写入,Chunk 的切分都是固定的;
  • Slice:每个 Chunk 由一个或多个 Slice 组成。一个 Slice 代表一次连续写入,长度不固定,取决于文件写入的方式,且不能跨越 Chunk 边界。如果一个文件由一次连贯的顺序写生成,那么每个 Chunk 中仅包含一个 Slice;
  • Block:每个 Slice 会被进一步拆分成固定大小的 Block,默认为4 MiB。最终这些 Block 被多线程并发上传到对象存储。Block 是对象存储和磁盘缓存的最小物理存储单元

format命令的--block-size参数正是用来调整 Block 大小的,默认值为4M,定义于 cmd/format.go。从源码中的fixObjectSize函数(cmd/format.go#L218-L234)可以看到取值约束:最小 64 KiB、最大 16 MiB,且会被强制对齐为 2 的幂,超出范围时客户端会打印警告并自动收敛:

func fixObjectSize(s uint64) uint64 { const min, max = 64 << 10, 16 << 20 // ... 对齐为 2 的幂,并在 [64KiB, 16MiB] 区间内截断 }

因此,在对象存储平台的文件浏览器中是找不到存入 JuiceFS 的源文件的——存储桶中只有一个chunks目录和一堆数字编号的目录与文件。这些数字编号的对象正是拆分后的 Block,而 Block 与 Chunk、Slice 的对应关系、文件名、大小等元数据都保存在元数据引擎中。这正是 JuiceFS 高性能运作的秘诀:读写时按偏移量分而治之,避免了对整个大文件的寻址与传输开销。

此外,架构文档 还解释了写入后的碎片化治理机制:多次追加、覆盖写会使 Slice 相互堆叠,读取时需要查找「当前范围内最新写入的 Slice」,这种碎片化会同时影响读性能与空间占用。因此客户端会异步执行碎片合并(compaction),将同一 Chunk 内的所有 Slice 合并为一,实现位于 pkg/vfs/compact.go,并可通过 compact 命令 手动触发。

三、开始使用

1. 准备工作

创建 JuiceFS 需要以下 3 个方面的准备:

  1. 准备元数据数据库(Redis、MySQL、SQLite 等,选择方式见 元数据引擎设置指南);
  2. 准备对象存储(选择与配置见 对象存储设置指南);
  3. 下载安装 JuiceFS 客户端,安装方式见 安装文档。

2. format:创建文件系统

format命令的通用格式为:

juicefs format [command options] META-URL NAME

需要提供的三种信息:

  • [command options]:设定文件系统的存储介质,留空则默认使用本地磁盘作为存储介质,路径为$HOME/.juicefs/local(macOS)、/var/jfs(Linux)或C:/jfs/local(Windows);
  • META-URL:用来设置元数据存储引擎的 URL 或文件路径(Redis、TiKV、MySQL 等);
  • NAME:文件系统名称。

命令的官方示例直接内嵌在 cmd/format.go 的帮助文本中:

# 创建简单的测试卷(数据存储在本地目录) $ juicefs format sqlite3://myjfs.db myjfs # 使用 Redis + S3 创建卷 $ juicefs format redis://localhost myjfs --storage s3 --bucket https://mybucket.s3.us-east-2.amazonaws.com # 使用带密码的 MySQL 创建卷 $ juicefs format mysql://jfs:mypassword@(127.0.0.1:3306)/juicefs myjfs # 更安全的替代方式(通过环境变量传递密码) $ META_PASSWORD=mypassword juicefs format mysql://jfs:@(127.0.0.1:3306)/juicefs myjfs # 创建启用「配额」的卷 $ juicefs format sqlite3://myjfs.db myjfs --inodes 1000000 --capacity 102400 # 创建禁用「回收站」的卷 $ juicefs format sqlite3://myjfs.db myjfs --trash-days 0

以 单机模式快速上手 为例,用 SQLite + 本地磁盘创建一个名为myjfs的文件系统:

juicefs format sqlite3://myjfs.db myjfs

成功时输出类似:

2021/12/14 18:26:37 juicefs[40362] <INFO>: Meta address: sqlite3://myjfs.db 2021/12/14 18:26:37 juicefs[40362] <INFO>: Data use file:///Users/herald/.juicefs/local/myjfs/ 2021/12/14 18:26:37 juicefs[40362] <INFO>: Volume is formatted as {Name:myjfs UUID:d5bdf7ea-... Storage:file Bucket:/Users/herald/.juicefs/local/ BlockSize:4096 Compression:none ...}

输出中的BlockSize:4096单位为 KiB,即默认 4 MiB Block。

format 关键参数解析(源码级)

结合 cmd/format.go 中的参数定义,format的主要选项可分为三组:

数据存储组(DATA STORAGE),定义于 formatStorageFlags:

参数默认值说明
--storagefile对象存储类型(如s3gsosscos
--bucket平台相关的本地目录对象存储的 Bucket URL / 路径
--access-key-对象存储 Access Key(可用环境变量ACCESS_KEY
--secret-key-对象存储 Secret Key(可用环境变量SECRET_KEY
--session-token-会话令牌(可用环境变量SESSION_TOKEN
--storage-class-默认存储类型(分层存储)
--tag-上传对象时附加的自定义标签

数据格式组(DATA FORMAT),定义于 formatFlags:

参数默认值说明
--block-size4MBlock 大小(KiB),有效范围 64 KiB ~ 16 MiB,须为 2 的幂
--compressnone压缩算法:lz4zstdnone
--encrypt-rsa-key-RSA 私钥文件路径(PEM 格式),用于数据静态加密
--encrypt-algoaes256gcm-rsa加密算法(aes256gcm-rsachacha20-rsa
--hash-prefixfalse为对象名添加 hash 前缀(分散热点)
--shards0按 key 哈希将 Block 分散存储到 N 个 bucket(上限 256)

管理组(MANAGEMENT),定义于 formatManagementFlags:

参数默认值说明
--capacity0(不限)卷空间硬配额(GiB)
--inodes0(不限)卷 inode 数硬配额
--trash-days1删除文件后进入回收站保留的天数,0表示禁用回收站
--enable-aclfalse启用 POSIX ACL(一旦启用不可逆)
--forcefalse覆盖已有 format 配置
--no-updatefalse若卷已格式化则不做任何更新

几个从源码中可以直接确认的实现细节:

  • 卷名校验:名称必须匹配^[a-z0-9][a-z0-9\-]{1,61}[a-z0-9]$,即仅允许小写字母、数字和连字符,长度 3~63 个字符(cmd/format.go#L441-L444);
  • 写入前自检format会真实执行一次「写 → 读 → 校验 → 删」的存储探测(test 函数),并在新建卷时检查目标前缀目录是否为空,防止误覆盖已有数据;设置环境变量JFS_NO_CHECK_OBJECT_STORAGE可跳过该校验;
  • 密钥落库前加密format会把AccessKey/SecretKey等信息加密后存入元数据(format.Encrypt()),这就是为什么挂载时不需要重复提供对象存储凭证——相关信息已经写入了元数据库;
  • 对于file/sqlite3类型的存储,--bucket会被自动转换为绝对路径(cmd/format.go#L568-L578)。

3. mount:挂载文件系统

挂载命令的通用格式:

juicefs mount [command options] META-URL MOUNTPOINT

将上例创建的myjfs挂载到~/jfs

juicefs mount sqlite3://myjfs.db ~/jfs

默认情况下客户端在前台挂载,终端中Ctrl + C或关闭窗口即卸载。使用-d(或--background)可让客户端在守护进程中后台挂载:

juicefs mount sqlite3://myjfs.db ~/jfs -d

挂载后,任何写入~/jfs的文件都会按「Chunk / Slice / Block」格式拆分成数据块存入底层存储,元数据则写入数据库。卸载使用:

juicefs umount ~/jfs

注意:SQLite 是单文件数据库,挂载时要注意数据库文件路径,相对路径与绝对路径均支持。若希望多台机器同时挂载,需要将 SQLite 换成 Redis、MySQL、PostgreSQL 等可通过网络被多端并发读写的引擎——这正是从单机模式走向分布式模式的关键一步。

4. 接入对象存储的完整示例

将本地存储替换为真实对象存储(以阿里云 OSS 为例):

juicefs format --storage oss \ --bucket https://myjfs.oss-cn-shanghai.aliyuncs.com \ --access-key ABCDEFGHIJKLMNopqXYZ \ --secret-key ZYXwvutsrqpoNMLkJiHgfeDCBA \ sqlite3://myjfs.db myjfs

其中--storage指定存储类型,--bucket指定 Endpoint,--access-key/--secret-key指定访问密钥。由于这些信息在format阶段已写入元数据库,后续mount命令与本地模式完全相同。所有子命令与命令行参数的完整索引见 命令参考。

5. 容器、Kubernetes 与大数据生态

  • 容器:JuiceFS 可以为 Docker、Podman 等容器化技术提供持久化存储,见 Docker 使用文档;
  • Kubernetes:通过 CSI 驱动便捷地用于 Kubernetes,见 Kubernetes 使用文档;
  • Hadoop:通过 Hadoop Java SDK 与 Hadoop 生态结合,替代 HDFS;
  • Python:通过 Python SDK 在进程内直接访问文件系统。

四、POSIX 兼容性

JuiceFS 通过了 pjdfstest 最新版全部8813 项兼容性测试:

All tests successful. Test Summary Report ------------------- /root/soft/pjdfstest/tests/chown/00.t (Wstat: 0 Tests: 1323 Failed: 0) TODO passed: 693, 697, 708-709, 714-715, 729, 733 Files=235, Tests=8813, 233 wallclock secs ( 2.77 usr 0.38 sys + 2.57 cusr 3.93 csys = 9.65 CPU) Result: PASS

除 pjdfstest 覆盖的特性外,JuiceFS 还支持:

  • close-to-open 一致性:文件写入完成并关闭后,之后的打开和读操作保证可以访问之前写入的数据;同一挂载点上所有写入的数据都可以立即读;
  • 原子元数据操作:重命名及所有其他元数据操作都是原子的,由元数据引擎(如 Redis)的事务机制保证;
  • 删除后仍可访问:文件被删除后,同一挂载点上若已打开,文件还可以继续访问;
  • mmap支持;
  • fallocate 与空洞文件支持;
  • 扩展属性支持;
  • BSD 锁(flock)POSIX 记录锁(fcntl)支持。

完整的兼容性说明见 POSIX 兼容性文档。

五、性能测试与性能分析

1. 内置 bench 命令

JuiceFS 提供性能测试子命令帮助了解它在你的环境中的表现:

juicefs bench /path/in/juicefs

实现位于 cmd/bench.go,可测试顺序/随机读写、元数据操作等场景。

2. 顺序读写性能(fio)

使用 fio 测试了 JuiceFS、AWS EFS 和 S3FS 的顺序读写性能,结果显示 JuiceFS 可以提供比另外两者10 倍以上的吞吐:

详细测试方法见 fio 测试文档。

3. 元数据性能(mdtest)

使用 mdtest 测试了 JuiceFS、EFS 和 S3FS 的元数据性能(创建/删除大量小文件的速率),JuiceFS 的元数据性能显著优于另外两者:

详细测试报告见 mdtest 文档,客户端的 mdtest 实现位于 cmd/mdtest.go。

4. 性能分析

如遇性能问题,可以使用「实时性能监控」能力(Prometheus 指标 + Grafana),见 故障诊断和分析 文档中的 性能监控 章节。

六、支持的对象存储

JuiceFS 支持几乎所有主流的对象存储服务,README 列出的包括:

  • 亚马逊 S3
  • 谷歌云存储(GCS)
  • 微软云存储(Azure)
  • 阿里云 OSS
  • 腾讯云 COS
  • 青云 QingStor 对象存储
  • Ceph RGW
  • MinIO
  • 本地目录
  • Redis
  • ……

从 pkg/object/ 目录中的后端实现文件可以更完整地看到覆盖面:s3.go、gs.go、azure.go、oss.go、cos.go、qingstor.go、ceph.go、minio.go、file.go、redis.go、hdfs.go、nfs.go、sftp.go、webdav.go 等。完整列表见 支持的存储服务。

此外,pkg/object/sharding.go 提供了--shards分片能力(按 key 哈希把 Block 分散到多个 bucket),pkg/object/encrypt.go 则提供了透明数据加密包装层,二者都构建在统一存储接口之上。

七、使用量收集与禁用方式

JuiceFS 客户端会收集匿名使用数据,用于了解社区的使用情况。从 pkg/usage/usage.go 可以看到实际上报的字段仅包括:

type usage struct { VolumeID string `json:"volumeID"` SessionID int64 `json:"sessionID"` UsedSpace int64 `json:"usedBytes"` UsedInodes int64 `json:"usedInodes"` Version string `json:"version"` Uptime int64 `json:"uptime"` MetaEngine string `json:"metaEngine"` // 元数据引擎类型 DataStore string `json:"dataStore"` // 对象存储类型 }

即只上报版本号、卷使用量、运行时长等统计数据,不包含任何用户信息。如需禁用,在挂载时加上--no-usage-report参数即可(该选项定义于 cmd/flags.go#L370):

juicefs mount --no-usage-report ...

八、常见问题(FAQ)

为什么不支持某个对象存储?

已支持绝大部分对象存储(见 列表)。如果目标存储与 S3 协议兼容,也可以直接当作 S3 来使用(--storage s3并指向对应 Endpoint)。否则欢迎提交 issue 增加支持。

是否可以使用 Redis 集群版作为元数据引擎?

可以。自 v1.0.0 Beta3 版本开始,JuiceFS 支持使用 Redis 集群版(Cluster)作为元数据引擎。但需要注意的是:Redis 集群版要求一个事务中所有操作的 key 必须在同一个 hash slot 中,因此一个 JuiceFS 文件系统只能使用一个 hash slot。更多细节见 Redis 最佳实践 与 常见问题。

JuiceFS 与同类技术的区别是什么?

可参考 同类技术对比 文档。

九、路线图、社区与开源协议

产品路线图(来自 README):

  • 基于用户和组的配额——从源码结构看,format 结构体中已存在UserGroupQuota字段(cmd/format.go#L528),且仓库提供了 quota 命令 与目录配额实现,该特性正在逐步落地;
  • 快照(Snapshot);
  • 一次写入多次读取(WORM)。

社区与生产验证:JuiceFS 已用于生产环境,使用者名单维护在 ADOPTERS_CN.md(英文见 ADOPTERS.md),并与多个开源项目有集成合作。JuiceFS 的存储格式已经稳定,会被后续发布的所有版本支持。问题反馈通过 GitHub Issues 管理,贡献指南见 CONTRIBUTING.md 与 贡献指南文档。

开源协议:使用 Apache License 2.0 开源,详见 LICENSE。

致谢:JuiceFS 的设计参考了 Google File System、HDFS 以及 MooseFS。

十、延伸阅读

  • 技术架构详解:客户端各接入方式、Chunk/Slice/Block 存储细节、碎片合并原理;
  • 单机模式快速上手 / 分布式模式;
  • 缓存调优:本地磁盘/内存缓存、预读与元数据缓存配置;
  • S3 网关;
  • FUSE 挂载选项;
  • 在 Windows 中使用 JuiceFS;
  • 故障诊断和分析;
  • 内部实现(开发视角)。

【免费下载链接】juicefsJuiceFS is a distributed POSIX file system built on top of Redis and S3.项目地址: https://gitcode.com/GitHub_Trending/ju/juicefs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询