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就远低于上限。
重建期间,别做的四件事
- 不要重启。重建是内存里的状态推进,重启会从头再来(有些配置下甚至会因为 superblock 事件数不一致而拒绝自动组装)。
- 不要跑重负载任务。大文件打包、全站备份、批量重编码——都会和重建抢 I/O,把预计 2 小时的重建拖成 10 小时,也提高二次故障概率。
- 不要在重建期间改阵列拓扑。想加盘、想扩容量、想改 chunk size,全部等重建完成后再说。
- 不要只看百分比。百分比会停住甚至倒退,这是正常的(I/O 抖动)。看
finish=那一段的剩余时间趋势更有意义。
第五步:让阵列在重启后能自动组装——mdadm.conf 与 initramfs
这是最经典的「救援时才发现」的坑:你把阵列修好了,运行正常,然后一次重启,阵列没了。原因通常是 /etc/mdadm/mdadm.conf 里的 ARRAY 行和实际根设备不一致,或者 initramfs 里的那份配置是旧的。
# 用当前真实状态生成配置(比手写可靠得多)
mdadm --detail --scan >> /etc/mdadm/mdadm.conf
# 去重后再跑一次,然后同步进 initramfs
update-initramfs -u -k allDebian/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 只解决「盘坏不停机」,不解决「误删能回滚」「机房出事能异地恢复」。阵列修好之后,顺手把异地备份那条链路也检查一遍,才算真的把这个隐患关掉了。