第 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 有性能影响,选择低峰期执行
- 碎片整理会破坏快照共享,谨慎使用
扩展阅读