搞 Linux 服务器的人,迟早会碰上这么一件事:机器刚买回来,手里攥着四块崭新的硬盘,老板说“数据要稳,坏一块盘不能丢数据”,但又没批硬件 RAID 卡的钱。这时候软件 RAID 就是最务实的解法,而 mdadm 就是 Linux 下管理软件 RAID 的事实标准工具。
我第一次正经用 mdadm 是十多年前给一台跑业务数据库的机器做阵列,当时心里其实没底,觉得软件 RAID 不如硬件 RAID 卡“正统”。但后面在生成环境上跑了好几年,经历了两次坏盘热替换,一次意外断电重启,数据都稳稳当当,算是彻底改变了我的看法。对于绝大多数中小企业服务器、自建 NAS、甚至个人开发机来说,Linux 软件 RAID 搭配 mdadm,可靠性和性价比完全够用,前提是你得真懂它,而不是瞎敲几条命令就撒手不管。
这篇文章我尽量把 mdadm 从原理到实战操作捋清楚,包括 RAID 级别怎么选、阵列怎么建、日常怎么盯、坏了盘怎么处理,以及我踩过的那些坑。内容有点长,但都是实操里验证过的干货,适合想真正弄懂软件 RAID 的运维和开发者。
1. 整体设计与思路拆解:为什么选择软件 RAID 而不是直接上硬件卡
1.1 软件 RAID 的核心定位:一个“用 CPU 换数据安全”的划算买卖
先得把概念摆正。软件 RAID 不是说有某个应用程序在用户态帮你做数据分条和校验,真正的读写逻辑在内核里,md 驱动直接接管底层块设备,把多块物理硬盘抽象成一个逻辑块设备。mdadm 全程叫作 “MD (Multiple Device) administer”,大部分时候只是一个管理工具,负责创建、组装、监控和管理这些 md 设备,真正的数据搬运工是内核里的 md 模块。这意味着软件 RAID 不是“模拟 RAID”,它就是“内核级 RAID”,只是实现方式跟带独立处理器的阵列卡不一样。
为什么说它是划算买卖?硬件 RAID 卡的本质是带一颗专用 RAID 芯片、一个缓存、甚至带电池保护的独立小系统,它在主板 BIOS 阶段就能接管磁盘,操作系统根本不需要知道你下面有几块盘。而软件 RAID 是操作系统层的逻辑,CPU 要参与数据分条的计算,尤其是 RAID5、RAID6 的校验运算会消耗 CPU 资源。但现在的服务器 CPU 动不动十几核几十线程,那点校验计算就像大象驮一根羽毛,何况 md 层还支持把校验计算卸载到支持 CRC 指令的 CPU 上。真正有瓶颈的场景是很极端的 IO 压力,比如每秒几十万次的小块随机写,那时软件 RAID 的 CPU 开销才会明显显现。对绝大多数业务来说,这个“CPU 换数据安全”的买卖非常划算。
1.2 硬件 RAID 与软件 RAID 的差异对照:别被“硬件一定更快”骗了
很多人一提到 RAID,第一反应就是“得买阵列卡”。这个认知不能说错,但至少要分场景。硬件 RAID 的优势是独立处理、带缓存、系统崩了阵列配置也不丢,缺点同样明显:贵、不同厂商卡驱动互相打架、卡坏了换同型号卡可能还有兼容性问题。
软件 RAID 的优势正好相反:不依赖特定硬件,任何 Linux 发行版都自带支持,系统坏了把盘插到另一台 Linux 机器上,mdadm 只要认到同一个阵列成员就能重新组装出来。这在我们运维圈里有个“救命”场景:机器主板烧了,手边随便找台服务器,把原有数据盘插上去,mdadm --assemble --scan 就能把阵列拉起来,里面业务照跑。硬件 RAID 卡要实现这种迁移,基本得找同品牌同型号的卡,不然配置不认。下表是我整理的兩者核心差异:
| 对比维度 | 软件 RAID (mdadm) | 硬件 RAID |
|---|---|---|
| 成本 | 完全免费,内核自带 | 阵列卡几百到几千元不等 |
| 性能开销 | 占用少量 CPU/内存 | 卡上独立芯片处理 |
| 迁移性 | 极高,跨机器重组能力强 | 依赖同型号或同厂商阵列卡 |
| 缓存/掉电保护 | 依赖文件系统层(如 journal) | 卡带缓存和电池/电容保护 |
| 配置复杂度 | 命令和配置文件需理解 | BIOS/工具界面操作直观 |
| 故障恢复 | 需要手动干预的场景多 | 部分卡支持自动重建 |
我个人用下来的感受是:如果你的工作负载是数据库这种需要大量小随机写且对延迟极其敏感的,硬件 RAID 卡的缓存确实能兜底很多写放大问题;但如果是文件存储、备份服务器、Web 服务、代码仓库,软件 RAID 的表现已经够优秀了,省下来的钱加几块盘都比买卡划算。
1.3 让我坚定选择 mdadm 的几个理由
接触过几套硬件阵列卡之后,我对软件 RAID 的信任反而更足了。一个很现实的点是,硬件 RAID 卡的 BIOS 配置界面普遍还是上世纪风格,操作逻辑晦涩,而且各家厂商的配置工具互不通用。做运维的人应该都有这种经历:新来的同事误删了阵列配置,或者是阵列卡电池报警,整个阵列进入只读模式,查了半天才发现是卡的问题。而 mdadm 的配置文件就是 /etc/mdadm.conf 一个文本文件,阵列成员、UUID、命名规则写得明明白白,出问题了一套 grep 就能定位,这种透明可排查性让它在生产环境里显得尤其可靠。
另一个让我对 mdadm 死心塌地的场景就是阵列迁移。有一次机房迁移,旧服务器怎么都点不亮,折腾了半小时发现是主板供电模块老化。当时查了下备件库存,同型号主板没有现货,接口都不一样,根本没法直接把盘插上去。最后找了一台系统盘容量、接口数量都够的其他型号服务器,把阵列里的数据盘以非系统盘身份接上去,开机后执行 mdadm --assemble --scan,几秒内就把原 RAID6 阵列完整拉起来了。那个瞬间我对软件 RAID 的信任值直接拉满,硬件卡哪有这种灵活性。
2. 核心细节解析与实操要点:RAID 级别选择与 mdadm 关键机制
2.1 各 RAID 级别怎么选:不只是 0、1、5 的简单排序
很多新手上来就问“RAID5 是不是比 RAID1 好”,这是个典型误区。RAID 级别没有绝对的好坏,只有合适不合适。选级别之前得先问自己三个问题:你的数据能不能容忍丢失?你需要多少可用容量?你接受写性能打几折?
先看RAID0:把两块或以上磁盘合并成一个大卷,数据均匀分条写入,所有盘并行读写。优点是可以把所有磁盘容量全部用上,读写性能接近线性增长。缺点无需多说,任何一块盘坏了,整个阵列就归零,数据全丢。它只适合完全不重要的临时数据,比如渲染农场缓存、日志采集缓冲。别把重要数据放 RAID0,这个道理我见过太多次有人用血泪验证了。
再看RAID1:最少两块盘,每份数据写两份分别落到不同磁盘,读性能理论上翻倍,写性能跟单盘持平。容量利用率是 50%,即两块 2TB 盘最终你只拿到 2TB。这是最稳妥、恢复逻辑最简单的级别,非常适合系统盘、数据库日志盘、配置存储这类需要绝对可靠且数据量不大的场景。我自己装系统时就喜欢拿两快小容量 SSD 组 RAID1 装系统,系统崩了阵列还在,重装系统数据也在,省去了很多备份恢复的麻烦。
RAID5:最少三块盘,数据分条加分布式校验。它用一块盘的容量做校验,比如三块 4TB 盘组 RAID5,真实可用 8TB,坏任意一块盘数据不丢,换上新盘后重建即可。写性能因为每次写入都要计算并更新校验数据会有折扣,但读性能不错。这是中小型企业文件服务器非常常见的方案,性价比高,容错能力覆盖了绝大多数情况。
RAID6:最少四块盘,双份分布式校验,可用容量是盘数减二。比如六块 4TB 盘组 RAID6,可用容量 16TB,允许同时坏两块盘。写入性能比 RAID5 更低,但面对大容量机械盘动辄几十小时的重建周期,RAID5 在重建期间碰上第二块盘故障的概率并不低,RAID6 多一道保险。如果阵列总容量超过 8TB、数据是重要业务数据,我强烈建议优先考虑 RAID6,多牺牲一块盘容量换来的安心感绝对值回票价。
RAID10:最少四块盘,是 RAID1+RAID0 的嵌套:先两两做镜像(RAID1),再把多组镜像做条带(RAID0)。它兼具可靠性与写性能,容量利用率 50%。数据库场景如果预算够,RAID10 往往是比 RAID5 更稳的选择,因为写性能和故障恢复速度都更友好。缺点是磁盘成本高。
我做选型时有一个粗线条口诀:系统盘选 RAID1,容量和容错折中选 RAID5,数据很重要且阵列盘数多选 RAID6,追求性能又不差钱选 RAID10,纯缓存临时数据才选 RAID0。这个口诀帮我应付了绝大多数项目,也希望能帮你理清思路。
2.2 mdadm 的架构:md 设备、成员盘与 UUID 的身份识别机制
理解 mdadm 的架构,得先搞清楚三个核心概念:md 设备、成员盘、UUID。md 设备就是 /dev/md0、/dev/md127 这类逻辑设备节点,你格式化和挂载文件系统的对象是它;成员盘是实际参与阵列的物理磁盘,比如 /dev/sdb、/dev/sdc;而 UUID 是阵列身份的“防伪标识”。
创建阵列时,mdadm 会在每块成员盘的头部(通常是分区后偏移量处)写入一份超级块(superblock),超级块里保存了阵列的 UUID、层级、成员状态、事件计数等元数据。这个机制很关键:系统重启后,内核的 md 模块扫描磁盘时,就是靠这些超级块来识别“哦这几块盘本来就是一个阵列”,进而触发自动组装。所以强烈建议你不要手动在阵列成员盘上再建分区并挂载文件系统,否则容易干扰超级块识别。
成员盘的识别不光靠设备名。/dev/sdb 这个名字在系统重启后完全可能变成 /dev/sdc,因为内核枚举设备顺序受总线扫描顺序影响。mdadm 会通过 UUID 和超级块里的成员位置来实现确定性识别,这就是为什么 /etc/mdadm.conf 里你会看到 ARRAY /dev/md0 UUID=... 这么一行配置。在数据中心的机器上,如果哪一天重启后阵列没自动挂载,第一反应别急着重建阵列,先执行 mdadm --assemble --scan,大概率是 UUID 识别没触发,手动组装一下就能救回来。
2.3 关键参数概念:chunk size 和 metadata 版本有多重要
chunk size(条带大小)是 RAID 层面一个特别重要却容易被忽视的参数。简单理解,它在 RAID0/5/6 里决定了分条写入时每条数据切多大一块。chunk 设小(比如 64K),阵列更像“细粒度交织”,适合随机小 IO 和并发访问;chunk 设大(比如 512K 或 1M),顺序大文件的读写吞吐会更高,但单个小 IO 会造成整条 RAID 条带上的所有盘都被动参与,反而拖慢速度。数据库随机读写我会选 64K 或 128K,视频存储、备份仓库这种大文件流我会选 512K。
metadata(元数据)版本则决定了超级块写入磁盘的位置和格式。mdadm 默认在 1.2 版本之前还用过 0.90 和 1.0,0.90 版超级块写在各盘末尾(考虑兼容老引导程序),1.0 也写末尾,1.1 和 1.2 写盘头,其中 1.2 是当前主流默认。之所以强调这个,是因为如果你做根分区(/boot 或 /)所在的阵列,建议用 0.90 或 1.0,超级块在盘尾对引导程序更友好:有些老版本 GRUB 和主板 BIOS 不认盘头超级块,启动阶段阵列识别不了,系统就起不来。数据盘阵列直接用默认 1.2 没问题,Ubuntu/CentOS 的 mdadm 默认都写 1.2。简单记:系统盘阵列 metadata 选 0.90,纯数据盘阵列选 1.2,这个经验在多个发行版上验证过都稳。
3. 实操过程与核心环节实现:从磁盘准备到阵列创建的完整流程
3.1 实操前的磁盘规划与条件检查
开始动手之前,先把准备工作做扎实。无论你是虚拟机环境还是物理机,都要确保参与阵列的磁盘是“空盘级别”的,也就是说这些盘上没有你还要的数据。这一步很多人吃过亏:建阵列时 new 操作会覆盖盘头超级块区域,虽然不会立刻擦掉全盘数据,但阵列创建后原分区表可能直接失效,而且后续写入会逐步覆盖原有文件系统区域,造成数据不可逆丢失。所以,如果盘上还有需要的东西,赶紧备份,别拿生产数据来试错。
然后要确认三件事。第一,系统是否装好了 mdadm 工具。Ubuntu/Debian 系执行 sudo apt install mdadm,CentOS/RHEL 系执行 sudo yum install mdadm,安装过程会自动启用内核 md 模块。第二,确认参与阵列的磁盘设备名。强烈不建议凭记忆去猜设备名,而是用 lsblk 或 fdisk -l 查看一次,确认盘符、容量、型号。第三,确认这些盘没有被系统挂载、没有残余 RAID 元数据。如果是从别处拆来的盘,可以用 mdadm --examine /dev/sdX 检查是否已有阵列信息,有的话需要清理。
我常用的一条清理命令是 sudo mdadm --zero-superblock /dev/sdX,这个操作会把盘上已有的 md 超级块清零,让这块盘回到“干净”状态。注意如果该盘正在一个运转的阵列里,先要把阵列停掉,不然内核会因为元数据消失而出现不可预期行为。
3.2 使用 mdadm 创建 RAID5 的完整命令与每一步的含义
下面我用一个六块盘(/dev/sdb 到 /dev/sdg)组 RAID5 的案例来走一遍完整流程,实际生产中以你的设备名为准。先创建分区。虽然 mdadm 可以直接拿整块盘做阵列成员,但强烈建议先分一个分区出来,比如 /dev/sdb1,而不是直接用 /dev/sdb。原因有二:一是系统盘引导和某些工具对整块盘做 md 成员支持不够好,分区的灵活性更高;二是以后如果想调整阵列布局或者排查磁盘问题,分区级设备能避免很多误会。分区就用 fdisk 或 parted 创建,比如 sudo fdisk /dev/sdb,然后 n——p——w 一气呵成,六块盘各建一个同等大小的分区。
创建分区后,执行创建命令:
sudo mdadm --create /dev/md0 --level=5 --raid-devices=6 --chunk=128 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1 /dev/sdf1 /dev/sdg1这段命令的意思要从左往右看:--create 是创建动作;/dev/md0 是给新阵列命名为 md0;--level=5 指定 RAID5;--raid-devices=6 说明这个大阵列由六块盘组成,它跟后面跟着的设备列表数量一致,计数就是从零开始的 1~6 个参数。最后 --chunk=128 把 chunk size 设为 128KB,适合通用场景。如果盘符顺序不想写死,也可以写成简短的复数形式,mdadm 会帮你展开。
创建完成后,通过 /proc/mdstat 查看阵列状态:
cat /proc/mdstat这个文件是内核 md 模块的实时状态窗口,会显示阵列名称、状态、每个成员盘的工作情况以及重建进度。新建的 RAID5 阵列通常会先做一次初始化同步(initial resync),把校验数据填满全盘,期间我感觉速度不算太快,慢的时候可能要走几十个小时。这个过程建议不要中断,因为内核在同步期间已经在正常处理新写入的数据,此时重启阵列不会丢数据,但重建进度会从头再来,白白浪费时间。
3.3 创建文件系统、挂载以及持久化配置 /etc/mdadm.conf
阵列创建同步完成后,接下来就是文件系统格式化。这一步很多人纠结要不要在 RAID5 上再用 LVM,我的建议是:看具体场景,直接用文件系统也可以,但加一层 LVM 会方便后期扩容和做快照。如果只用 mkfs,直接对 /dev/md0 创建即可:
sudo mkfs.ext4 /dev/md0但如果在 RAID5 阵列盘数不足时格式化了,后续一旦换盘扩容,文件系统层面对跨盘不够透明,还得用 resize2fs 之类的工具去扩展,灵活性差。所以我个人习惯是“mdadm 上叠 LVM”,先 pvcreate /dev/md0,再 vgcreate vg_data /dev/md0,然后 lvcreate -L 800G -n lv_01 vg_data,最后对逻辑卷做 mkfs。扩展卷容量时,因为 VG 层把 md 设备的容量管理做了封装,直接 lvextend 和 resize2fs 就好,不用纠结 mdadm 层面的 chunk 平衡问题。生产环境里这种“RAID 管冗余、LVM 管容量”的经典组合,我用着非常顺手。
最后,把阵列信息写入配置文件,确保重启后能自动组装:
sudo mdadm --detail --scan | sudo tee -a /etc/mdadm.conf--detail --scan 的输出行格式类似 ARRAY /dev/md0 metadata=1.2 name=myhost:0 UUID=xxxx:xxxx:xxxx:xxxx,把它追加进配置文件后,系统 initramfs 阶段就会读到这块配置,自动把 md0 拉起来。注意这一步非常关键,漏了它,下次开机你会发现 /dev/md0 压根不存在,需要手动 assemble,如果没经验很容易误以为阵列数据丢了,白惊吓一场。
挂载层面,在 /etc/fstab 里写好挂载项,建议用 UUID 而不是设备名。执行 blkid /dev/md0 拿到文件系统 UUID,写进 fstab 的四个字段里,mount -a 验证一遍。挂载后顺手查看 /proc/mdstat,如果显示 [UUUUUU] 这种全是 U 的状态,说明所有盘都在线,阵列健康。
3.4 实战演示:用热备盘与磁盘扩容习惯提升容错水平
这里说一个我特别推荐的高级用法:热备盘(spare disk)。简单理解,阵列正常工作时有额外盘处于待命状态不参与读写,一旦有盘故障,内核会自动把故障盘剔除,把热备盘顶上进阵列,然后自动开始后台重建。热备盘的好处是你不需要等监控报警后半夜爬起来手动替换,故障转移是内核自动处理的,能大幅缩短数据处于无冗余状态的时间窗口。
创建阵列时预留热备盘,命令加一个参数:
sudo mdadm --create /dev/md0 --level=5 --raid-devices=5 --spare-devices=1 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1 /dev/sdf1 /dev/sdg1这里第五位参数 --spare-devices=1 声明了六块盘中前五块是阵列成员,最后一块是热备盘。当然也可以阵列创建完成后再加:sudo mdadm --add /dev/md0 /dev/sdg1。热备盘的大小最好和成员盘一致或者不小于成员盘,因为重建时系统默认按成员盘的最小容量来扩展备用盘,如果热备盘比成员盘小,会直接导致重建失败。这个坑我踩过一次:四块 1TB 盘一块 600G 做热备,结果阵列降级重建时约等于报废,最后只能用大容量盘重新初始化。
光有热备盘还不能高枕无忧,日常监控同样重要。建议写一个 cron 脚本定期抓取 /proc/mdstat 状态,状态中如果出现类似 [U_UUUU]、[UU_U] 之类的“_”标记,就说明有盘离线了,立即发邮件或者对接告警系统通知值班人。我从踩坑中总结的窍门是:能提前十分钟知道坏了一块盘,和等用户反馈“这盘怎么不能写了”才去找原因,处理成本和业务影响完全不是一回事。
4. 常见问题与排查技巧实录:阵列降级、坏盘替换与元数据救援
4.1 当阵列出现降级(degraded)状态:第一步不是换盘而是确认状态
很多人第一次接触阵列故障,一看到 mdstat 里出现 degraded 就慌了,急着拔盘换盘。但谨慎的做法是先确认故障盘到底损坏到了什么程度,因为有些所谓“故障盘”只是偶发 IO 超时被内核踢出了阵列,实际上盘的硬件可能没坏。碰到“降级”先执行:
sudo mdadm --detail /dev/md0这条会输出阵列角色的详细清单,包括每个成员盘的状态、事件计数、更新时间和是否有 spare。同时跑一遍 sudo dmesg | tail -50,看看有没有 IO error、hard reset、timeout 之类的记录,这些是判断故障原因的关键线索。如果盘只是被误踢(比如卡住的 SATA 数据线松动导致几秒没响应),直接 sudo mdadm --re-add /dev/md0 /dev/sdX 大概率能把它加回来,阵列会自动继续同步校验数据,不需要换盘。
如果确认盘确实故障——比如 SMART 信息里大量 pending sectors、dmesg 打印满屏 IO error——那就进入坏盘替换流程。以 RAID5 六盘为例,坏盘是 /dev/sdd,替换流程是:
sudo mdadm --manage /dev/md0 --fail /dev/sdd1这一步把坏盘标记为 failed,内核会把该盘从阵列逻辑中移除,并立刻开始把你预留的热备盘顶上做重建。接着从物理层面把盘拔掉,新盘装上,分区后执行:
sudo mdadm --manage /dev/md0 --add /dev/sdd1如果没预设热备盘,前面两步做完之后阵列会处于降级状态,这时候一切读写都还在正常进行,但已经没有冗余,再坏一块就全灭。务必尽快替换并加回新盘让阵列开始重建。重建期间负载会明显升高,因为 RAID5 要读所有剩余成员盘的数据来重算坏盘的校验内容,这时候业务流量如果是高峰期,你会发现磁盘 IO 延迟有所上升,这是正常的,只要阵列状态是 syncing + resync 且进度在前进,就不用太焦虑。
4.2 阵列不识别,UUID 未自动组装的经典救援过程
再讲一个高频故障:系统重启后 /dev/md0 不见了。多数情况下不是阵列坏了,而是系统没能自动组装。检查顺序要清晰:
先看 sudo mdadm --examine /dev/sdX1 的输出,它会打印盘上的超级块信息,包括阵列 UUID、状态、角色。如果显示 states clean or active,说明阵列超级块没问题,只是系统没有配置文件或 initramfs 没触发自动组装。执行 sudo mdadm --assemble --scan,它会扫描所有未使用磁盘上的超级块,根据 UUID 一致性自动把属于同一阵列的成员组合成 md 设备。
如果自动扫描没成功,再显式指定成员盘组装:
sudo mdadm --assemble /dev/md0 /dev/sdb1 /dev/sdc1 /dev/sde1 /dev/sdf1 /dev/sdg1注意这里故意省略了故障盘 sdd1,缺了它没关系,阵列能组起来,状态是 degraded,数据正常可见,之后再按坏盘替换流程处理即可。还有一种情况是盘比较多、UUID 冲突(比如以前堆叠的旧阵列残留),那就得靠 --update=homehost 或者 --force 之类参数小心处理,在没有完全理解含义前不建议乱用,可能会改变超级块内容。
有一种更隐蔽的情况:盘还在,但超级块被误清了。如果执行 mdadm --examine 提示 No superblock found,而你知道这块盘之前确实是阵列成员,那就要冷静想想是不是有人执行过 --zero-superblock 或者误格式化了。这种场景下还有个冷门但有用的恢复手段:查 /etc/mdadm.conf 里记录的历史 UUID,再用 grep 去全盘找还有没有别的盘的超级块是匹配这个 UUID 的,如果碰巧还能凑出符合 RAID 级别的最低盘数,用 --assemble --force 还可以尝试把阵列拉起来。虽然不一定每次都成功,但不能连试都不试就直接宣告阵列报废。
4.3 重建慢、性能差的瓶颈分析与解决策略
RAID5/RAID6 阵列重建速度慢是很多运维的痛点,尤其是大容量机械盘时代,重建时间动不动以天计。这个问题的根源在 RAID5 重建时要读所有剩余盘的全部数据来擦算丢失盘的校验值,再加上同一时间段阵列还在正常服务业务读写,IO 竞争非常激烈。解决思路大概有这几个方向。
一是调节重建速度参数。md 层提供了两个核心参数:/proc/sys/dev/raid/speed_limit_min 和 speed_limit_max,分别代表重建速度的上下限(单位 KB/s)。默认值可能比较保守,如果服务器在非业务高峰时段重建,可以临时上调:
echo 200000 > /proc/sys/dev/raid/speed_limit_min echo 400000 > /proc/sys/dev/raid/speed_limit_max调到 200~400MB/s 能在盘性能允许时明显加速重建。但别高兴太早,盲目拉满上线也可能导致正常业务 IO 饿死,因为重建进程和业务 IO 是共享同一组盘的内核队列的。我的习惯是白天用保守值(比如 min 50000 / max 200000),凌晨业务低峰再调高,配合 cron 自动切换。
二是检查是否磁盘本身处于传输瓶颈。比如某些 USB 外接盘或老式 SATA 2 接口,跑不满 speed_limit 上限,这时候调参没有意义。物理盘正常做法是用 smartctl 测一下传输速度,或者 dd 读盘测速,确保瓶颈不在链路。还有就是临时停掉业务对阵列的访问,让重建独占 IO,速度会显著提升。有一次我在深夜把数据库实例临时停掉,RAID5 重建从预计 40 小时缩短到 9 小时,这对紧急恢复业务尤为重要。
最后一条老生常谈但值得重申:重建期间千万不要掉电,最好接上 UPS。大阵列重建中途断电,轻则进度中断,重则在重建逻辑里留下不一致状态,可能因为一块盘的校验数据不完整导致整阵列无法干净启动。我办公区域就配了一台在线式 UPS,旁路切换 UPS 给磁盘阵列单独供电,这事花小钱省大心。
4.4 坏盘更换后的数据一致性检查清单
换完盘、重建完成后别急着庆祝,至少还要做一轮一致性检查。首要是看 /proc/mdstat,正常状态应该完全变成 [UUUUUU] 或对应的满 U 标记,没有 syncing 或 resync 字样。接着执行 fsck 或者用 xfs_repair -n 之类做只读文件系统检查,确保文件系统层面没有因为重建产生逻辑错误。然后跑一遍 mdadm --detail /dev/md0,确认事件计数一致,没有任何盘处于 failed 或 spare 状态。
生产环境的经验告诉我,最稳的做法是重建完成后手动触发一次全阵列一致性校验:
echo check > /sys/block/md0/md/sync_action这会驱动 md 模块把所有成员盘的数据和校验信息完整比较一遍,发现问题会在内核日志里打 mismatch 警告。这个过程很耗时,但值得做,特别是阵列承受过一次降级重建之后,它能兜底发现那些表面“重建完成”但内部校验不一致的隐藏问题。忘了这一步,过几个月因为某些特定扇区访问时报 IO error,那时候排查的难度会高好几个级别,搞不好就丢数据。
5. 总结与经验沉淀:千言万语汇成几条硬道理
软件 RAID(mdadm)这套方案,我用下来的核心体会是:它足够可靠、足够透明、足够便宜,但它不是一个可以“创建完就遗忘”的黑盒。你越了解它的工作机制——超级块、UUID、事件计数、重建队列——就越能在故障来临时从容应对。反之,只会在 Google 上搜命令来执行而不理解内部逻辑的人,遇到阵列故障时会非常被动,因为在超时重试之间很可能做出一连串让情况更糟的操作。
具体到项目落地,我个人的经验清单大概有这么几条,每次给客户或团队做培训时我都会反复强调:
- 阵列的选择从来不是参数表上的最优,而是你业务对“可靠性、容量、性能、成本”四个维度的权衡结果,先算清楚账再动手。
- 永远不要把整个系统的可靠性押在单一副本上。即使做了 RAID6 双容错,核心业务数据最好还有异地备份,RAID 解决的是硬件故障,备份解决的是逻辑错误、误删除和勒索病毒。
- 任何生产级改动(创建、换盘、扩容、重启)越详细的记录越好,至少把 mdadm --detail 的输出留一份在文档里,出事时你会无比感谢当初的自己。
- 监控和告警不能省。一块盘从 smart 报错到真正离线可能只有几小时,及时介入跟事后抢救的代价天差地别。
最后再分享一个每次换盘我都用的“笨办法”:新盘上机前,先在别处用 dd 或者 badblocks 做一次全盘写读测试,确认没有坏道再放进阵列。这一道工序虽然花点时间,但能让你区别“阵列重建失败”和“新盘自己就是坏的”这两个完全不同的问题。那次我图省事没测,直接换上去就做重建,重建到 30% 时盘卡死,结果阵列直接进入双故障降级,险象环生。从那以后,这个笨办法就成了我工作的铁律。希望这篇文章能把你要踩的坑先帮你都踩一遍,少走点弯路。
延伸思考:后续还能怎么玩?如果你已经熟练掌握了基础阵列的创建和恢复,下一步可以研究这几个方向:用 mdadm 配合 LVM 的 thin provisioning 做虚拟化存储池;用 mdadm 的 --bitmap 参数给阵列启用写时位图,减少异常断电后的全盘同步时间;以及用 mdadm 的 reshape 功能在线把 RAID5 扩成 RAID6,或者在线加盘扩容,这是很多人在 RAID 扩容需求面前不知道的一个隐藏大招。搞透了这些,软件 RAID 的灵活程度真的能刷新你的认知。