Btrfs 文件系统运维完全教程 / 第 8 章:数据校验 (Scrub)
第 8 章:数据校验 (Scrub)
8.1 Scrub 概述
8.1.1 什么是 Scrub
Scrub 是 Btrfs 的定期数据校验机制,通过读取所有数据块并验证校验和,主动发现和修复静默数据损坏(Silent Data Corruption)。
8.1.2 为什么需要 Scrub
| 数据损坏类型 | 说明 | Scrub 是否能发现 |
|---|
| 位翻转(Bit Rot) | 存储介质自然老化 | ✅ |
| 写入不完整 | 断电或固件 bug | ✅ |
| DMA 传输错误 | 内存/总线错误 | ✅ |
| 固件 bug | 磁盘控制器错误 | ✅ |
| 恶意篡改 | 人为修改数据 | ✅ |
| 磁盘扇区坏块 | 物理损坏 | ✅ |
8.1.3 工作原理
Scrub 流程:
1. 扫描文件系统的所有 extent
2. 读取每个 extent 的数据
3. 计算校验和(CRC32C / xxhash / sha256 / blake2b)
4. 与元数据中存储的校验和比较
5. 如果不匹配:
a. RAID 1/10:从其他副本修复
b. 单设备模式:报告错误
6. 记录结果到统计信息
8.2 执行 Scrub
8.2.1 启动 Scrub
# 启动 scrub(后台运行)
sudo btrfs scrub start /mnt/data
# 启动并等待完成
sudo btrfs scrub start -B /mnt/data
# 只 scrub 指定设备
sudo btrfs scrub start -d /dev/sdb /mnt/data
# 限制 scrub 速度(降低对业务的影响)
sudo btrfs scrub start -c 2 /mnt/data # 限制 2 个并发
# 设置 IO 优先级(需要 ionice 支持)
sudo ionice -c 3 btrfs scrub start /mnt/data
8.2.2 查看 Scrub 状态
# 查看当前 scrub 状态
sudo btrfs scrub status /mnt/data
# 输出示例:
# UUID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
# Scrub started: Sat May 10 02:00:00 2026
# Status: running
# Duration: 0:35:22
# Total to scrub: 100.00GiB
# Rate: 48.50MiB/s
# Error summary: no errors found
# 查看历史 scrub 结果
sudo btrfs scrub status -d /mnt/data
8.2.3 取消 Scrub
# 取消正在进行的 scrub
sudo btrfs scrub cancel /mnt/data
8.3 Scrub 错误处理
8.3.1 错误类型
| 错误类型 | 说明 | 严重程度 |
|---|
| csum (校验和错误) | 读取数据的校验和与存储的不匹配 | 高 |
| super (超级块错误) | 超级块损坏 | 严重 |
| verify (验证错误) | 元数据验证失败 | 高 |
| read (读取错误) | 物理读取失败 | 严重 |
| csum (已修复) | 从其他副本修复成功 | 信息 |
8.3.2 查看 Scrub 错误
# 查看 scrub 错误详情
sudo btrfs scrub status -d /mnt/data
# 输出中错误示例:
# Scrub device /dev/sdb (id 1) history
# Scrub started: Sat May 10 02:00:00 2026
# Status: finished
# Duration: 0:35:22
# Total to scrub: 100.00GiB
# Rate: 48.50MiB/s
# Error summary: csum=3
# Corrected: 2
# Uncorrectable: 1
# Unverified: 0
# 查看设备错误统计
sudo btrfs device stats /mnt/data
8.3.3 修复错误
单设备模式(无法自动修复):
# 如果 scrub 发现错误且无法修复
# 1. 立即备份数据
sudo rsync -av /mnt/data/ /backup/
# 2. 检查文件系统
sudo umount /mnt/data
sudo btrfs check /dev/sdb1
# 3. 如果 check 报错
sudo btrfs check --repair /dev/sdb1 # ⚠️ 危险操作
RAID 1 模式(自动修复):
# RAID 1 模式下,scrub 会自动从其他副本修复损坏的数据
# scrub 结果中 "Corrected" 数量会增加
# 查看修复详情
sudo btrfs device stats /mnt/data
# [/dev/sdb].corruption_errs 3 ← 检测到 3 个损坏
# [/dev/sdc].corruption_errs 0
# 修复后的数据已经写回正确的副本
8.4 定期 Scrub 调度
8.4.1 推荐调度频率
| 场景 | 建议频率 | 原因 |
|---|
| 生产服务器 | 每周 1-2 次 | 数据完整性至关重要 |
| NAS / 文件服务器 | 每周 1 次 | 大量数据需要保护 |
| SSD 存储 | 每月 1 次 | SSD 出错概率较低 |
| 归档存储 | 每月 1 次 | 数据变更少 |
| 桌面系统 | 每月 1 次 | 非关键数据 |
8.4.2 systemd 定时器配置
# /etc/systemd/system/btrfs-scrub@.timer
[Unit]
Description=Btrfs scrub timer for %i
[Timer]
OnCalendar=weekly
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/btrfs-scrub@.service
[Unit]
Description=Btrfs scrub for %i
[Service]
Type=oneshot
ExecStart=/usr/bin/btrfs scrub start -B %i
Nice=19
IOSchedulingClass=idle
# 启用 scrub 定时器
sudo systemctl enable --now btrfs-scrub@mnt-data.timer
# 检查定时器状态
sudo systemctl list-timers btrfs-scrub@mnt-data.timer
8.4.3 Cron 调度
# 每周日凌晨 2 点执行 scrub
0 2 * * 0 /usr/bin/btrfs scrub start -B /data 2>&1 | logger -t btrfs-scrub
# 每月 1 号凌晨 3 点(SSD)
0 3 1 * * /usr/bin/btrfs scrub start -B /data 2>&1 | logger -t btrfs-scrub
8.4.4 综合 Scrub 脚本
#!/bin/bash
# btrfs-scrub-wrapper.sh - 带通知的 Scrub 脚本
set -euo pipefail
MOUNT_POINT="${1:?Usage: $0 /mount/point}"
ALERT_EMAIL="${2:-admin@example.com}"
LOG_FILE="/var/log/btrfs-scrub.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
send_alert() {
local subject="$1"
local body="$2"
echo "$body" | mail -s "Btrfs Scrub: $subject" "$ALERT_EMAIL"
}
log "Starting scrub on $MOUNT_POINT"
# 执行 scrub
OUTPUT=$(sudo btrfs scrub start -B "$MOUNT_POINT" 2>&1) || true
log "$OUTPUT"
# 检查结果
STATUS=$(sudo btrfs scrub status "$MOUNT_POINT" 2>&1)
log "$STATUS"
# 检查错误统计
ERRORS=$(sudo btrfs device stats "$MOUNT_POINT" 2>&1)
TOTAL_ERRORS=$(echo "$ERRORS" | grep -v " 0$" | grep -v "^[/" | wc -l)
if [[ "$TOTAL_ERRORS" -gt 0 ]]; then
log "WARNING: Device errors detected!"
log "$ERRORS"
send_alert "Scrub completed with errors on $MOUNT_POINT" \
"Scrub output:\n$OUTPUT\n\nDevice stats:\n$ERRORS"
else
log "Scrub completed successfully, no errors found."
fi
8.5 Scrub 性能影响
8.5.1 资源消耗
| 资源 | 影响 | 说明 |
|---|
| CPU | 中等 | 校验和计算 |
| 内存 | 低 | 仅读取缓存 |
| 磁盘 I/O | 高 | 顺序读取所有数据 |
| 网络(NFS) | 高 | 如果通过网络挂载 |
8.5.2 降低 Scrub 影响
# 方法 1:降低优先级
sudo ionice -c 3 btrfs scrub start /mnt/data
sudo nice -n 19 btrfs scrub start /mnt/data
# 方法 2:限制并发设备数
sudo btrfs scrub start -c 1 /mnt/data
# 方法 3:选择低峰期执行
# cron 中设置在凌晨执行
0 2 * * 0 /usr/bin/btrfs scrub start -B /data
8.5.3 Scrub 速度参考
| 设备类型 | 大约速度 | 100GB 耗时 |
|---|
| NVMe SSD | 500-2000 MiB/s | 1-3 分钟 |
| SATA SSD | 200-500 MiB/s | 3-8 分钟 |
| HDD 7200RPM | 100-200 MiB/s | 8-15 分钟 |
| HDD 5400RPM | 50-100 MiB/s | 15-30 分钟 |
8.6 Scrub 与其他操作的关系
8.6.1 Scrub 与 Balance
| 操作 | 目的 | 对数据完整性的影响 |
|---|
| Scrub | 验证数据完整性 | 发现并修复损坏 |
| Balance | 重新分配空间 | 不验证完整性 |
💡 提示: 建议在 balance 之前先执行 scrub,确保数据完整性。
8.6.2 Scrub 与快照
# scrub 会校验所有数据,包括快照中的数据
# 快照与源子卷共享数据块,所以 scrub 高效地一次验证
8.6.3 Scrub 与 RAID
# RAID 1:scrub 自动修复损坏的副本
sudo btrfs scrub start /mnt/raid1
# 错误会被自动修复
# RAID 5/6:scrub 可以使用奇偶校验修复
# 但由于 write hole 问题,修复可能不完全可靠
8.7 本章小结
| 操作 | 命令 |
|---|
| 启动 scrub | btrfs scrub start /mnt |
| 等待完成 | btrfs scrub start -B /mnt |
| 查看状态 | btrfs scrub status /mnt |
| 取消 scrub | btrfs scrub cancel /mnt |
| 查看错误 | btrfs scrub status -d /mnt |
| 设备统计 | btrfs device stats /mnt |
关键要点:
- Scrub 是发现静默数据损坏的唯一方法
- 生产环境建议每周执行 1-2 次
- RAID 模式下 scrub 可以自动修复损坏
- 使用 ionice/nice 降低 scrub 对业务的影响
- 配合告警脚本及时发现问题
扩展阅读