Skip to main content

技术架构

如下图所示,JuiceFS 由三大组件构成:JuiceFS 客户端元数据引擎数据存储。后续章节将逐一详细介绍。

JuiceFS-arch

JuiceFS 客户端(Client)

JuiceFS 采用「富客户端」设计,因此 JuiceFS 客户端是文件系统中的重要组成部分:所有文件读写,包括碎片合并、回收站文件过期删除等后台任务,均在客户端中发起执行。因此 JuiceFS 客户端需要同时与元数据引擎和数据存储进行通信。服务端(也就是下面将会介绍的「元数据引擎」)不会也不能直接修改任何文件系统数据。

客户端支持众多接入方式,包括:

  • 通过 FUSE:JuiceFS 文件系统能够以 POSIX 兼容的方式挂载到服务器,将海量云端存储直接当做本地存储来使用。点击此处查看使用详情。
  • 通过 Python SDK:在无法通过 FUSE 挂载,或需要在 Python 进程中直接访问文件系统的场景,可以使用 Python SDK 直接读写文件系统。此外,Python SDK 原生实现了 fsspec 便于接入 Ray 等框架。点击此处查看使用详情。
  • 通过 Windows 客户端:获得接近本地文件系统的体验。点击此处查看使用详情。
  • 通过 Hadoop Java SDK:JuiceFS 文件系统能够直接替代 HDFS,为 Hadoop 提供低成本的海量存储。点击此处查看使用细节。
  • 通过 Kubernetes CSI 驱动:JuiceFS 文件系统能够直接为 Kubernetes 提供海量存储。点击此处查看 JuiceFS CSI 文档。
  • 通过 S3 网关:使用 S3 作为存储层的应用可直接接入,同时可使用 AWS CLI、s3cmd、MinIO client 等工具访问 JuiceFS 文件系统,已有的支持 S3 应用可直接无缝接入。点击此处查看使用详情。
  • 通过 WebDAV 服务:以 HTTP 协议,以类似 RESTful API 的方式接入 JuiceFS 并直接操作其中的文件。点击此处查看使用详情。

元数据引擎(Metadata Engine)

如上架构图所示,JuiceFS 企业版和云服务采用 Juicedata 自研的高性能元数据引擎。该元数据引擎存储文件元数据,包含以下内容:

  • 常规文件系统的元数据:文件名、文件大小、权限信息、创建修改时间、目录结构、文件属性、符号链接、文件锁等。
  • JuiceFS 独有的元数据:文件的 Chunk 及 Slice 映射关系、客户端会话等。

Juicedata 已经在大多数公有云都部署了元数据服务,供云服务用户开箱即用。作为 JuiceFS 云服务用户,您将通过公网使用元数据服务(建议在同一区域以获得最佳性能)。若您大规模使用 JuiceFS 并需要更低的访问延迟,可联系 Juicedata 团队,通过 VPC 对等连接提供私有网络支持。

元数据服务是一个基于 Raft 协议的高可用集群,所有元数据操作均以变更日志(changelog)形式进行追加(这也让类似「实时数据保护」这样的高级数据安全功能成为可能)。一个 Raft 组由 3 个节点组成,包含 Leader 和 Follower 两种角色,通过 Raft 共识算法进行数据复制,确保元数据的强一致性和服务的高可用。

single-zone

一个 Raft 组构成一个 JuiceFS 元数据分区。目前单分区元数据服务适用于索引节点(inode)不超过 2 亿的场景。如需支持更大量级的数据规模,可使用我们的多分区元数据服务(目前仅在私有部署提供),通过增加分区来实现元数据服务的水平拓展。

multi-zone

在多分区模式下,JuiceFS 能在单一命名空间支撑千亿级文件存储,每个分区内的架构与单分区相同。不同分区的节点可以混部在相同的机器上,分区数支持动态调整,分区间的元数据也支持动态迁移(自动或者手动负载均衡),来满足高负载业务访问场景,从而有效避免数据热点引发的性能问题。这一系列功能均可通过 JuiceFS Web 控制台进行管理和监控,满足企业运维需求。而对于 JuiceFS 客户端,访问多分区元数据服务也与单分区无异,能同时读写不同分区的数据,并自动感知分区拓扑变化。

数据存储(Data Storage)

传统文件系统将文件数据和元数据都存储在本地磁盘上。而 JuiceFS 则将文件数据存储在对象存储中,将对应的元数据存储在元数据引擎中。前文提到 JuiceFS 客户端会分别与元数据引擎和数据存储进行通信,而元数据引擎则与对象存储完全解耦,既不关心也不会访问对象存储服务,所有实际文件数据均存放在您选择的对象存储上。

您可以使用公有云服务提供的对象存储,也可以使用自建的解决方案。JuiceFS 支持几乎所有类型的对象存储,包括 Amazon S3、Google Cloud Storage(GCS)、Azure Blob 等公有云选项,以及 OpenStack Swift、Ceph、MinIO 等私有化方案。这些都在「设置对象存储」中有详细介绍。

JuiceFS 如何存储文件

在 JuiceFS 处理实际文件数据时,ChunkSliceBlock 是三个重要的概念。

每个文件由一个或多个「Chunk」组成,每个 Chunk 最大为 64 MiB。不论文件有多大,所有读写操作都会根据其偏移量(也就是产生读写操作的文件位置)来定位到对应的 Chunk。正是这种分而治之的设计,让 JuiceFS 面对大文件时也有优秀的性能。只要文件总长度保持不变,不论经历多少修改写入,文件的 Chunk 切分都是固定的。

File and chunks

Chunk 的存在是为了优化查找定位,实际的文件写入则在「Slice」上进行。在 JuiceFS 中,一个 Slice 代表一次连续写入,隶属于某个 Chunk,并且不能跨越 Chunk 边界,因此 Slice 长度也不会超 64MiB。

举例说明,如果一个文件是由一次连贯的顺序写生成,那么每个 Chunk 中仅包含一个 Slice。上方的示意图就属于这种情况:顺序写入一个 160MiB 的文件,最终会产生三个 Chunk,而每个 Chunk 仅包含一个 Slice。

文件写入会产生 Slice,而调用 flush 则会将这些 Slice 持久化。flush 可以被用户显式调用,就算不调用,JuiceFS 客户端也会自动在恰当的时机进行 flush,防止缓冲区被写满。持久化到对象存储时,为了能够尽快写入,会将 Slice 进一步拆分为多个「Block」(默认最大 4MiB)并利用多线程并发写入来提升写性能。上边介绍的 Chunk 和 Slice 其实都是逻辑数据结构,而 Block 则是最终的物理存储形式,是对象存储和磁盘缓存的最小存储单元。

Split slices to blocks

将文件写入 JuiceFS 后,您无法在对象存储中直接找到原始文件。实际上存储桶中只有一个 chunks 目录和一系列以数字编号的目录和文件,让人不禁疑惑「我的文件到底去了哪儿?」。这些以数字编号的对象存储文件正是经过 JuiceFS 拆分存储的 Block。而这些 Block 与 Chunk、Slice 的对应关系,以及其他元数据信息(比如文件名、大小等属性)均存储在元数据引擎中。这种解耦设计让 JuiceFS 文件系统得以高性能运作。

How JuiceFS stores files

回到逻辑数据结构的话题,如果文件并不是由连贯的顺序写生成,而是多次追加写,每次追加均调用 flush 触发写入上传,就会产生多个 Slice。如果每次追加写入的数据量不足 4MiB,那么最终存入对象存储的数据块,也会是一个个小于 4MiB 的 Block。

Small append writes

取决于写入模式,Slice 的排列模式可以是多种多样的:

  • 如果文件在相同区域被反复修改,Slice 之间会发生重叠。
  • 如果在互不重合的区域进行写入,Slice 中间会有间隔。

但不论 Slice 的排列有多复杂,当读取文件时,对于每一处文件位置,都会读到该位置最新写入的 Slice,用下图可以更加直观地理解:Slice 虽然会相互堆叠,但读文件一定是「从上往下看」,因此一定会看到该文件的最新状态。

Complicate pattern

正是由于 Slice 会相互覆盖,JuiceFS 在 Chunk 与 Slice 的引用关系中标记了各个 Slice 的有效数据偏移范围(内部实现可以参考社区版文档,企业版的设计类似),用这种方式告诉文件系统,每一个 Slice 中的哪些部分是有效的数据。

但也不难想象,读取文件需要查找「当前读取范围内最新写入的 Slice」,在上图所示的大量堆叠 Slice 的情况下,这样的反复查找将会显著影响读性能,我们称之为文件「碎片化」。碎片化不仅影响读性能,还会在各个层面(对象存储、元数据)增加空间占用。因此每当写入发生时,客户端都会判断文件的碎片化情况,并在后台任务中运行碎片合并,将同一个 Chunk 内的所有 Slice 合并为一。

compaction

JuiceFS 的存储设计,还有着以下技术特点:

  • 为了避免读放大,JuiceFS 不对文件进行合并存储。但也存在例外:遇到大量写入小文件时,会合并写入对象存储块以提升写入性能,然后在「碎片合并」任务中进行拆分。
  • JuiceFS 提供强一致性保证,同时可根据场景需要与缓存功能一起调优。比如通过设置更激进的元数据缓存,牺牲一部分一致性,换取更好的性能。详见「元数据缓存」
  • JuiceFS 支持并默认开启「回收站」功能,删除文件后保留一段时间才彻底清理,最大程度避免误删文件引发事故。