Btrfs 文件系统运维完全教程 / 第 9 章:空间平衡 (Balance)
第 9 章:空间平衡 (Balance)
9.1 Balance 概述
9.1.1 什么是 Balance
Balance(平衡)是 Btrfs 的空间重分配操作。它重新写入文件系统中的数据块,将它们从旧的块组(Block Group)移动到新的块组,实现:
- 空间回收 — 删除大量数据后回收未使用的块组空间
- RAID 转换 — 在不同 RAID 级别之间转换
- 碎片整理 — 重新组织数据布局
- 块组合并 — 合并零散的小块组
9.1.2 块组(Block Group)
Btrfs 将设备空间划分为多个块组(Block Group),每个块组的大小通常为 1GB(数据)或 256MB(元数据):
设备 /dev/sdb(100GB)
┌──────────┬──────────┬──────────┬──────────┬──────────┐
│ Block │ Block │ Block │ Block │ 未分配 │
│ Group 1 │ Group 2 │ Group 3 │ Group 4 │ 空间 │
│ 数据 │ 数据 │ 元数据 │ 数据 │ │
│ 50% 使用 │ 10% 使用 │ 30% 使用 │ 已满 │ │
└──────────┴──────────┴──────────┴──────────┴──────────┘
平衡后:
┌──────────┬──────────┬──────────┬──────────┬──────────┐
│ Block │ Block │ Block │ 已释放 │ 未分配 │
│ Group 1 │ Group 2 │ Group 3 │ 块组 │ 空间 │
│ 数据 │ 元数据 │ 数据 │ │ (更大) │
│ 80% 使用 │ 30% 使用 │ 70% 使用 │ │ │
└──────────┴──────────┴──────────┴──────────┴──────────┘
9.1.3 何时需要 Balance
| 场景 |
是否需要 Balance |
原因 |
| 大量删除文件后 |
✅ 是 |
回收空块组空间 |
| 添加新设备后 |
✅ 是 |
将数据重新分配到新设备 |
| RAID 级别转换 |
✅ 是 |
必须通过 balance 转换 |
btrfs filesystem usage 显示 Unallocated 很少 |
✅ 是 |
空间碎片化 |
| 空间"已用"与"实际数据量"差距大 |
✅ 是 |
块组内有大量空闲但无法释放 |
| 日常使用 |
❌ 否 |
不需要定期 balance |
| SSD 碎片整理 |
⚠️ 谨慎 |
可能增加 SSD 写入量 |
9.2 Balance 操作
9.2.1 基础 Balance
# ⚠️ 全平衡 - 会重写所有数据,非常耗时!
sudo btrfs balance start /mnt/data
# 带过滤器的平衡(推荐)
# 只平衡使用率低于 5% 的块组
sudo btrfs balance start -dusage=5 /mnt/data
# 只平衡使用率低于 50% 的块组
sudo btrfs balance start -dusage=50 /mnt/data
# 只平衡元数据
sudo btrfs balance start -musage=10 /mnt/data
# 同时过滤数据和元数据
sudo btrfs balance start -dusage=10 -musage=30 /mnt/data
9.2.2 Balance 过滤器详解
| 过滤器 |
说明 |
示例 |
-dusage=N |
数据块组使用率 <= N% |
-dusage=10 |
-musage=N |
元数据块组使用率 <= N% |
-musage=20 |
-dlimit=N |
最多处理 N 个数据块组 |
-dlimit=5 |
-mlimit=N |
最多处理 N 个元数据块组 |
-mlimit=5 |
-dconvert=PROFILE |
转换数据 RAID 级别 |
-dconvert=raid1 |
-mconvert=PROFILE |
转换元数据 RAID 级别 |
-mconvert=raid1 |
-dsuspend |
暂停数据平衡 |
— |
-msuspend |
暂停元数据平衡 |
— |
9.2.3 查看 Balance 状态
# 查看当前 balance 状态
sudo btrfs balance status /mnt/data
# 输出示例:
# Balance on '/mnt/data' is running
# 3 out of about 100 chunks balanced (4 considered), 97% left
# 平衡完成后:
# No balance found on '/mnt/data'
9.2.4 取消 Balance
# 取消正在进行的 balance
sudo btrfs balance cancel /mnt/data
# 暂停 balance(可以稍后恢复)
sudo btrfs balance pause /mnt/data
# 恢复暂停的 balance
sudo btrfs balance resume /mnt/data
9.3 空间回收
9.3.1 空间碎片化问题
# 场景:删除了大量数据,但空间没有释放
# 查看空间使用
sudo btrfs filesystem usage /mnt/data
# Device size: 100.00GiB
# Device allocated: 80.00GiB
# Used: 10.00GiB ← 实际只用了 10GB
# Free (estimated): 20.00GiB ← 但只有 20GB 可用!
# 原因:块组已分配但内部数据已删除,块组本身不能释放
9.3.2 回收空间
# 1. 查看块组使用情况
sudo btrfs filesystem df /mnt/data
# Data, single: total=78.00GiB, used=9.00GiB
# System, DUP: total=8.00MiB, used=16.00KiB
# Metadata, DUP: total=1.01GiB, used=500.00MiB
# 2. 使用 balance 回收低使用率的块组
sudo btrfs balance start -dusage=5 /mnt/data
# 先回收使用率低于 5% 的块组(几乎为空)
sudo btrfs balance start -dusage=20 /mnt/data
# 再回收使用率低于 20% 的块组
sudo btrfs balance start -dusage=50 /mnt/data
# 最后回收使用率低于 50% 的块组
# 3. 验证空间回收效果
sudo btrfs filesystem usage /mnt/data
# Device allocated: 15.00GiB ← 已分配减少
# Free (estimated): 85.00GiB ← 可用空间增加
9.3.3 渐进式回收策略
#!/bin/bash
# btrfs-reclaim-space.sh - 渐进式空间回收
set -euo pipefail
MOUNT_POINT="${1:?Usage: $0 /mount/point}"
echo "=== Space before balance ==="
sudo btrfs filesystem usage "$MOUNT_POINT" | head -10
# 渐进式回收
for usage in 1 5 10 20 30 50; do
echo ""
echo "=== Balancing data chunks with usage <= ${usage}% ==="
sudo btrfs balance start -dusage="$usage" -dlimit=10 "$MOUNT_POINT" 2>&1 || true
done
# 回收元数据
for usage in 1 5 10 20 30 50; do
echo ""
echo "=== Balancing metadata chunks with usage <= ${usage}% ==="
sudo btrfs balance start -musage="$usage" -mlimit=10 "$MOUNT_POINT" 2>&1 || true
done
echo ""
echo "=== Space after balance ==="
sudo btrfs filesystem usage "$MOUNT_POINT" | head -10
9.4 RAID 转换
9.4.1 单设备转 RAID 1
# 1. 添加第二个设备
sudo btrfs device add /dev/sdc /mnt/data
# 2. 转换为 RAID 1
sudo btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt/data
# 3. 验证
sudo btrfs filesystem show /mnt/data
sudo btrfs filesystem df /mnt/data
9.4.2 RAID 1 转 RAID 10
# 需要至少 4 个设备
sudo btrfs device add /dev/sdd /mnt/data
sudo btrfs device add /dev/sde /mnt/data
# 转换
sudo btrfs balance start -dconvert=raid10 -mconvert=raid10 /mnt/data
9.4.3 转换进度
# 查看转换进度
sudo btrfs balance status /mnt/data
# Balance on '/mnt/data' is running
# 15 out of about 80 chunks balanced (15 considered), 81% left
# 等待完成
while sudo btrfs balance status /mnt/data | grep -q "running"; do
sleep 10
done
9.5 Balance 性能影响
9.5.1 资源消耗
| 资源 |
影响程度 |
说明 |
| CPU |
中等 |
数据搬移和 RAID 计算 |
| 内存 |
低 |
仅使用少量缓存 |
| 磁盘 I/O |
高 |
大量读写操作 |
| 时间 |
长 |
大文件系统可能需要数小时 |
9.5.2 降低 Balance 影响
# 方法 1:限制处理的块组数量
sudo btrfs balance start -dlimit=5 -mlimit=5 /mnt/data
# 方法 2:只处理低使用率块组
sudo btrfs balance start -dusage=10 /mnt/data
# 方法 3:使用 ionice 降低 I/O 优先级
sudo ionice -c 3 btrfs balance start /mnt/data
# 方法 4:选择低峰期执行
# 在 cron 中设置凌晨执行
9.5.3 Balance 速度参考
| 场景 |
大约速度 |
说明 |
| NVMe SSD |
200-500 MiB/s |
100GB: 3-8 分钟 |
| SATA SSD |
100-300 MiB/s |
100GB: 5-15 分钟 |
| HDD |
50-100 MiB/s |
100GB: 15-30 分钟 |
| RAID 1 Balance |
更慢 |
需要写入两个副本 |
| RAID 转换 |
很慢 |
需要重写所有数据 |
9.6 Balance 调度
9.6.1 推荐调度策略
| 场景 |
建议 |
说明 |
| 大量删除后 |
手动执行 |
删除 > 20% 数据后 |
| 添加设备后 |
手动执行 |
立即 balance |
| RAID 转换 |
手动执行 |
按需执行 |
| 定期维护 |
每月 1 次 |
只处理低使用率块组 |
| 碎片整理 |
每季度 1 次 |
只在 HDD 上 |
9.6.2 定期 Balance 脚本
#!/bin/bash
# btrfs-monthly-balance.sh - 每月空间平衡
set -euo pipefail
MOUNT_POINT="/data"
LOG_FILE="/var/log/btrfs-balance.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
log "Starting monthly balance on $MOUNT_POINT"
# 渐进式回收低使用率块组
for usage in 5 10 20 30; do
log "Balancing data: usage <= ${usage}%"
sudo btrfs balance start -dusage="$usage" -dlimit=5 "$MOUNT_POINT" 2>&1 | tee -a "$LOG_FILE" || true
done
for usage in 5 10 20 30; do
log "Balancing metadata: usage <= ${usage}%"
sudo btrfs balance start -musage="$usage" -mlimit=5 "$MOUNT_POINT" 2>&1 | tee -a "$LOG_FILE" || true
done
log "Balance completed"
log "Current usage:"
sudo btrfs filesystem usage "$MOUNT_POINT" | head -8 | tee -a "$LOG_FILE"
# Cron 配置:每月 15 号凌晨 3 点
0 3 15 * * /usr/local/bin/btrfs-monthly-balance.sh
9.7 Balance 与碎片整理
9.7.1 碎片整理命令
# 对整个文件系统进行碎片整理
sudo btrfs filesystem defragment -r /mnt/data
# 对指定目录碎片整理
sudo btrfs filesystem defragment -r /mnt/data/projects
# 指定压缩算法(同时重新压缩)
sudo btrfs filesystem defragment -r -czstd /mnt/data/documents
# 限制单个文件大小(只整理大于 32MB 的文件)
sudo btrfs filesystem defragment -r -t 32M /mnt/data
# 对单个文件碎片整理
sudo btrfs filesystem defragment /mnt/data/largefile.img
9.7.2 碎片整理注意事项
| 设备类型 |
是否需要碎片整理 |
原因 |
| SSD |
❌ 通常不需要 |
SSD 随机读性能好 |
| HDD |
✅ 定期执行 |
碎片严重影响 HDD 性能 |
| 虚拟机磁盘 |
⚠️ 谨慎 |
可能破坏 COW 快照共享 |
| RAID |
⚠️ 谨慎 |
碎片整理触发大量写入 |
⚠️ 警告: 碎片整理会破坏快照的数据共享,导致快照占用大量额外空间。对有快照的子卷执行碎片整理前请三思。
9.8 本章小结
| 操作 |
命令 |
| 全平衡 |
btrfs balance start /mnt |
| 过滤平衡 |
btrfs balance start -dusage=10 /mnt |
| RAID 转换 |
btrfs balance start -dconvert=raid1 /mnt |
| 查看状态 |
btrfs balance status /mnt |
| 取消平衡 |
btrfs balance cancel /mnt |
| 碎片整理 |
btrfs filesystem defragment -r /mnt |
关键要点:
- 不要轻易执行全 balance,使用过滤器控制范围
- 删除大量数据后需要 balance 回收空间
- 添加设备后需要 balance 重新分配数据
- Balance 有性能影响,选择低峰期执行
- 碎片整理会破坏快照共享,谨慎使用
扩展阅读