Skip to main content

高性能 Find

如果 JuiceFS 文件系统中已经存有海量文件,需要按照特定条件搜索,那么 Linux 自带的 find 可能性能会比较差,从 v5.3.7 开始,可以使用 juicefs find 命令作为 find 的高性能替代,通常会比 find 快 1~2 个数量级。详细介绍见命令参考

注意

客户端升级到 v5.3.7 即可使用 juicefs find。如果元数据服务未升级到 v5.3.7,依然可以正常使用,但客户端检索性能会有较大折损。

背景

为什么需要 juicefs find

在大型分布式文件系统上线后,存储治理是一个普遍痛点:

  • 大量历史数据长期占用存储空间,但无人知晓哪些文件仍在使用、哪些已经「沉睡」。
  • 存储团队需要定期盘点长时间未访问的文件,交给业务部门去确认是否删除。
  • 常见的需求表达:「列出超过 X 天未访问的文件列表」、「找出占用空间超过 Y GiB 的大文件」

现有方案对比

方案特点
标准 Linux find单机遍历,无法利用 JuiceFS 元数据服务分布式扫描能力,大目录极慢
juicefs find服务端直接过滤,支持 atime/size/type 等谓词,结果精准返回,零外部依赖
提示

juicefs find 直接在 JuiceFS 内部实现按条件递归查找文件,结合两阶段过滤(服务端元数据侧预筛选 + 客户端挂载侧最终求值),兼顾性能与灵活性。

核心价值

juicefs find 为存储治理提供了完整的「发现 → 确认 → 执行」闭环:

快速定位「冷数据」→ 业务部门确认 → 创建删除任务 → 释放存储空间
  • 定位:通过 -atime-size-user 等谓词组合,在海量文件中快速筛选出符合条件的「冷数据」。
  • 确认:先用 -print 将匹配结果导出为清单,交给业务部门审核哪些确实可以清理。
  • 执行:确认无误后用 -delete 批量删除,或配合 -exec 调用外部工具(如归档、压缩),释放存储空间、降低存储成本。

功能概述

juicefs find 命令用于在 JuiceFS 挂载点中按条件递归查找文件或目录,并支持执行动作(如打印、删除、执行外部命令)。

该实现采用两阶段过滤:

  1. 服务端过滤(元数据侧):基于表达式 AST 在元数据树上做快速筛选,减少回传数据量。
  2. 客户端过滤与动作执行(挂载侧):对服务端返回条目做最终表达式求值并执行动作。默认动作为 -print

命令格式

juicefs find [-p N] [PATH ...] [EXPRESSION]

简单示例:

juicefs find /mnt/jfs -name "*.log"
juicefs find /mnt/jfs -type f -size +10M -print
juicefs find /mnt/jfs -name "*.tmp" -a -delete
juicefs find /mnt/jfs -type f -exec ls -l {} \;

高级用法示范:

# 使用 8 个并发线程扫描
juicefs find -p 8 /mnt/jfs -name "*.log"

# 查找大文件
juicefs find /mnt/jfs -type f -size +1G

# 查找最近 1 天内修改的日志
juicefs find /mnt/jfs -name "*.log" -mtime -1

# 忽略大小写查找路径
juicefs find /mnt/jfs -ipath "*backup*"

# 组合条件
juicefs find /mnt/jfs -type f -a \( -name "*.go" -o -name "*.md" \)

# 按时间比较:修改时间晚于指定日期
juicefs find /mnt/jfs -newermt "2024-01-01"

# 按时间比较:访问时间晚于参考文件
juicefs find /mnt/jfs -neweram /mnt/jfs/reference.txt

# 执行动作
juicefs find /mnt/jfs -type f -name "*.tmp" -delete
juicefs find /mnt/jfs -type f -name "*.log" -exec gzip {} \;

选项与语法

遍历选项

  • -p, --threads N 并发线程数(默认 10),提升大目录扫描速度。该参数必须放在路径之前。
  • -maxdepth N 最大遍历深度。可以放在表达式中的任意位置。
  • -mindepth N 最小匹配深度。可以放在表达式中的任意位置。

逻辑运算

  • 与:-a, -and(也支持隐式与)。
  • 或:-o, -or
  • 非:!, -not
  • 分组:(...)

表达式遵循常见优先级:

  1. 括号

支持的谓词

谓词说明生命周期管理用途
-atime [+-]N文件最后访问时间。+N 匹配 N 天之前,-N 匹配最近 N 天内(均不含第 N 天)识别冷数据的核心谓词
-mtime [+-]N文件内容最后修改时间。+N/-N 同上识别长期未更新的文件
-ctime [+-]N文件状态最后变更时间(含内容修改、权限/所有者变更等)。+N/-N 同上识别状态变更时间范围内的文件
-size [+-]N[KMGT]指定文件大小(+ 为大于,- 为小于;K/M/G/T 采用 1024 进制)识别占用空间多的大文件
-type f/d/l文件类型(文件/目录/软链接)区分文件与目录分别治理
-name/-iname文件名(支持通配符)按扩展名筛选(如 .log.tmp
-path/-ipath路径匹配(支持通配符,* 匹配 /按目录筛选
-user/-group按文件所属用户/组筛选,同时支持名称和数字 ID(如 UID、GID)按部门维度统计冷数据
-empty空文件或空目录清理无效残留文件
-perm MODE按权限筛选。-perm 644 权限恰好为 644;-perm -644 权限至少为 644;-perm /644 权限包含 644 中的任一位排查权限异常文件
-links按硬链接数筛选识别无引用的文件
-inum [+-]N按 inode 号筛选,+ 为大于,- 为小于定位特定 inode 关联的文件
-regex/-iregex正则匹配完整路径,采用 RE2 语法,自动全路径锚定;-iregex 不区分大小写复杂路径模式匹配
-newerXY FILE比参考文件/日期更新。X 为检查的时间字段(a 访问时间 / m 修改时间 / c 变更时间),Y 为参考类型(a/c/m 为文件引用,t 为日期字符串)。-newer 等价于 -newermm以某文件或日期为基准比较
-mmin/-amin/-cmin分钟级时间筛选精细化时间控制
-nouser/-nogroup无对应用户/组的文件排查孤儿文件

-newerXYt 模式支持以下日期格式,按优先级依次尝试:YYYY-MM-DD HH:MM:SS、RFC 3339 格式(带时区)、ISO 8601 格式(不带时区)、YYYY-MM-DD 纯日期,以及系统 date --date 所能解析的其他格式(如 1 year agolast Monday)。

支持的动作

动作说明
-print打印路径(默认动作)
-print0打印路径,以 null 字符分隔(适合 xargs -0
-printf FORMAT按指定格式打印,支持 %p(完整路径)、%f(文件名)、%s(文件大小)、%M(权限字符串)、%u/%g(用户/组名)、%t/%a/%c(时间)等格式化占位符
-exec CMD {} \;对每个匹配项执行命令(暂不支持 -exec ... + 形式)
-delete删除匹配的文件

生命周期管理典型场景

以下场景均可用 juicefs find 组合条件实现:

场景一:生成月度存储治理报告

# 找出所有超过 90 天未访问的文件,导出到清单
juicefs find /mnt/jfs -type f -atime +90 > /tmp/cold_files_90d.txt

# 进一步按大小区间分类统计
juicefs find /mnt/jfs -type f -atime +90 -size +1G > /tmp/cold_large_1g.txt
juicefs find /mnt/jfs -type f -atime +90 -size +100M > /tmp/cold_large_100m.txt
用途

识别「冷数据」,按大小分级导出为清单,交给业务部门确认是否可删除。

场景二:查找超过 30 天未访问的大文件(> 1 GiB)

juicefs find /mnt/jfs -type f -atime +30 -size +1G -print
用途

大文件即使数量少,也占用大量空间,这类文件优先治理。

场景三:查找 7 天内修改过的日志文件

juicefs find /mnt/jfs -name "*.log" -mtime -7 -print
用途

确认近期还在写入的日志,避免误删正在使用的日志。

场景四:查找空文件或空目录

juicefs find /mnt/jfs -empty -print
用途

发现已删除内容但残留的空文件/目录,释放 inode 资源。

场景五:按部门统计冷数据

# 按部门目录维度分别统计超过 180 天未访问的文件
juicefs find /mnt/jfs/rd -type f -atime +180 -print
juicefs find /mnt/jfs/marketing -type f -atime +180 -print

# 也可以按文件所属用户筛选
juicefs find /mnt/jfs -type f -atime +180 -user sales -print
用途

按部门/用户维度统计冷数据,责任到人,便于业务部门统一治理。

场景六:批量清理老旧临时文件

# 第一步:预览要删除的临时文件,确认清单
juicefs find /mnt/jfs -type f -name "*.tmp" -atime +7 -print

# 第二步:确认无误后执行删除
juicefs find /mnt/jfs -type f -name "*.tmp" -atime +7 -delete
建议

务必先 -print 预览,确认无误后再执行 -delete

场景七:与外部系统集成

# 导出为 null 分隔格式,避免文件名含空格导致的问题
juicefs find /mnt/jfs -type f -atime +365 -print0 > /tmp/cold_files-1y.txt

# 结合 xargs 批量压缩一年前的冷数据(节省存储成本)
cat /tmp/cold_files-1y.txt | xargs -0 gzip
用途

将查找结果以 -print0 格式导出,无缝衔接 xargs 等外部工具做后续处理。

注意事项

  1. 请在挂载点路径上使用该命令,避免对非 JuiceFS 路径执行。
  2. 使用 -delete务必先用同条件执行 -print 预览。
  3. 对大目录建议设置 -maxdepth 以控制扫描范围。
  4. 谓词解析错误会直接返回错误,建议先从简单表达式逐步叠加。
  5. 对于低版本的元数据服务或者不支持的谓词,可以回退到客户端做过滤。
  6. 对于没有访问权限的目录会自动跳过(静默)。
  7. 遍历过程中或者执行出错,会打印相关日志。
  8. atime 相关功能需要元数据服务开启记录 atime 功能(默认关闭更新 atime)。
  9. 大规模扫描时建议使用独立 Token 并设置 CPU 使用率上限(v5.3.7+,仅需升级元数据服务),避免影响正常业务。

故障排查

问题可能原因
无输出检查路径是否正确、是否命中条件、atime 是否被记录(可咨询 JuiceFS 团队确认)
-exec 执行失败检查外部命令是否存在、参数是否正确、权限是否足够
执行后返回错误常见于 delete/exec 行为失败;日志会显示具体失败条目

性能表现与负载

  • 实际使用中,受各分区元数据分布的均衡性、过滤条件的复杂度、扫描返回的数据量、元数据服务的负载等因素影响,处理性能会有较大波动,从单分区几万 inodes/s 到几十万 inodes/s 均有可能。
  • 可以通过配置并发数(-p / --threads)来加速扫描,但需要注意增大并发也会增加元数据服务的负载,建议避免过度调高并发而影响正常业务请求处理。
  • 遍历过程中,归档的目录需要解压缩后才能扫描。从 v5.3.12 版本开始(仅需升级元数据服务,不依赖客户端升级),扫描完成的目录节点会被及时重新压缩,大幅缩减解压缩数据在内存中的滞留时间,从而显著降低内存峰值并消除间歇性 GC 导致的 CPU 满载问题。升级后内存仍会有小幅增长,增长量与 -p/--threads 设置的并发度成正比:并发越高,同时处于解压缩状态的目录节点越多。在未升级到此版本的元数据服务上,大规模 juicefs find 扫描可能引发内存大幅增长和间歇性全核 CPU 占用。
  • 解压缩在请求处理线程中同步执行,受限于所属 Token 的 CPU 配额;重新压缩在后台完成,不占用 Token CPU 配额,且单次开销很小,不会产生额外负载。

使用独立 Token 控制负载

在大规模文件系统上执行 juicefs find 扫描时,建议为执行扫描的挂载点创建独立的客户端 Token,并限制其元数据服务 CPU 使用率(该功能从 v5.3.7 开始支持,仅需升级元数据服务,不依赖客户端升级),配合 -p/--threads 控制并发数,避免扫描影响正常业务请求处理。