尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

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

JuiceFS 分布式 POSIX 文件系统:架构原理、快速上手与源码级解析 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/ 则实现了 Redisredis.go、SQL 系sql.go、sql_mysql.go、sql_pg.go、sql_sqlite.go、TiKVtkv_tikv.go、etcd、FoundationDB、Badger 等多种元数据引擎。核心特性官方 README 列出的十大核心特性如下POSIX 兼容像本地文件系统一样使用无缝对接已有应用无业务侵入性HDFS 兼容完整兼容 HDFS API提供更强的元数据性能可参考 Hadoop Java SDK 文档S3 兼容提供 S3 网关实现 S3 协议兼容的访问接口实现位于 pkg/gateway/云原生通过 Kubernetes CSI 驱动可以很便捷地在 Kubernetes 中使用 JuiceFS参见 Kubernetes 使用指南多端共享同一文件系统可在上千台服务器同时挂载高性能并发读写共享数据强一致性确认的修改会在所有挂载了同一文件系统的服务器上立即可见强悍性能毫秒级的延迟吞吐上限取决于对象存储规模测试方法见 性能测试数据安全支持传输中加密encryption in transit以及静态加密encryption at rest实现见 pkg/object/encrypt.go文件锁支持 BSD 锁flock及 POSIX 锁fcntl数据压缩支持使用 LZ4 或 Zstandard 压缩数据节省存储空间压缩算法实现位于 pkg/compress/compress.go。二、架构三大组成部分JuiceFS 由三个部分组成JuiceFS 客户端协调对象存储和元数据存储引擎并实现 POSIX、Hadoop、Kubernetes、S3 Gateway 等文件系统接口数据存储存储数据本身支持本地磁盘、对象存储元数据引擎存储数据对应的元数据支持 Redis、MySQL、SQLite 等多种引擎。从 技术架构文档 可以进一步看到客户端支持的多种接入方式通过FUSE以 POSIX 方式挂载实现位于 pkg/fuse/、通过Python SDK在进程内直接访问、通过Windows 客户端WinFSP实现位于 pkg/winfsp/、通过Hadoop Java SDK替代 HDFSsdk/java/、通过Kubernetes CSI 驱动、通过S3 网关cmd/gateway.go以及WebDAV 服务cmd/webdav.go。元数据引擎中存储的内容包括两类常规文件系统的元数据文件名、文件大小、权限信息、创建修改时间、目录结构、文件属性、符号链接、文件锁等文件数据的索引文件的数据分配和引用计数、客户端会话等。文件如何被存储Chunk、Slice 与 Block任何存入 JuiceFS 的文件都会被拆分成固定大小的Chunk默认容量上限是64 MiB。这一数值在源码中是硬编码的常量见 pkg/meta/interface.goChunkSize 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 中仅包含一个 SliceBlock每个 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 个方面的准备准备元数据数据库Redis、MySQL、SQLite 等选择方式见 元数据引擎设置指南准备对象存储选择与配置见 对象存储设置指南下载安装 JuiceFS 客户端安装方式见 安装文档。2. format创建文件系统format命令的通用格式为juicefs format [command options] META-URL NAME需要提供的三种信息[command options]设定文件系统的存储介质留空则默认使用本地磁盘作为存储介质路径为$HOME/.juicefs/localmacOS、/var/jfsLinux或C:/jfs/localWindowsMETA-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_PASSWORDmypassword 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对象存储类型如s3、gs、oss、cos--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压缩算法lz4、zstd、none--encrypt-rsa-key-RSA 私钥文件路径PEM 格式用于数据静态加密--encrypt-algoaes256gcm-rsa加密算法aes256gcm-rsa、chacha20-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]$即仅允许小写字母、数字和连字符长度 363 个字符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挂载到~/jfsjuicefs 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 生态结合替代 HDFSPython通过 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 Files235, Tests8813, 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 RGWMinIO本地目录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 分散到多个 bucketpkg/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#L370juicefs 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),仅供参考
返回列表