Linux btrfs scrub / balance 的定期维护计划与 IO 影响控制

1次阅读

scrub 不会卡死系统但会打满磁盘io,需用 ionice -c2 -n7 限速;balance 仅在 chunk 碎片、分布不均或设备故障时才需运行;scrub 与 balance 必须串行且先 scrub 后 balance。

Linux btrfs scrub / balance 的定期维护计划与 IO 影响控制

scrub 会卡住系统吗?IO 负载怎么压下来

不会直接卡死,但默认跑法会让磁盘 IO 持续打满,尤其在机械盘或混用负载的机器上,rsyncpostgres 这类服务响应会明显变慢。

关键不是“做不做”,而是“怎么限速”。btrfs scrub 本身不支持 --throttle 或类似参数,得靠外部工具控速:

  • ionice -c2 -n7 降低 IO 调度优先级(推荐,对交互影响最小)
  • 配合 cpulimit 没用——scrub 是 IO 密集型,CPU 占用通常不到 5%
  • 避免在 /proc/sys/vm/swappiness 高的机器上跑,swap 活跃时 scrub 可能触发内存回收抖动

示例命令:

ionice -c2 -n7 btrfs scrub start -B /mnt/data

-B 表示前台运行,方便配合 ionice

balance 什么时候必须跑?哪些 Filter 真的有用

不是定期跑就有益。btrfs balance 主要解决两类问题:碎片导致的写放大、chunk 分布不均引发的单盘过载。80% 的误操作源于把它当“磁盘整理”用。

真正需要 balance 的信号只有三个:

  • btrfs Filesystem usage /path 显示某块 device 的 used 接近 100%,但其他盘还有空闲
  • 写入大量小文件后,btrfs filesystem df /pathData 类型的 total 远大于 used(说明 chunk 碎片严重)
  • 执行 btrfs device stats /path 发现某设备有持续 read_failures,balance 可强制迁移该设备上的 chunk(但先确认硬件没坏)

常用 filter 中,usage=85profiles=dup 最实用;limit=100 这种纯数字限制容易误伤——它按 chunk 数计,不是按空间算。

scrub 和 balance 能不能一起跑?顺序有讲究吗

绝对不要并发执行。两者都会读写 chunk tree 和 extent tree,同时跑大概率触发 transaction aborted 错误,日志里出现 aborting transaction 就是这个原因。

必须串行,且顺序固定:

  • btrfs scrub —— 它只读,能发现静默数据损坏,是 balance 前的安全检查
  • 等 scrub 完成且无 errors(查 btrfs scrub status /path),再跑 btrfs balance
  • balance 完了最好再 scrub 一次,验证迁移后的数据一致性

中间任意一步失败,就停住。balance 半途被 kill 可能留下 inconsistent chunk tree,恢复起来比重做还麻烦。

crontab 里怎么写才不算耍流氓

直接写 0 2 * * 0 btrfs scrub start /mnt/data 是典型反模式:没检查挂载状态、没处理锁冲突、没防 overlap。

一个可用的最小化脚本逻辑:

  • findmnt -T /mnt/data 确认路径已挂载且是 btrfs
  • 检查 /var/run/btrfs-scrub.lock 是否存在(自己建个简单锁文件)
  • timeout 24h 防止 scrub 卡死(某些坏块场景下会 hang 住)
  • 把输出重定向到 /var/log/btrfs-scrub.log,别丢进 /dev/null

IO 影响最隐蔽的点:balance 默认使用 metadatasystem profile 的 full write,即使你只 filter data chunk,它仍会重写所有 metadata。这意味着 SSD 的写入放大和寿命消耗比看起来高得多。

text=ZqhQzanResources