坑边闲话:ZFS 在文件系统层面可以提供许多方法保证数据可靠,但 ZFS 依然受限于硬件损坏的限制。在发生硬盘报错、I/O hang、resilver 卡死等故障时,首要的处理任务是确保系统处于可用状态。如果系统已经被 D 状态进程或错误风暴拖垮,那么任何恢复操作(例如新建池、替换硬盘、执行 zfs 命令)都会极度缓慢甚至完全卡死。
1. 保证系统可用
ZFS 中的 RAIDZ vdev 具有同步 I/O 语义,只要 一块磁盘无响应,整个 vdev 的 I/O 都会停在那里等待,引发:
- 大量 D 状态进程
- 命令执行卡住(例如
zpool status、zfs list)
resilver / scrub 长时间 0B/s
- 文件系统操作卡死
- CPU soft lockup
这是 ZFS 的一致性设计决定的,但对故障盘来说会让系统被拖死。
因此:第一步永远是 offline 故障磁盘。
2. 使用 zpool offline **下线故障磁盘
如果阵列冗余允许(RAID-Z1/Z2/Z3 或镜像),主动 offline 有问题的磁盘是最有效的恢复操作。
zpool offline pool_name disk_id
2.1 offline 的目的
- 避免整个阵列因为坏盘 I/O 超时而全挂
- 恢复系统响应速度
- 让后续操作变得可执行:
- 数据备份
- snapshot send/receive
- 替换硬盘
- 创建新池
- 正常文件操作
ZFS 阵列中的磁盘通常是同步协作的,因此坏盘会导致整个阵列进入盲目等待,这就是大量卡死的根本原因。
2.2 使用 partition-uuid 指定盘符
灾后恢复中,使用 /dev/sdX 是非常不可靠的,因为:
- 重启会改变 sdX 顺序
- 多控制器或 HBA 会改变挂载顺序
- 插拔硬盘会重新分配字母
- ZFS vdev 里查找 sdX 字符会反悔 no such device 报错
因此更推荐使用 partition-uuid:
ls -l /dev/disk/by-partuuid/
然后:
zpool offline pool_name PARTUUID=xxxx-xxxx-xxxx-xxxx
这样可以避免误操作或重启后设备名变化带来的混乱。
3. offline 后的恢复流程
在坏盘被隔离后,整个系统恢复正常速度,才能安全执行以下操作。
3.1 数据备份 / replicate
包括:
zfs send | zfs receive
zrepl 增量备份
- syncoid
- rsync(用于紧急拷贝)
系统在正常 I/O 下才能保证备份不被卡住。
3.2 替换硬盘
确保新盘健康(SMART 检查正常)后执行:
zpool replace pool_name old_disk new_disk
3.3 scrub / resilver
在系统健康且无坏盘拖延后,scrub/resilver 才能恢复正常速度。
总结
恢复策略总结如下:
- 灾后恢复首先是保证系统不被坏盘拖死
- 及时 offline 故障盘是关键
- 后续的备份、替换、新建池等操作只能在系统可用的前提下进行
- 使用 partition-uuid 代替
/dev/sdX 更可靠,不怕重启、控制器变化
- offline → 备份 → replace → scrub 是最安全稳定的流程
这一流程已经是非常成熟的 ZFS 灾后恢复实践,可作为生产级经验参考。