分布式文件夹系统
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 \
myjfsjuicefs 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 \
myjfsjuicefs mount -d sqlite3:///home/k/jfs-meta/myjfs.db /mnt/jfsSQLite 元数据引擎的路径写法
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,例如 @ -> %40storage 参数支持的存储类型
format/mount 的 --storage 指定实际存数据的对象存储后端,官方文档完整列表:https://juicefs.com/docs/community/reference/how_to_set_up_object_storage
| 分类 | storage 值 | 说明 |
|---|---|---|
| 公有云对象存储 | s3 | Amazon S3、Oracle 云、Vultr、Cloudflare R2、JD 云 OSS、Ceph RGW、Apache Ozone、Telnyx 等兼容 S3 协议的服务均用 s3 |
gs | Google Cloud Storage | |
wasb | Azure Blob Storage | |
b2 | Backblaze B2 | |
ibmcos | IBM 云对象存储 | |
scw | Scaleway Object Storage | |
space | DigitalOcean Spaces | |
wasabi | Wasabi | |
storj | Storj | |
bunny | Bunny Storage | |
oss | 阿里云 OSS | |
cos | 腾讯云 COS | |
obs | 华为云 OBS | |
bos | 百度智能云 BOS | |
tos | 火山引擎 TOS | |
ks3 | 金山云 KS3 | |
qingstor | 青云 QingStor | |
qiniu | 七牛云 Kodo | |
oos | 天翼云 OOS | |
eos | 移动云 EOS | |
ufile | 优刻得 US3 | |
| 自建/私有部署 | minio | MinIO(本文档示例用的就是这个) |
ceph | Ceph RADOS(librados 原生接口) | |
gluster | GlusterFS | |
swift | OpenStack Swift | |
webdav | WebDAV | |
hdfs | HDFS | |
sftp | SFTP/SSH | |
cifs | CIFS/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.confsudo 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 = yessudo apt install -y samba # 或 sudo yum install -y samba
sudo smbpasswd -a k # 单独设置 SMB 登录密码,与系统密码无关
sudo systemctl enable --now smbdWindows 端:此电脑 → 映射网络驱动器 → 路径填 \\<Linux IP>\shared → 勾选"使用其他凭据连接" → 用户名 k + 上面设置的 Samba 密码。
效果
Windows 侧是原生网络驱动器体验,读写/重命名/拖拽不卡顿;Linux 侧文件属主始终是 k:k,本地脚本/程序读写无需 sudo。