分布式文件夹系统

juicefs

云原生分布式文件系统,将元数据和数据分离存储:元数据存于数据库(Redis/MySQL/TiKV 等),数据存于对象存储(S3/OSS/MinIO 等),对外提供 POSIX / HDFS / S3 / CSI 等多种访问方式。

仓库地址:https://github.com/juicedata/juicefs 文档:https://juicefs.com/docs/zh/community/introduction

架构

graph LR
    Client[JuiceFS Client<br/>POSIX/FUSE/HDFS/S3 Gateway] --> Meta[元数据引擎<br/>Redis/MySQL/TiKV/SQLite]
    Client --> Obj[对象存储<br/>S3/OSS/MinIO/本地磁盘]
  • 元数据引擎:只存文件名、目录树、权限、文件与数据块的映射等元数据,不存实际数据;决定了元数据操作的性能上限。
  • 数据存储:文件按 chunk(默认 64MiB)→ slice → block(默认 4MiB)切分后上传到对象存储,实际数据不经过元数据引擎。
  • 客户端:负责数据切分、压缩、加密、缓存,直接与元数据引擎和对象存储通信,多个客户端挂载同一文件系统可实现共享读写。

安装

curl -sSL https://d.juicefs.com/install | sh -

创建与挂载文件系统

juicefs format \
    --storage minio \
    --bucket http://127.0.0.1:9000/myjfs \
    --access-key <ak> \
    --secret-key <sk> \
    redis://127.0.0.1:6379/1 \
    myjfs
juicefs mount -d redis://127.0.0.1:6379/1 /mnt/jfs
关于 format 的 name 参数

format 最后的 <name> 是文件系统名字,会写入元数据引擎;mount 不需要再传 name,客户端会从 meta-url 指向的元数据存储里自动读出。 一个 meta-url(如某个 Redis db 编号 / 某个 MySQL database)只能对应一个文件系统,重复 format 会报错或需要 --force 覆盖(危险操作)。要跑多个独立文件系统,需用不同 db 编号或不同 database 名分别 format,例如 redis://host:6379/1 和 redis://host:6379/2。

juicefs format \
    --storage minio \
    --bucket http://127.0.0.1:9000/myjfs \
    --access-key <ak> \
    --secret-key <sk> \
    sqlite3:///home/k/jfs-meta/myjfs.db \
    myjfs
juicefs mount -d sqlite3:///home/k/jfs-meta/myjfs.db /mnt/jfs
SQLite 元数据引擎的路径写法

sqlite3:// 后跟的是本地 db 文件路径:相对路径直接写 sqlite3://myjfs.db(相对当前工作目录),绝对路径要写三个斜杠,即 sqlite3:///绝对路径/myjfs.db(sqlite3:// + 绝对路径本身的 /)。db 文件所在目录需提前创建好且有写权限;同一个 db 文件同一时刻只能被一个客户端挂载(SQLite 不支持多机并发写),仅适合单机场景。

# 只有密码,无用户名(Redis < 6.0 常见),注意冒号不能省
juicefs mount -d redis://:<password>@127.0.0.1:6379/1 /mnt/jfs

# 有用户名+密码(Redis 6+ ACL)
juicefs mount -d redis://<username>:<password>@127.0.0.1:6379/1 /mnt/jfs

# 更安全:用环境变量传密码,避免明文出现在 shell 历史/ps 中
export META_PASSWORD=<password>
juicefs mount -d redis://127.0.0.1:6379/1 /mnt/jfs
# 若同时有用户名,URL 中仍需保留 username@,密码从环境变量读取
juicefs mount -d redis://<username>@127.0.0.1:6379/1 /mnt/jfs

# 密码含 @ : / 等特殊字符时需 URL encode,例如 @ -> %40

storage 参数支持的存储类型

format/mount 的 --storage 指定实际存数据的对象存储后端,官方文档完整列表:https://juicefs.com/docs/community/reference/how_to_set_up_object_storage

分类storage 值说明
公有云对象存储s3Amazon S3、Oracle 云、Vultr、Cloudflare R2、JD 云 OSS、Ceph RGW、Apache Ozone、Telnyx 等兼容 S3 协议的服务均用 s3
gsGoogle Cloud Storage
wasbAzure Blob Storage
b2Backblaze B2
ibmcosIBM 云对象存储
scwScaleway Object Storage
spaceDigitalOcean Spaces
wasabiWasabi
storjStorj
bunnyBunny Storage
oss阿里云 OSS
cos腾讯云 COS
obs华为云 OBS
bos百度智能云 BOS
tos火山引擎 TOS
ks3金山云 KS3
qingstor青云 QingStor
qiniu七牛云 Kodo
oos天翼云 OOS
eos移动云 EOS
ufile优刻得 US3
自建/私有部署minioMinIO(本文档示例用的就是这个)
cephCeph RADOS(librados 原生接口)
glusterGlusterFS
swiftOpenStack Swift
webdavWebDAV
hdfsHDFS
sftpSFTP/SSH
cifsCIFS/SMB
file本地磁盘(单机测试用)
数据库兼作对象存储redis、tikv、etcd、sqlite3、mysql、postgres这几个既能做元数据引擎(跟在 meta-url 位置),也能单独作为 --storage 把数据本身存进去(一般只用于小规模测试,性能/容量远不如真正的对象存储)
–storage、–bucket、–access-key/–secret-key 的关系

--storage 只决定用哪种协议/SDK 访问,真正的连接地址在 --bucket(如 --bucket https://myjuicefs.s3.us-east-2.amazonaws.com),鉴权信息在 --access-key/--secret-key。--bucket 后面也支持拼 URL 参数做细节控制,例如 ?tls-insecure-skip-verify=true 跳过证书校验。

元数据引擎选择

引擎特点适用场景
Redis性能最高,全内存小规模、追求极致性能,需自行保证持久化/高可用
MySQL/PostgreSQL运维成熟,事务保证强团队已有关系型数据库运维经验
TiKV分布式、可水平扩展海量文件(十亿级+)、大规模生产
SQLite单机、零依赖本地测试、单机场景

常用管理命令

juicefs status redis://127.0.0.1:6379/1
# 单个文件/目录的内部信息(inode、chunk 分布等)
juicefs info /mnt/jfs/somefile

# 目录树的文件数/大小汇总
juicefs summary /mnt/jfs/somedir

# 挂载后是普通文件系统,可直接用系统自带的 df 查看空间占用
df -h /mnt/jfs
为什么 df 显示 1P

底层是对象存储,本身没有固定容量上限,未设置 --capacity 时默认用 1 PiB 占位显示,不代表真实可用空间。可通过容量配额设置为具体值:

# format 时指定容量(单位 GiB)
juicefs format ... --capacity 1024 redis://127.0.0.1:6379/1 myjfs

# 对已有文件系统修改容量配额
juicefs config redis://127.0.0.1:6379/1 --capacity 2048

超过配额后写入会被拒绝;设为 0(默认)表示不限制。

juicefs umount /mnt/jfs
# 元数据导出为 json,可用于迁移/灾备
juicefs dump redis://127.0.0.1:6379/1 meta.dump.json

# 从备份恢复元数据到新的元数据引擎
juicefs load redis://127.0.0.1:6379/2 meta.dump.json
# 默认删除的文件会进入 .trash,保留一段时间后自动清理
juicefs gc redis://127.0.0.1:6379/1
# trash-days 默认 1(删除的文件保留1天再清理),设为 0 即关闭回收站,rm 直接删除
juicefs config redis://127.0.0.1:6379/1 --trash-days 0

# 或者调整保留时长,比如保留 7 天
juicefs config redis://127.0.0.1:6379/1 --trash-days 7
关闭/缩短保留期后误删文件无法再用 juicefs restore 找回,请谨慎操作。

本地缓存

# 客户端本地磁盘缓存加速热数据读取,--cache-dir 指定缓存目录,--cache-size 指定上限(MiB)
juicefs mount -d --cache-dir /var/jfsCache --cache-size 102400 redis://127.0.0.1:6379/1 /mnt/jfs
拷贝完数据发现 cache-dir 是空的?

默认情况下本地缓存主要是读缓存:写入的数据直接同步上传到对象存储,不会顺带进本地缓存,只有读取时才会缓存该 block。所以刚拷完没读过是正常的,不代表配置没生效。

  • 验证方法:先 cat 读一下文件,再看 <cache-dir>/<uuid>/raw/ 下是否有内容,或者用 juicefs stats /mnt/jfs 实时看 blockcache 命中/写入次数。
  • 若想让写入也立刻进本地缓存(先写本地再异步上传),需要加 --writeback(回写模式),但要注意上传完成前本地磁盘损坏会丢数据。
对象存储后端是机械硬盘时,小文件写入建议加 –writeback

对象存储后端(如自建 RustFS)跑在机械硬盘上时,默认同步写入模式下大量小文件是一个一个同步上传,很慢。加上 --writeback 后写入先落 --cache-dir 本地缓存、立即返回,再由后台异步上传,小文件写入速度接近本地磁盘,对 Linux 本地读写和通过 Samba 共享给 Windows 都有效。 权衡同上:数据在异步上传完成前只存在本地缓存里,本地磁盘损坏/机器断电会丢失尚未上传的部分,对可靠性要求高的数据不建议开。

ps aux | grep '[j]uicefs mount'        # 确认挂载进程带上了 cache-dir 参数
cat /mnt/jfs/somefile > /dev/null      # 触发一次读取
find /var/jfsCache/ -type f | head     # 查看缓存目录(注意有一层 UUID 子目录)
juicefs stats /mnt/jfs                 # 实时查看缓存命中率

其他访问方式

  • Hadoop SDK:作为 HDFS 的兼容实现接入大数据生态(Hive/Spark/Presto 等)。
  • S3 Gateway:juicefs gateway 启动一个兼容 S3 协议的网关,供已有 S3 客户端/工具直接访问。
  • CSI Driver:juicefs-csi-driver,供 Kubernetes 以 PV/PVC 方式挂载使用,参考 Kubernetes。
  • Fuse 挂载:标准 POSIX 接口,可当作普通本地目录使用。

Windows 共享方案:Linux 挂载 + Samba

为什么不直接用 WinFsp 在 Windows 上挂载

Windows 直接通过 WinFsp 挂载 JuiceFS 会导致 Windows SID 与 Linux POSIX 权限体系冲突,实测权限非常乱、难以使用。更稳的方案是:只在 Linux 端挂载 JuiceFS,再用 Linux 原生 Samba 把挂载点共享给 Windows,Windows 侧当作普通网络驱动器访问即可。

graph LR
    Win[Windows 客户端] -->|SMB 映射网络驱动器| Smb[Linux smbd]
    Smb -->|本地 POSIX 访问| Mnt[JuiceFS FUSE 挂载点<br/>allow_other + all-squash]
    Mnt --> Meta[元数据引擎]
    Mnt --> Obj[对象存储]

要点:非 root 挂载 FUSE 时内核默认会隔离其他进程(包括 smbd),所以挂载时必须加 allow_other;再用 --all-squash 把所有访问统一映射为同一个本地用户,避免 Samba 侧出现权限混乱。

sudo sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf
sudo mkdir -p /var/jfsCache && sudo chown -R $(id -u):$(id -g) /var/jfsCache
mkdir -p /home/k/shared

juicefs mount -d \
    -o allow_other \
    --all-squash $(id -u):$(id -g) \
    --cache-dir /var/jfsCache \
    --cache-size 51200 \
    redis://:<password>@192.168.111.111:6379/1 /home/k/shared
后端是机械硬盘、小文件多的话

参考前面 本地缓存 一节,加上 --writeback 可以显著加速小文件写入。

[shared]
   comment = JuiceFS Storage via Samba
   path = /home/k/shared
   browseable = yes
   read only = no
   guest ok = no
   create mask = 0775
   directory mask = 0775
   force user = k
   force group = k
   kernel oplocks = no
   follow symlinks = yes
   wide links = yes
sudo apt install -y samba        # 或 sudo yum install -y samba
sudo smbpasswd -a k              # 单独设置 SMB 登录密码,与系统密码无关
sudo systemctl enable --now smbd

Windows 端:此电脑 → 映射网络驱动器 → 路径填 \\<Linux IP>\shared → 勾选"使用其他凭据连接" → 用户名 k + 上面设置的 Samba 密码。

效果

Windows 侧是原生网络驱动器体验,读写/重命名/拖拽不卡顿;Linux 侧文件属主始终是 k:k,本地脚本/程序读写无需 sudo。