Linux 基础体系 · 第 58/85 篇。示例面向现代主流 Linux 发行版;发行版差异、权限和生产风险会明确说明。
Linux 软件 RAID:mdadm、级别、重建、降级、监控和恢复
Linux 软件 RAID 由内核中的 md(multiple devices)驱动和用户空间工具 mdadm 共同实现。内核负责把多个块设备组合成一个逻辑块设备,例如 /dev/md0;mdadm 负责创建阵列、写入 RAID 元数据、组装阵列、处理成员替换以及监控状态。
RAID 的目标主要是提高可用性、容量或吞吐,不是备份。RAID 无法防止误删除、文件系统损坏、勒索软件、主机整体损坏或同步写入的逻辑错误。
本文中的命令面向现代主流 Linux 发行版。设备名、配置文件路径、systemd 服务名和 initramfs 更新命令可能因发行版不同而变化;涉及真实磁盘的命令必须先确认设备身份。
1. RAID 在块设备栈中的位置
一个典型的 Linux 存储栈可以表示为:
物理磁盘
└─ 分区,例如 /dev/sdb1
└─ md RAID 成员
└─ /dev/md0
└─ 文件系统,例如 ext4 或 XFS
└─ 挂载点,例如 /data
如果还使用 LVM,常见布局是:
物理磁盘
└─ 分区
└─ /dev/md0
└─ LVM PV
└─ VG
└─ LV
└─ 文件系统
也可以把 RAID 放在 LVM 之上,但两者承担的职责不同:
- RAID 提供成员冗余、条带化和重建能力。
- LVM 提供逻辑卷划分、快照和容量管理。
- 文件系统负责文件、目录、元数据和空间分配。
- 挂载负责把文件系统接入目录树。
应用通常不应该直接访问 /dev/sdb1 这类 RAID 成员,而应该访问 /dev/md0、其上的逻辑卷或文件系统。
1.1 先确认设备,而不是凭设备名猜测
以下命令用于查看块设备拓扑:
lsblk -o NAME,PATH,SIZE,TYPE,FSTYPE,UUID,MOUNTPOINTS,MODEL,SERIAL
findmnt
cat /proc/mdstat
示例:
NAME PATH SIZE TYPE FSTYPE MOUNTPOINTS
sda /dev/sda 1.8T disk
├─sda1 /dev/sda1 1.8T part
sdb /dev/sdb 1.8T disk
└─sdb1 /dev/sdb1 1.8T part
md0 /dev/md0 1.8T raid1 ext4 /data
lsblk 显示的是当前设备树,/proc/mdstat 显示的是内核 md 阵列状态。两者都正常并不意味着底层磁盘健康,还需要检查 SMART:
sudo smartctl -a /dev/sdb
smartctl 属于 smartmontools,可能需要单独安装。对于硬件 RAID 控制器后的磁盘,SMART 查询方式还取决于控制器。
2. mdadm 管理的是什么
mdadm 不是文件系统工具,也不是通用的磁盘复制工具。它主要管理三类信息:
- 阵列配置:RAID 级别、成员数量、条带大小、布局。
- 成员状态:活动、备用、故障、移除、重建中。
- 超级块(superblock):阵列 UUID、设备角色、事件计数、阵列级别等元数据。
创建阵列时,mdadm 会把 RAID 元数据写入成员设备。之后系统可以根据超级块识别哪些设备属于同一阵列。
常用查看命令:
sudo mdadm --detail /dev/md0
sudo mdadm --examine /dev/sdb1
sudo mdadm --examine --scan
cat /proc/mdstat
其中:
--detail查看已经组装的逻辑阵列。--examine直接读取成员设备上的 RAID 超级块。--examine --scan根据超级块生成可用于组装的阵列描述。/proc/mdstat是内核提供的实时概览,适合快速观察同步、重建和降级状态。
典型的 mdadm --detail 输出可能包含:
/dev/md0:
Raid Level : raid1
Array Size : 1953381376
Used Dev Size : 1953381376
Raid Devices : 2
Total Devices : 2
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
这里的 Array Size 是阵列对上层提供的容量,不等于所有成员容量之和。Active Devices 是当前参与工作的成员,Working Devices 还包括可能尚未成为活动成员但设备仍可工作的成员;生产判断应结合完整输出,而不是只看一行。
3. RAID 级别的容量和容错条件
设:
- 是成员设备数量;
- 是可用于 RAID 的最小成员容量;
- 是阵列可用容量。
实际容量还会受到超级块、分区对齐和元数据开销影响,下面的公式用于理解主要关系。
3.1 RAID0:条带化,没有冗余
RAID0 把连续数据分散到多个成员:
条带 0 → 磁盘 A
条带 1 → 磁盘 B
条带 2 → 磁盘 C
条带 3 → 磁盘 D
容量近似为:
但是任意一个成员失效,都可能导致整个阵列无法恢复,因为一个文件的数据可能分布在多个成员上。RAID0 的“性能”和“容量”不能被误解为可靠性。
创建示例:
sudo mdadm --create /dev/md0 \
--level=0 \
--raid-devices=2 \
/dev/sdb1 /dev/sdc1
对于只要可用性而不是临时高速空间的生产数据,不应使用 RAID0。
3.2 RAID1:镜像
RAID1 把相同数据写入多个成员:
写入块 X
├─ 磁盘 A:X
└─ 磁盘 B:X
等容量成员组成的 RAID1 容量近似为:
两个成员时,可以容忍一个成员失效。三个成员时,理论上只要仍有一个一致且可工作的副本,阵列还可以继续提供数据;但多个成员同时故障后的安全性取决于故障顺序、事件计数和阵列状态。
创建两个成员的 RAID1:
sudo mdadm --create --verbose /dev/md0 \
--metadata=1.2 \
--level=1 \
--raid-devices=2 \
/dev/sdb1 /dev/sdc1
RAID1 适合系统盘、数据库镜像和需要简单恢复路径的场景。它不提供 RAID0 那样的容量叠加,写入也通常需要更新多个副本。
3.3 RAID5:条带化加单校验
RAID5 在每个条带中保存数据块和一个校验块。校验通常可以抽象为异或:
其中:
- 是同一条带中的数据块;
- 是校验块;
- 是按位异或。
如果丢失一个数据块,例如 ,可以计算:
因此,等容量成员组成的 RAID5 容量近似为:
RAID5 只能容忍一个成员故障。两个成员同时失效时,单个校验无法唯一确定两个未知数据块。
例如四块 4 TB 磁盘组成 RAID5:
- 原始容量:16 TB;
- 近似可用容量:12 TB;
- 可容忍:1 块成员故障;
- 第二块成员在重建完成前故障:阵列通常无法继续恢复全部数据。
创建示例:
sudo mdadm --create --verbose /dev/md0 \
--metadata=1.2 \
--level=5 \
--raid-devices=4 \
/dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1
RAID5 的写入可能涉及“读-改-写”:
- 读取旧数据块;
- 读取旧校验块;
- 计算新校验;
- 写入新数据和新校验。
完整条带写入可以避免部分读操作,但随机小写仍可能产生较高的写放大和延迟。RAID5 还必须面对条带更新过程中断电造成的数据与校验不一致问题;具体保护能力取决于内核 md RAID5 实现、设备写入保证以及是否启用相应的保护机制,不能把“有校验”当成“断电事务一致性”。
3.4 RAID6:双校验
RAID6 保存两组独立校验,通常称为 P 和 Q。它不只是把 RAID5 的同一个异或校验复制一次,而是使用能够在两个未知块存在时求解的双校验算法。
等容量成员的容量近似为:
RAID6 可以容忍任意两个成员同时故障。六块 4 TB 磁盘组成 RAID6 时,近似容量为 16 TB,可容忍两块成员故障。
RAID6 需要更多校验计算和写入工作,重建也可能更慢,但对于大容量磁盘和较长重建窗口,双故障容忍通常比 RAID5 更重要。
3.5 RAID10:镜像组上的条带化
RAID10 先形成镜像关系,再在镜像组之间条带化。四块磁盘的常见布局可以抽象为:
镜像组 0:A ↔ B
镜像组 1:C ↔ D
条带 0 → 镜像组 0
条带 1 → 镜像组 1
条带 2 → 镜像组 0
条带 3 → 镜像组 1
等容量成员的常见容量约为:
RAID10 至少需要两个成员,但生产中通常使用四块或更多磁盘。它至少可以容忍一个成员故障;如果故障成员分布在不同镜像组,也可能同时容忍多个故障。如果同一镜像组的两个成员都失效,则对应数据丢失。
因此,“RAID10 可以坏两块盘”不是无条件结论。正确说法是:它可以容忍多个故障,但不能让同一镜像副本的两个成员都丢失。
创建四成员 RAID10:
sudo mdadm --create --verbose /dev/md0 \
--metadata=1.2 \
--level=10 \
--raid-devices=4 \
/dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1
mdadm 的 RAID10 还涉及 near、far、offset 等布局参数。布局会影响副本位置、顺序访问和随机访问特性,不应仅凭“RAID10”三个字推断所有性能行为。若没有明确的性能测试和恢复要求,通常先使用发行版和 mdadm 默认布局,并记录实际配置。
4. 超级块、元数据和启动行为
mdadm 的超级块用于识别阵列成员。常见元数据版本包括:
0.90:旧式格式,兼容性限制较多;1.0:超级块位于设备末尾;1.1:超级块位于设备起始位置附近;1.2:现代系统常见格式,超级块位于设备前部,但通常不会覆盖整个设备。
创建时可以显式指定:
--metadata=1.2
1.2 通常适合数据阵列,但如果阵列直接承载引导所需内容,必须同时考虑固件、GRUB、initramfs 和发行版支持。某些引导环境对超级块位置、组件启动方式或 RAID 级别存在限制。
创建阵列后,应把阵列识别信息写入系统配置。例如 Debian 系常见路径是:
sudo mdadm --detail --scan | sudo tee -a /etc/mdadm/mdadm.conf
sudo update-initramfs -u
其他发行版可能使用 /etc/mdadm.conf,并通过:
sudo dracut -f
更新 initramfs。配置文件路径和服务名称必须以目标发行版文档为准。若只创建了阵列却没有更新 initramfs,系统可能在启动早期无法组装根文件系统所在阵列。
5. 从创建到挂载:一个完整流程
以下示例假设 /dev/sdb1 和 /dev/sdc1 已经是两个专用于 RAID1 的分区。它们不能包含需要保留的数据。
5.1 分区和设备准备
先确认设备:
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL,SERIAL
sudo wipefs -n /dev/sdb1
sudo wipefs -n /dev/sdc1
wipefs -n 只探测签名,不执行擦除。确认不再需要旧数据后,才可以使用不带 -n 的 wipefs;对错误设备执行擦除会立即破坏可恢复性。
现代 GPT 分区通常应设置为 Linux RAID 分区类型。可以使用 fdisk、gdisk 或 parted 完成,但分区工具的语法和类型标识会因工具版本不同。重点是两个分区的起始位置对齐,并且成员容量足够一致。
5.2 创建阵列并等待初始同步
sudo mdadm --create --verbose /dev/md0 \
--metadata=1.2 \
--level=1 \
--raid-devices=2 \
/dev/sdb1 /dev/sdc1
创建后立即查看:
cat /proc/mdstat
sudo mdadm --detail /dev/md0
同步中的输出可能类似:
md0 : active raid1 sdc1[1] sdb1[0]
976630336 blocks super 1.2 [2/2] [UU]
[===>.................] resync = 18.4% ...
[UU] 表示两个成员都在线;如果显示 [U_],表示第二个位置缺失。即使 RAID1 在同步过程中已经可以提供服务,也不代表它已经完成冗余建立。此时再次故障的风险更高。
5.3 在阵列上创建文件系统
不要在单个 RAID 成员上创建文件系统,而要在 /dev/md0 上创建:
sudo mkfs.ext4 /dev/md0
sudo mkdir -p /data
sudo mount /dev/md0 /data
df -h /data
文件系统 UUID 可以用于 /etc/fstab:
sudo blkid /dev/md0
/etc/fstab 示例:
UUID=<md0-filesystem-uuid> /data ext4 defaults,nofail 0 2
nofail 是否适合生产环境取决于业务要求。它可以避免非根文件系统不可用时阻塞启动,但也可能让服务在数据目录没有挂载的情况下启动。对必须使用数据盘的服务,应让启动失败显式暴露问题,而不是静默使用空目录。
6. 阵列状态:clean、degraded、rebuilding 和 reshape
可以把 md 阵列的关键状态理解为数据可用性和冗余状态的组合。
6.1 clean
clean 表示阵列已同步完成,当前成员状态与阵列配置一致。它不等于:
- 所有物理磁盘健康;
- 文件系统没有错误;
- 数据已经备份;
- 没有潜伏坏块。
6.2 degraded:降级
降级表示阵列仍能提供数据,但缺少一个或多个预期成员。例如 RAID1 两个成员中掉了一个,状态可能是:
State : clean, degraded
Active Devices : 1
Working Devices : 1
Failed Devices : 1
对于 RAID5,缺一块仍可工作;对于 RAID6,缺两块仍可工作。降级期间阵列的容错余量降低,通常也会有额外的读、校验或重建压力。
降级本身不等于数据已经损坏,但它是一个必须处理的故障状态。
6.3 recovery:从备用或新成员恢复副本
recovery 通常表示从现有有效数据向备用成员或新加入成员复制缺失内容。例如 RAID1 更换故障盘后,活动成员把数据同步到新盘。
6.4 resync:重新同步
resync 通常表示对成员之间的内容进行同步或一致性检查。新建阵列后的初始同步也经常显示为 resync。
6.5 reshape:改变阵列结构
reshape 是改变 RAID 结构,例如:
- RAID5 增加成员;
- RAID1 改变镜像成员数量;
- 修改某些布局或条带参数。
reshape 不是普通故障重建。它可能移动大量已有数据,持续时间长,期间故障路径和恢复步骤也更复杂。执行前必须确认备份、供电和监控条件。
7. 故障成员的处理:fail、remove、add
假设 /dev/md0 是 RAID1,内核报告 /dev/sdb1 出错。
7.1 先区分瞬时错误和物理故障
先查看:
dmesg -T | grep -Ei 'ata|scsi|I/O error|uncorrect|reset|md'
sudo smartctl -a /dev/sdb
sudo mdadm --detail /dev/md0
如果只是线缆、背板或控制器瞬时异常,直接把盘标记为故障并移除可能扩大问题。反过来,如果磁盘已经出现大量不可校正错误,继续让它参与重建也可能导致更多 I/O 错误。
7.2 手动标记故障并移除
sudo mdadm --manage /dev/md0 --fail /dev/sdb1
sudo mdadm --manage /dev/md0 --remove /dev/sdb1
--fail 把成员标记为故障,使 md 不再把它作为正常副本使用;--remove 从当前阵列活动列表移除它。执行后检查:
cat /proc/mdstat
sudo mdadm --detail /dev/md0
如果磁盘只是暂时掉线,有时可以直接重新加入:
sudo mdadm --manage /dev/md0 --re-add /dev/sdb1
但只有在确认设备、分区和超级块仍然正确时才这样做。不要对一个已经确定存在介质故障的磁盘使用 --re-add 来掩盖问题。
7.3 更换磁盘并加入
新盘必须至少满足阵列要求的成员容量。实际可用容量由分区大小决定,因此“标称容量相同”不一定足够;不同型号的扇区数可能略有差异。
把新盘分区复制为与旧盘相同的布局时,必须明确源盘和目标盘。例如目标盘是全新的 /dev/sdb:
sudo sfdisk -d /dev/sda | sudo sfdisk /dev/sdb
这条命令会覆盖目标盘的分区表,不能把 /dev/sda 和 /dev/sdb 的身份搞反。复制后确认:
lsblk /dev/sdb
sudo fdisk -l /dev/sdb
然后加入阵列:
sudo mdadm --manage /dev/md0 --add /dev/sdb1
加入后,内核会开始 recovery。观察:
watch -n 2 cat /proc/mdstat
重建完成的典型状态:
md0 : active raid1 sdb1[2] sdc1[1]
[2/2] [UU]
这里的成员编号不一定等于分区名中的顺序,因此应以 mdadm --detail 的 State、Active Devices 和设备列表为准。
8. 重建的实际机制和速度取舍
以 RAID1 为例,重建过程大致如下:
- 阵列发现成员缺失,进入 degraded 状态。
mdadm监控或管理员把新成员加入阵列。- 内核 md 驱动读取现有有效副本。
- 数据被写入新成员对应位置。
- 根据同步进度更新状态。
- 完成后阵列回到 clean、非降级状态。
RAID5/6 的重建更复杂。重建一个缺失成员时,系统需要读取其他成员并计算缺失数据;如果遇到不可读取扇区,可能导致重建失败或暴露潜在数据问题。
Linux md 可以使用 bitmap 记录哪些区域发生过写入。写意图位图(write-intent bitmap)使短暂掉线的成员重新加入时,只需同步可能变化的区域,而不是盲目扫描整个阵列。它不能替代完整校验,也不能保证长期离线成员只需同步极少数据。
查看是否启用 bitmap:
sudo mdadm --detail /dev/md0
某些阵列可以配置内部 bitmap:
sudo mdadm --grow /dev/md0 --bitmap=internal
该操作是否适用于已有阵列、对性能和元数据的影响,要结合 mdadm 版本和 RAID 级别确认。不要在不了解当前阵列状态时直接执行 --grow。
内核通常通过以下参数限制 md 同步速度:
cat /proc/sys/dev/raid/speed_limit_min
cat /proc/sys/dev/raid/speed_limit_max
临时调整示例:
sudo sysctl -w dev.raid.speed_limit_min=50000
sudo sysctl -w dev.raid.speed_limit_max=200000
提高上限可能缩短重建时间,但会增加磁盘吞吐、队列深度和业务延迟;降低速度可以保护在线业务,却延长阵列处于低冗余状态的时间。调优不能脱离磁盘性能、业务 I/O 模式和故障窗口。
9. 监控:不能只看 /proc/mdstat
9.1 即时检查
cat /proc/mdstat
sudo mdadm --detail /dev/md0
/proc/mdstat 适合观察:
- 是否有阵列;
- 是否降级;
- 是否正在 resync、recovery 或 reshape;
- 大致进度和速度。
mdadm --detail 更适合确认:
- RAID 级别;
- 期望成员数;
- 当前活动成员;
- 故障成员;
- 备用成员;
- UUID 和事件信息。
9.2 mdadm monitor
常见的监控形式是:
sudo mdadm --monitor --scan --mail=ops@example.com
守护进程模式和邮件配置的具体参数、服务管理方式因发行版版本不同而变化。许多系统通过 systemd 的 mdmonitor、mdadm-monitor 或发行版自定义单元启动监控;应使用以下命令确认:
systemctl list-unit-files | grep -i md
systemctl status mdmonitor.service
systemctl status mdadm-monitor.service
不要假设服务名在所有发行版中相同。
监控至少应在以下事件发生时告警:
- 阵列降级;
- 成员故障或被移除;
- 重建失败;
- reshape 失败;
- 阵列停止;
- 监控服务自身停止。
告警系统应验证“邮件或事件是否真的送达”,不能只把命令写入配置文件就认为监控已经生效。
9.3 SMART 和系统 I/O 指标
RAID 状态正常并不代表磁盘没有潜在故障。应结合:
sudo smartctl -H /dev/sdb
sudo smartctl -a /dev/sdb
iostat -xz 5
iostat -xz 5 可以观察设备利用率、平均等待时间、队列长度和吞吐。重建期间,磁盘 %util 接近饱和、await 上升、队列变长,可能是正常的重建压力,也可能说明业务已经受到影响。要区分这两种情况,需要同时观察业务延迟和阵列进度。
RAID 监控回答的是“阵列是否缺成员”;SMART 和 I/O 监控回答的是“成员是否正在恶化”和“业务是否受到性能影响”。三者不能互相替代。
10. 在线扩容:RAID、分区、LVM 和文件系统是四个步骤
“给 RAID 增加磁盘后容量自动增加”是常见误解。在线扩容通常要经过以下层次:
新磁盘分区变大或增加新成员
→ mdadm 扩展阵列结构
→ md 设备容量变大
→ LVM PV/LV 扩展(如果使用 LVM)
→ 文件系统扩展
10.1 RAID1 增加成员
先把新分区加入:
sudo mdadm --manage /dev/md0 --add /dev/sdd1
这通常只会增加备用成员,不一定立即改变 RAID1 的有效容量。若要把 RAID1 从两个镜像成员扩展为三个:
sudo mdadm --grow /dev/md0 --raid-devices=3
不同 RAID 级别对 --grow 的支持和限制不同,执行前应检查当前 mdadm 版本的手册。扩展会触发同步,期间仍然存在额外 I/O 和故障风险。
10.2 RAID5 增加成员
典型顺序是:
sudo mdadm --manage /dev/md0 --add /dev/sde1
sudo mdadm --grow /dev/md0 --raid-devices=5
这会触发 reshape,将原有条带重新映射到新的成员数量。reshape 期间不能把阵列当作普通“加入一块备用盘”处理;必须监控进度,并在变更前确认备份和恢复方案。
10.3 RAID 设备之后的文件系统扩展
如果 /dev/md0 上直接是 ext4:
sudo mdadm --grow /dev/md0 --size=max
sudo resize2fs /dev/md0
如果是 XFS,扩展通常对挂载点执行:
sudo xfs_growfs /data
XFS 通常支持在线扩大,但不能按同样方式缩小。
如果 md 上是 LVM,则应先扩大 md 设备,再执行类似:
sudo pvresize /dev/md0
sudo lvextend -l +100%FREE /dev/vgdata/lvdata
sudo resize2fs /dev/vgdata/lvdata
对于 XFS:
sudo xfs_growfs /data
每一步都要验证:
sudo mdadm --detail /dev/md0
sudo pvs
sudo vgs
sudo lvs
df -h /data
缩容比扩容复杂得多,必须先缩小文件系统,再缩小逻辑卷、PV 和 RAID 结构。文件系统是否支持在线缩小也不同;错误顺序可能直接截断数据。
11. 阵列组装和启动恢复
正常启动时,系统根据 initramfs、mdadm.conf 和超级块自动组装阵列。手动检查成员:
sudo mdadm --examine /dev/sdb1 /dev/sdc1 /dev/sdd1
尝试扫描并组装:
sudo mdadm --assemble --scan --verbose
组装成功后:
cat /proc/mdstat
lsblk
sudo mdadm --detail /dev/md0
如果阵列没有自动组装,常见原因包括:
- initramfs 没有包含 mdadm 配置;
- 阵列配置文件缺失;
- 成员设备尚未出现;
- 磁盘连接或控制器有问题;
- 超级块中的 UUID 不一致;
- 阵列曾经异常停止,成员事件计数存在差异。
可以比较成员的元数据:
for d in /dev/sdb1 /dev/sdc1 /dev/sdd1; do
echo "=== $d ==="
sudo mdadm --examine "$d"
done
重点观察阵列 UUID、设备角色、事件计数和设备状态。不要仅凭设备文件名决定成员顺序。
12. 恢复时最危险的命令:--force、--create 和 --zero-superblock
12.1 --assemble --force
当成员的事件计数不一致时,--force 可能强行组装阵列。但这意味着管理员在接受一个判断:哪些成员包含较新的阵列状态,哪些成员可能是旧副本。
错误使用 --force 可能导致:
- 旧数据覆盖新数据;
- 阵列以错误成员组合启动;
- 文件系统出现静默损坏;
- 后续同步把错误传播到其他成员。
只有在已经保存各成员镜像或明确理解事件计数、设备角色和故障时间线时,才考虑使用它。恢复优先级应是先保护原始数据,再尝试组装。
12.2 不要用 --create “修复”已有阵列
对已有数据阵列执行:
mdadm --create /dev/md0 ...
可能重写超级块并破坏原始识别信息。即使使用了看似相同的 RAID 级别和成员数量,也不能保证条带大小、布局、设备角色和事件状态完全一致。
恢复已有阵列的第一选择通常是:
sudo mdadm --assemble --scan
而不是重新 --create。
12.3 --zero-superblock 会删除 RAID 识别信息
以下命令会清除成员上的 md 超级块:
sudo mdadm --zero-superblock /dev/sdb1
它只适合已经确认不再属于任何需要保留的阵列成员、准备重新使用的设备。对仍有恢复价值的成员执行该命令,会增加恢复难度。
13. 不同故障路径的恢复策略
13.1 单成员故障,阵列仍在线
这是最常见的路径:
- 查看
mdadm --detail和内核日志; - 判断是暂时掉线还是物理故障;
- 物理故障时
--fail、--remove; - 准备容量足够的新成员;
--add加入;- 观察 recovery;
- recovery 完成后确认
[UU]或对应完整状态; - 检查 SMART 和硬件告警,找出故障根因。
只更换磁盘而不检查背板、电源、线缆和控制器,可能导致新盘再次掉线。
13.2 阵列降级但业务仍需运行
降级阵列通常可以继续挂载,但风险是容错能力已经下降。此时应减少不必要的高负载操作,尤其要谨慎处理 RAID5/6 的大规模校验和重建。
不要因为阵列还能读写,就把降级状态当成正常状态。恢复完成后仍应检查文件系统和业务数据,因为 RAID 只保证块级冗余,不保证应用事务逻辑。
13.3 多成员故障,超过 RAID 级别容错能力
RAID5 缺两块、RAID6 缺三块,通常无法从剩余信息唯一还原全部数据。此时不存在一个通用的 mdadm 参数可以“计算出”丢失的数据。
正确方向是:
- 立即停止可能造成写入的操作;
- 不要继续尝试随机组装组合;
- 尽可能对所有成员做扇区级镜像;
- 在镜像副本上进行恢复实验;
- 根据成员事件计数、设备角色和故障顺序重建阵列;
- 恢复文件后验证文件系统和业务数据;
- 必要时使用专业数据恢复工具或服务。
对有坏扇区的磁盘,优先考虑能够记录错误并断点续读的镜像工具,而不是反复对原盘执行高负载重建。
13.4 RAID1 成员内容不一致
RAID1 的两个成员都能读,并不表示它们的每个块都一致。若出现未被检测的静默损坏,系统需要依据阵列状态和同步策略决定使用哪个副本;管理员不能简单地假设“左边磁盘永远正确”。
因此:
- 不要随意交换成员顺序;
- 不要在没有备份的情况下强制指定同步方向;
- 对关键数据执行文件级校验或应用级校验;
- 结合事件计数、故障时间线和文件系统检查结果判断。
13.5 文件系统损坏不是 RAID 成员故障
如果阵列状态是 clean,但挂载失败:
sudo mdadm --detail /dev/md0
sudo fsck -f /dev/md0
fsck 是否安全取决于文件系统和挂载状态。通常文件系统检查应在卸载状态下进行;XFS 使用 xfs_repair,不能用 ext4 的 fsck 逻辑替代。
RAID 正常只说明 md 层能够提供块设备,不说明 ext4、XFS 或上层 LVM 元数据没有损坏。
14. 读取一致性检查和潜伏错误
长期运行的 RAID 可能存在“阵列看起来正常,但某些区域已经无法可靠读取”的问题。可以执行一致性检查:
echo check | sudo tee /sys/block/md0/md/sync_action
watch -n 2 cat /proc/mdstat
检查结果通常可以从以下接口查看:
cat /sys/block/md0/md/sync_action
cat /sys/block/md0/md/mismatch_cnt
check 会读取并比较阵列内容,可能占用大量 I/O。mismatch_cnt 非零表示发现不一致,但它不自动告诉你哪一份数据具备业务意义,也不等于已经定位了具体文件。
某些系统通过定时任务或 systemd timer 周期性执行阵列检查。应确认检查任务存在、能够完成,并且不会与业务高峰和重建任务产生不可接受的竞争。
15. 性能:RAID 级别只是起点
RAID 性能由以下因素共同决定:
- RAID 级别和布局;
- 条带大小(chunk size);
- 文件系统块大小和分配策略;
- 顺序或随机 I/O;
- 读写比例;
- 队列深度;
- 磁盘介质和控制器;
- 重建、校验或 reshape 是否正在运行。
例如 RAID5 的随机小写容易触发部分条带的读-改-写;顺序大写更容易形成完整条带。RAID1 读取可以从多个副本分配请求,但实际调度行为不能简单等同于“读取速度翻倍”。
使用 iostat 检查性能:
iostat -xz 5
重点关注:
r/s、w/s:读写请求速率;rkB/s、wkB/s:吞吐;await:平均请求等待时间;aqu-sz:平均队列长度;%util:设备忙碌程度。
%util 高不必然等于性能故障,NVMe、并发队列和设备实现会影响它的解释。必须结合延迟、吞吐、队列深度和业务请求时间判断。
16. 一个可重复的实验方式:使用 loop 设备
不想直接操作真实磁盘时,可以用文件创建实验阵列。但 loop 设备只能验证命令、状态和部分故障流程,不能代表真实磁盘的性能、掉电行为或介质错误。
示例:
mkdir -p ~/mdadm-lab
for n in 1 2; do
truncate -s 512M ~/mdadm-lab/disk${n}.img
done
loop1=$(sudo losetup --find --show ~/mdadm-lab/disk1.img)
loop2=$(sudo losetup --find --show ~/mdadm-lab/disk2.img)
sudo mdadm --create /dev/md99 \
--metadata=1.2 \
--level=1 \
--raid-devices=2 \
"$loop1" "$loop2"
cat /proc/mdstat
sudo mdadm --detail /dev/md99
sudo mkfs.ext4 /dev/md99
sudo mkdir -p /mnt/mdadm-lab
sudo mount /dev/md99 /mnt/mdadm-lab
echo test | sudo tee /mnt/mdadm-lab/example.txt
sync
模拟成员故障:
sudo mdadm --manage /dev/md99 --fail "$loop1"
cat /proc/mdstat
实验结束时:
sudo umount /mnt/mdadm-lab
sudo mdadm --stop /dev/md99
sudo losetup -d "$loop1"
sudo losetup -d "$loop2"
如果实验中途停止阵列或删除 loop 设备,应先确认没有挂载点和正在运行的 I/O。否则实验本身会制造与真实磁盘故障相似的错误。
17. 生产环境中的验证顺序
一次阵列变更或故障处理,至少应形成以下闭环:
识别设备
→ 查看 md 状态
→ 查看内核日志和 SMART
→ 执行最小必要变更
→ 观察 recovery/resync/reshape
→ 验证阵列状态
→ 验证文件系统和挂载
→ 验证业务读写与告警
例如更换成员后,不应只看到 mdadm --add 命令返回成功就结束。还应确认:
sudo mdadm --detail /dev/md0
cat /proc/mdstat
sudo dmesg -T | tail -n 100
df -h /data
sudo systemctl status mdmonitor.service
最终目标不是“命令执行成功”,而是:
- 阵列成员数量正确;
- 没有 failed 或 removed 成员;
- recovery 已完成;
- 文件系统仍然挂载并可读写;
- 监控能够报告下一次故障;
- 替换下来的旧盘没有被误认为新盘;
- 配置已写入 initramfs 和系统持久化配置。
18. 必须牢记的边界
RAID 级别提供的是明确的块级故障模型:
- RAID0:扩大容量和条带化,但没有容错;
- RAID1:保存多个副本,容量按一份计算;
- RAID5:一个校验,可容忍一个成员故障;
- RAID6:双校验,可容忍两个成员故障;
- RAID10:镜像与条带组合,容错取决于故障是否集中在同一镜像组。
mdadm 负责管理阵列,而不是替代备份、文件系统检查、SMART 监控、灾难恢复演练或应用级数据校验。真正可靠的存储方案必须同时回答四个问题:
- 单块磁盘故障时,阵列能否继续服务?
- 重建期间再次故障时,阵列是否仍有容错余量?
- 阵列元数据、文件系统和启动配置损坏时,如何恢复?
- 误删除、逻辑损坏和主机整体丢失时,备份在哪里?
只有把这些问题分别验证过,/dev/md0 才不只是一个“看起来正常”的块设备,而是可监控、可重建、可恢复的存储组件。
系列导航与关联阅读
- 系列入口:Linux 完整学习路线:从内核与文件系统到网络、性能和生产运维
- 上一篇:LVM 深入:PV、VG、LV、Thin Pool、Snapshot、扩缩容和恢复
- 下一篇:Linux NFS:协议、挂载、缓存、一致性、权限和高可用
- 延伸:Linux 块设备与存储:分区、LVM、RAID、挂载和在线扩容
- 延伸:Linux 磁盘性能诊断:iostat、延迟、队列深度、吞吐和饱和度
官方资料
本文依据 Linux 内核、systemd 与主流发行版官方文档重新梳理;正文与实验由 WR BLOG 编写。

评论
0 条讨论