JuiceFS 目录用量统计(Dir Stats)实战指南:启用、查看与修复
【免费下载链接】juicefsJuiceFS is a distributed POSIX file system built on top of Redis and S3.项目地址: https://gitcode.com/GitHub_Trending/ju/juicefs
JuiceFS 从 v1.1.0 起内置了目录用量统计(Directory Usage Stats)能力,在每个目录的元数据上异步维护"数据长度、占用空间、文件数"三组统计值,从而让quota、info、summary等子命令可以秒级返回结果。本文以 docs/zh_cn/guide/dir-stats.md 为骨架,结合仓库源码,完整讲解目录用量统计的启用与禁用、单层/递归/树形查看方式、快速模式与严苛模式的差异,以及统计值丢失时的fsck诊断与修复流程。
目录用量统计是什么
目录用量统计是 JuiceFS 元数据引擎中的一组按目录维护的预计算指标。启用后,每个目录都会保存以下三个数值(见 pkg/meta/quota.go 中dirStat结构体定义):
| 字段 | 含义 |
|---|---|
length | 目录下所有文件的逻辑数据长度(字节) |
space | 按 4KiB 对齐后的实际占用空间(字节) |
inodes | 目录下的文件与子目录数量(inode 数) |
这组数值由挂载客户端在文件写入、删除、重命名、截断等元数据操作发生时异步累加更新,写入元数据引擎对应的 Hash 存储中(Redis 引擎对应dirDataLengthKey、dirUsedSpaceKey、dirUsedInodesKey三个 Hash,见 pkg/meta/redis.go 的doUpdateDirStat实现;SQL 引擎与 TKV 引擎在 pkg/meta/sql.go 和 pkg/meta/tkv.go 有等价实现)。
由于统计是异步的,启用后会带来少量额外开销;但换来的是quota、info、summary等命令不再需要现场遍历目录树,而是直接读取预计算值,速度大幅提升。
注意:目录用量统计依赖挂载客户端配合,启用前请确保所有可写入客户端均已升级到 v1.1.0 以上版本,否则旧客户端写入时无法同步更新统计值。
启用与禁用目录用量统计
新文件系统默认开启
使用juicefs format创建文件系统时,DirStats默认即为开启状态。在 cmd/format.go 中可以看到格式化时构建的 Format 结构体直接写死了DirStats: true:
DirStats: true, UserGroupQuota: false, MetaVersion: meta.MaxVersion, MinClientVersion: "1.1.0-A",也就是说,v1.1.0 之后格式化的 volume 无需任何额外配置即可使用目录用量统计。而旧版本创建、随后迁移到新版本的 volume,其DirStats保持为false,需要手动开启。
用 config 命令开关
运行juicefs config $URL --dir-stats即可为存量 volume 开启目录统计,其中$URL是元数据引擎地址(如redis://localhost)。config子命令的--dir-stats参数定义在 cmd/config.go,帮助信息写得很直白:"enable dir stats, which is necessary for fast summary and dir quota"——它同时是快速summary和目录配额的前置依赖。
$ juicefs config redis://localhost --dir-stats再次执行juicefs config redis://localhost(不带任何修改参数)可以查看当前配置,确认"DirStats": true已生效:
$ juicefs config redis://localhost 2023/05/31 15:56:39.721188 juicefs[30626] <INFO>: Meta address: redis://localhost [interface.go:494] 2023/05/31 15:56:39.723284 juicefs[30626] <INFO>: Ping redis latency: 159.226µs [redis.go:3566] { "Name": "myjfs", "UUID": "82db28de-bf5f-43bf-bba3-eb3535a86c48", "Storage": "file", "Bucket": "/root/.juicefs/local/", "BlockSize": 4096, "Compression": "none", "EncryptAlgo": "aes256gcm-rsa", "TrashDays": 1, "MetaVersion": 1, "DirStats": true }如需禁用,传入--dir-stats=false:
$ juicefs config redis://localhost --dir-stats=false 2023/05/31 15:59:39.046134 juicefs[30752] <INFO>: Meta address: redis://localhost [interface.go:494] 2023/05/31 15:59:39.048301 juicefs[30752] <INFO>: Ping redis latency: 171.308µs [redis.go:3566] dir-stats: true -> false禁用限制:目录配额存在时无法关闭
目录用量统计是目录配额功能的基础。为目录设置配额时会自动开启目录用量统计;反过来,只要 volume 上还存在任何目录配额,就无法禁用目录用量统计。
这一点在源码中有强约束:config命令处理dir-stats修改时,会先通过HandleQuota列出全部目录配额,若发现仍有残留配额,直接返回错误(见 cmd/config.go):
if originDirStats && !format.DirStats { qs := make(map[string]*meta.Quota) err := m.HandleQuota(meta.Background(), meta.QuotaList, "", meta.DirQuotaType, qs, false, false, false) ... return fmt.Errorf("cannot disable dir stats when there are still %d dir quotas: %v", len(qs), paths) }查看目录统计
单层统计:juicefs info
juicefs info $PATH只读取目标目录单层(不递归)的统计用量,数据直接来自预计算的dirStat:
$ juicefs info /mnt/jfs/pjdfstest/ /mnt/jfs/pjdfstest/ : inode: 2 files: 10 dirs: 4 length: 43.74 KiB (44794 Bytes) size: 92.00 KiB (94208 Bytes) path: /pjdfstest其中length是逻辑长度,size是 4KiB 对齐后的实际占用,files与dirs之和即为inodes统计值。
递归统计:juicefs info -r
如需递归遍历并汇总整个目录树,使用juicefs info -r $PATH:
$ juicefs info -r /mnt/jfs/pjdfstest/ /mnt/jfs/pjdfstest/: 278 921.0/s /mnt/jfs/pjdfstest/: 1.6 MiB (1642496 Bytes) 5.2 MiB/s /mnt/jfs/pjdfstest/ : inode: 2 files: 278 dirs: 37 length: 592.42 KiB (606638 Bytes) size: 1.57 MiB (1642496 Bytes) path: /pjdfstest树形统计:juicefs summary
juicefs summary $PATH以表格形式展示各层级的目录用量(默认展示 2 层、按大小排序取前 10 项),比info -r更适合快速定位"哪个子目录占用最大":
$ ./juicefs summary /mnt/jfs/pjdfstest/ /mnt/jfs/pjdfstest/: 315 1044.4/s /mnt/jfs/pjdfstest/: 1.6 MiB (1642496 Bytes) 5.2 MiB/s +------------------+---------+------+-------+ | PATH | SIZE | DIRS | FILES | +------------------+---------+------+-------+ | / | 1.6 MiB | 37 | 278 | | tests/ | 1.1 MiB | 18 | 240 | | tests/open/ | 112 KiB | 1 | 26 | | tests/... | 328 KiB | 7 | 71 | | .git/ | 432 KiB | 17 | 26 | | .git/objects/ | 252 KiB | 3 | 2 | | ... | 12 KiB | 0 | 3 | +------------------+---------+------+-------+summary子命令的参数在 cmd/summary.go 中定义,除--strict外还支持:
| 参数 | 默认值 | 说明 |
|---|---|---|
-d, --depth | 2 | 展示的树深度(0 表示只显示根目录,上限 10) |
-e, --entries | 10 | 按大小排序后展示的 Top N 项(上限 100) |
--strict | false | 严苛模式,实时遍历计算准确汇总(可能较慢) |
--csv | false | 以 CSV 格式输出,便于脚本解析 |
summary的实现通过挂载点控制通道向内核态/用户态挂载进程发送OpSummary请求,由vfs层汇总后以 JSON 返回(cmd/summary.go)。若挂载客户端版本过旧不支持,会报错 "summary is not supported, please upgrade and mount again"。
说明:目录统计只计算每个目录的单层用量。要查看递归总用量需用
juicefs info -r,但大目录的遍历汇总可能带来很大开销。如需持续监控某些特定目录的总用量,可参考目录配额文档,通过设置空配额的方式统计目录总用量(配额未设置上限时仅作统计用途)。
快速模式与严苛模式
由于目录用量是异步统计的,当客户端异常退出、崩溃或中途掉线时,可能丢失部分统计更新,导致预计算值与真实数据不一致。为此,juicefs info、juicefs summary和juicefs quota三个命令都提供了--strict选项:
- 快速模式(默认):直接读取预计算的目录统计值,速度极快,但结果可能因异步丢失而不准确;
- 严苛模式(
--strict):绕过目录统计,现场递归遍历目录树重新计算,结果准确但耗时更长。
在 cmd/summary.go 中可以看到--strict被编码为请求参数下发:
var strict uint8 if ctx.Bool("strict") { strict = 1 }同样的思路也体现在doGetDirStat的trySync参数上:元数据层在严苛模式下检测到统计值缺失或为负(dataLength < 0 || usedSpace < 0 || usedInodes < 0)时,会自动调用doSyncDirStat现场重算并回写(见 pkg/meta/redis.go)。
故障诊断与修复
对比快速模式与严苛模式
如果发现juicefs info、juicefs summary或juicefs quota在快速模式与严苛模式下的结果不一致,说明某些目录的统计值已损坏。以下示例中,目录/jfs/d内只有一个 1 GiB 的文件,但快速模式只统计到 448 MiB:
$ juicefs info -r /jfs/d /jfs/d: 1 3.3/s /jfs/d: 448.0 MiB (469766144 Bytes) 1.4 GiB/s /jfs/d : inode: 2 files: 1 dirs: 1 length: 448.00 MiB (469762048 Bytes) size: 448.00 MiB (469766144 Bytes) path: /d $ juicefs info -r --strict /jfs/d /jfs/d: 1 3.3/s /jfs/d: 1.0 GiB (1073745920 Bytes) 3.3 GiB/s /jfs/d : inode: 2 files: 1 dirs: 1 length: 1.00 GiB (1073741824 Bytes) size: 1.00 GiB (1073745920 Bytes) path: /d显然快速模式的 448 MiB 与严苛模式的 1.0 GiB 不符,说明/d的目录统计已损坏。
用 fsck 检查
此时使用juicefs fsck配合--path /d --sync-dir-stat进行诊断。fsck会遍历指定路径,将每个目录的预计算统计值与现场calcDirStat计算结果比对(逻辑见 pkg/meta/base.go),发现不一致时输出 WARNING:
$ juicefs fsck sqlite3://test.db --path /d --sync-dir-stat 2023/05/31 17:14:34.700239 juicefs[32667] <INFO>: Meta address: sqlite3://test.db [interface.go:494] [xorm] [info] 2023/05/31 17:14:34.700291 PING DATABASE sqlite3 2023/05/31 17:14:34.701553 juicefs[32667] <WARNING>: usage stat of /d should be &{1073741824 1073741824 1}, but got &{469762048 469762048 1} [base.go:2010] 2023/05/31 17:14:34.701577 juicefs[32667] <WARNING>: Stat of path /d (inode 2) should be synced, please re-run with '--path /d --repair --sync-dir-stat' to fix it [base.go:2025] 2023/05/31 17:14:34.701615 juicefs[32667] <FATAL>: some errors occurred, please check the log of fsck [main.go:31]用 fsck 修复
按提示,追加--repair即可修复损坏的目录统计。--sync-dir-stat的语义是"即使统计值存在且未损坏也强制重算"(见 cmd/fsck.go 的参数说明),因此检查与修复建议成对使用:
$ juicefs fsck -v sqlite3://test.db --path /d --sync-dir-stat --repair 2023/05/31 17:14:43.445153 juicefs[32721] <DEBUG>: maxprocs: Leaving GOMAXPROCS=8: CPU quota undefined [maxprocs.go:47] 2023/05/31 17:14:43.445289 juicefs[32721] <INFO>: Meta address: sqlite3://test.db [interface.go:494] [xorm] [info] 2023/05/31 17:14:43.445350 PING DATABASE sqlite3 2023/05/31 17:14:43.462374 juicefs[32721] <DEBUG>: Stat of path /d (inode 2) is successfully synced [base.go:2018]修复时,fsck会对每个目录调用元数据层的doSyncDirStat:先现场calcDirStat重算,再在事务中回写三个统计字段(Redis 引擎见 pkg/meta/redis.go,事务内还会写入DIRSTAT变更日志)。需要注意,--sync-dir-stat只在 volume 开启了DirStats时生效,否则会被忽略(pkg/meta/base.go 中有对应告警)。
修复后验证
再次用快速模式检查,结果应与严苛模式一致:
$ juicefs info -r /jfs/d /jfs/d: 1 3.3/s /jfs/d: 1.0 GiB (1073745920 Bytes) 3.3 GiB/s /jfs/d : inode: 2 files: 1 dirs: 1 length: 1.00 GiB (1073741824 Bytes) size: 1.00 GiB (1073745920 Bytes) path: /d与目录配额的关系
目录用量统计与目录配额(Directory Quota)是强耦合的上下游关系:
- 前置依赖:
quota命令的快速模式读取的就是目录统计值,目录配额因此依赖目录用量统计; - 自动开启:为目录设置配额后,目录用量统计会被自动启用;
- 禁止关闭:只要 volume 上还存在目录配额,
--dir-stats=false就会被拒绝(见上文源码约束)。
此外,JuiceFS 企业版还在此基础上提供了递归统计的目录大小能力,可直接通过ls -lh看到目录递归总大小;而社区版ls展示的仍是目录单层用量,如需查看递归统计,只能使用juicefs info -r或juicefs summary。
最佳实践小结
- 升级先行:v1.1.0 之前创建的 volume 在启用
dir-stats前,务必确认所有可写挂载客户端已升级到 v1.1.0 以上,避免旧客户端写入造成统计缺失。 - 按需开关:新格式化的 volume 默认开启,无需处理;存量 volume 用
juicefs config $URL --dir-stats开启,用juicefs config $URL确认生效。 - 善用 summary:日常排查目录空间占用优先使用
juicefs summary,配合--depth、--entries控制输出粒度;info -r适合精确获取某个目录树的递归总量。 - 定期对账:将
juicefs info(快速模式)与--strict模式对比作为巡检手段;发现不一致时,用juicefs fsck --path <目录> --sync-dir-stat --repair定向修复,避免大范围全量扫描。 - 注意开销:目录用量统计是异步增量更新的,写入路径会有少量额外元数据操作,这也是"快速查询"与"写入开销"之间的权衡。
【免费下载链接】juicefsJuiceFS is a distributed POSIX file system built on top of Redis and S3.项目地址: https://gitcode.com/GitHub_Trending/ju/juicefs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考