软件 RAID 阵列降级处理实战:mdadm 判读、故障盘定位与重建后重启阵列消失的防范

RAID 阵列降级了,你的服务器其实还在跑——这才是最危险的地方

用软件 RAID(Linux 上的 mdadm)搭过存储的站长,几乎都会经历这一刻:某天 cat /proc/mdstat,看到原本 [UU] 的两块盘变成了 [U_],后面跟着一行 [2/1] [_U] 或者 [1/2] [U_]。机器没死,网站还开着,SSH 也正常,于是很多人扫一眼就关掉了终端——这恰恰是软 RAID 最凶险的阶段。

原因很直白:RAID1 少了 1 块盘还能读写,RAID5 也还能降级运行,但此时阵列已经没有任何冗余了。第二块盘再坏,数据就是直接丢。更麻烦的是,降级状态下的重建(resync/rebuild)是个长时间、高 I/O 的过程,如果没搞清楚是哪块盘坏、为什么要坏,就急着 mdadm --add,很可能把好的盘踢出去、把坏的盘留下来,把一次可恢复的故障变成不可恢复的灾难。

这篇文章按「判读 → 定位原因 → 替换重建 → 验证与预防」四段来讲,命令全部是可直接跑的完整形态,不省略参数。

第一步:读懂 /proc/mdstat,别只看那个下划线

/proc/mdstat 是软 RAID 的第一现场,但它的信息密度比看起来高。一个典型的降级 + 重建中的输出长这样:

Personalities : [raid1] [raid6] [raid5] [raid4]
md0 : active raid1 sdb1[1] sda1[0](F)
      1048512 blocks super 1.2 [2/1] [_U]
      resync=PENDING

md1 : active raid5 sdc1[0] sdd1[1] sde1[3]
      209584128 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/2] [UU_]
      [>....................]  recovery =  4.1% (4300800/104792064) finish=142.3min speed=11766K/sec

unused devices: <none>

逐段读:

  • sda1[0](F) —— 这个 (F) 是 faulty,表示设备已被标记为故障并从阵列中移除。看到 (F) 才能确认是哪一块盘掉了,光看 [2/1] [_U] 只能知道「少了一块」,不知道是哪块。
  • [2/1] —— 期望 2 个设备,当前 1 个活跃。RAID1 掉一块还能跑。
  • [_U] —— 从左到右对应 mdadm --detail 里的设备顺序。_ 的位置就是缺失的槽位。
  • recovery = 4.1% ... finish=142.3min —— 正在重建,以及预计剩余时间。speed 是当前重建速率。

更完整的信息要用:

mdadm --detail /dev/md0

输出里必须盯住三个字段:State(clean, degraded 还是 clean, degraded, recovering)、Active Devices、以及最下面 Number Major Minor RaidDevice State 那张表里每块盘的状态。removed、faulty spare、active sync 这三种状态的含义完全不同:只有 faulty/removed 才是真的不参与工作。

第二步:判断「盘坏了」还是「盘没事,是别的问题」

这是整篇最关键的一步,也是最容易做错的一步。mdadm 把一块盘标记为 faulty,不代表那块盘物理坏了。常见的三类误判:

误判一:线的接触问题或背板抖动

数据中心里 SATA/SAS 线接触不良、电源瞬时波动,都会让内核在一瞬间读不到盘,于是 mdadm 果断把它踢出阵列。盘本身完全健康。判读方法:

dmesg -T | grep -iE 'ata|sd[a-z]|I/O error|reset|link'
smartctl -a /dev/sda

如果 dmesg 里是 ata1: link is slow to respond、failed command: READ FPDMA QUEUED 这类链路层错误,而 smartctl 的 Reallocated_Sector_Ct、Current_Pending_Sector、Offline_Uncorrectable 全为 0,那么大概率是链路问题,不是介质问题。

误判二:SMART 有坏道但那块盘还在正常服务

反过来也成立:smartctl 报了几个重映射扇区,但阵列状态是干净的 [UU]。这种情况不要立刻换盘,先盯着 SMART 看趋势——每隔几小时跑一次,如果 Reallocated_Sector_Ct 不再增长,说明坏道已经被固件重映射掉了,盘还能用。贸然换盘会触发全盘 rebuild,反而给剩下的好盘施加巨大压力。

误判三:阵列降级但 dmesg 里啥都没有

这说明故障发生得更早,dmesg 环形缓冲区已经把日志冲掉了。这时候要查持久化日志:

journalctl -k --since "7 days ago" | grep -iE 'md/raid|sd[a-z]|smart'
grep -iE 'md/raid|faulty' /var/log/syslog

如果连日志都没有,还有一个很实用的办法:直接问 mdadm 记录的事件计数。每块盘的 superblock 里都有一个 event counter,正常同步的成员事件数应该一致,落后的那块就是掉队者:

mdadm --examine /dev/sda1 | grep -E 'Events|Array State|Update Time'
mdadm --examine /dev/sdb1 | grep -E 'Events|Array State|Update Time'

Update Time 明显更早、Events 明显更小的那块,就是被踢出去的那块。这一步能在没有任何日志的情况下定位故障盘,非常值得养成习惯。

第三步:先把「救数据」的顺序做对,再谈换盘

在动任何 mdadm 的写命令之前,先完成两件保护性动作:

动作一:立刻备份阵列上最重要的数据

降级状态下的 RAID 是「随时可能彻底失效」的状态。如果阵列上跑着数据库,第一件事是导出而不是修盘。对于 MySQL:

mysqldump --single-transaction --routines --triggers \
  --all-databases | gzip > /root/pre-raid-repair-$(date +%F).sql.gz

注意 --single-transaction 是为了在 InnoDB 上拿到一致性快照而不锁表——这一点和平时备份的注意事项一样,不是 RAID 特有,但在这种「只剩一半冗余」的时刻,任何额外压力都要避免。

动作二:记录当前阵列的完整状态

mdadm --detail --scan > /root/mdadm-scan-before.txt
mdadm --detail /dev/md0 > /root/md0-detail-before.txt
cat /proc/mdstat > /root/mdstat-before.txt

这份记录的价值在于:如果重建过程中出了岔子,你能精确还原出「原来是什么样」。它同时也是 /etc/mdadm/mdadm.conf 的正确内容来源,后面会用到。

第四步:替换故障盘并重建(RAID1 与 RAID5 两种流程)

RAID1:双盘镜像的替换流程

# 1. 把故障盘标记为移除(如果它还在阵列里挂着)
mdadm /dev/md0 --fail /dev/sda1
mdadm /dev/md0 --remove /dev/sda1

# 2. 物理换盘后,确认新盘没有残留的 RAID 元数据
mdadm --zero-superblock /dev/sda1     # 仅对确认无用的新盘执行!

# 3. 加入阵列,自动开始重建
mdadm /dev/md0 --add /dev/sda1

# 4. 观察进度
watch -n 5 cat /proc/mdstat

--zero-superblock 是本段最危险的一条命令。它只在两种情况下用:换上的是一块曾经属于别的阵列的盘,或者旧盘被误判要重新加入但 superblock 已经乱了。对着正在服务的数据盘跑这条命令,等于把那块盘从阵列里彻底抹掉,且没有后悔药。执行前务必确认设备名——用 lsblk -f 再核一遍。

RAID5:注意「热备盘」和重建顺序

RAID5 的替换逻辑和 RAID1 类似,但有两个额外变量:

  • 热备盘(spare)会自动顶上。如果你本来就配了 --spare-devices,阵列降级后重建会立刻自动开始,你 /proc/mdstat 里看到的就是 recovery = x%,这时候不用手动 --add,要做的是等它跑完。
  • 重建速度可以调,但别调太猛。默认的重建速率限制在 /proc/sys/dev/raid/speed_limit_max(默认 200000 KB/s)。业务时段想降速保护 I/O:
    echo 20000 > /proc/sys/dev/raid/speed_limit_max

    等到夜间再放开。但要注意,速度限制是「上限」不是「保底」,实际重建速率还受磁盘本身和并行 I/O 影响——上文的 speed=11766K/sec 就远低于上限。

重建期间,别做的四件事

  1. 不要重启。重建是内存里的状态推进,重启会从头再来(有些配置下甚至会因为 superblock 事件数不一致而拒绝自动组装)。
  2. 不要跑重负载任务。大文件打包、全站备份、批量重编码——都会和重建抢 I/O,把预计 2 小时的重建拖成 10 小时,也提高二次故障概率。
  3. 不要在重建期间改阵列拓扑。想加盘、想扩容量、想改 chunk size,全部等重建完成后再说。
  4. 不要只看百分比。百分比会停住甚至倒退,这是正常的(I/O 抖动)。看 finish= 那一段的剩余时间趋势更有意义。

第五步:让阵列在重启后能自动组装——mdadm.conf 与 initramfs

这是最经典的「救援时才发现」的坑:你把阵列修好了,运行正常,然后一次重启,阵列没了。原因通常是 /etc/mdadm/mdadm.conf 里的 ARRAY 行和实际根设备不一致,或者 initramfs 里的那份配置是旧的。

# 用当前真实状态生成配置(比手写可靠得多)
mdadm --detail --scan >> /etc/mdadm/mdadm.conf

# 去重后再跑一次,然后同步进 initramfs
update-initramfs -u -k all

Debian/Ubuntu 上配置文件的路径是 /etc/mdadm/mdadm.conf,部分发行版在 /etc/mdadm.conf,改错文件等于没改。判断有没有生效,看 initramfs 里是否包含 mdadm 的自动组装脚本:

lsinitramfs /boot/initrd.img-$(uname -r) | grep -i mdadm

如果这里什么都没有,那么启动时阵列只能靠 udev 的自动识别,在成员盘全在时通常没事,一旦有盘掉线就可能组装失败,进而卡在 (initramfs) 提示符——那就同时是引导故障和存储故障了,排查复杂度直接翻倍。

第六步:用监控把「下一次」变成「提前知道」

软 RAID 最大的问题是它坏得很安静。阵列降级只是内核日志里的一行,网站照常访问,直到第二块盘坏掉才爆出来。所以监控不是可选项。

方案一:mdadm 自带邮件告警

在 /etc/mdadm/mdadm.conf 里加:

MAILADDR you@example.com
PROGRAM /usr/share/mdadm/checkarray --cron --all --quiet

然后确保 /etc/default/mdadm 里 DAEMON_OPTIONS 带上了监控相关参数。注意这条路依赖本机 MTA 能发信出去——如果没有配 SPF/DKIM/DMARC,告警邮件大概率直接进垃圾箱,等于没告警。这是个非常典型的「配置了但没用」的失败模式。

方案二:cron + 脚本判读 /proc/mdstat

更可靠的做法是自己写 20 行脚本,直接判读 /proc/mdstat 里的 degraded / _ 状态,通过 Telegram、企业微信或钉钉机器人推送。好处是不依赖邮件链路,且推送到达率有保障。判据要注意一个细节:重建中(recovering)也算「有下划线」,但这是正常状态,脚本里必须把 recovery/resync 单独排除,否则每次正常重建都会刷一堆误报,久而久之就没人看告警了。

方案三:连 SMART 一起监控

只监控 RAID 状态是不够的,理想情况下要在阵列降级之前就发现盘要坏。smartd 配合 smartctl -t short 的定期自检能在 Reallocated_Sector_Ct 持续增长时就预警。把 SMART 趋势和 mdstat 状态放在同一块看板上,才是完整的存储健康视图。

小结

软件 RAID 降级的处理,核心不是「怎么换盘」,而是顺序和判读:

  • 先判读:/proc/mdstat 看缺几块、mdadm --detail 看哪块 faulty、mdadm --examine 用事件计数在无日志时定位掉队盘。
  • 再定性:dmesg -T + smartctl -a 分清是链路问题还是介质问题——很多「故障盘」换上去之后发现是好的。
  • 先备份再动手:降级的阵列随时可能彻底失效,导出数据永远排在修盘之前。
  • 换盘时小心 --zero-superblock:它只该对着确认无用的新盘跑。
  • 修完要落盘**:mdadm --detail --scan 写进 mdadm.conf,再 update-initramfs,否则重启后阵列可能组装不起来。

最后一句实话:如果你现在还在用 RAID1 当唯一的备份手段,那它其实不是备份。RAID 只解决「盘坏不停机」,不解决「误删能回滚」「机房出事能异地恢复」。阵列修好之后,顺手把异地备份那条链路也检查一遍,才算真的把这个隐患关掉了。

Last modification:September 28th, 2026 at 12:25 pm

Leave a Comment