
1. 为什么我劝你先在虚拟机里把 RAID 和 LVM 跑一遍磁盘阵列RAID和 LVM 这两套东西属于那种看文档十分钟就懂、上手五分钟就废的典型。我在机房里见过太多类似的场面一台刚上架的业务服务器因为一条mdadm --create写错了设备名把已经跑着系统的那块盘卷进了阵列元数据一写机器再也没起来。事后复盘操作的人不是不懂命令他只是从来没在允许出错的地方完整地走过一遍流程。虚拟机在这个场景里的价值就是把允许出错这件事变成现实。你在 VMware 或者别的虚拟化平台里挂上四五块虚拟硬盘建 RAID0、RAID1、RAID5、RAID10把它们拆了再建、建了再拆最坏的结果不过是删掉一个目录重新来。这个过程能帮你建立起对设备命名、阵列状态、元数据位置这些抽象概念的肌肉记忆而这恰恰是纸质资料给不了的东西。这篇文章我打算按一条完整的实践线来写先用虚拟机准备好环境把四种常见的磁盘阵列逐个搭起来观察它们在真实运行时的状态变化然后在阵列之上叠一层 LVM把 PV、VG、LV 的逻辑理清楚最后集中处理那些容易让人卡住的坑。文章面向的读者是已经能装 Linux、会敲基本命令但对存储分层还停留在照着教程抄阶段的朋友如果你已经能独立做在线扩容和降级恢复那这篇可以当作一份排查手册来翻。需要提前说清楚的是虚拟机里的硬盘本质上是宿主机上的几个文件它验证的是流程、命令和逻辑不是真实的 IOPS 和吞吐数字。任何在虚拟机里跑出来的性能结论都别直接往生产环境套这个边界后面我还会再展开。2. RAID 0/1/5/10 的原理账本与选型逻辑2.1 从一块盘坏掉这件事倒推冗余的本质选 RAID 级别本质上不是在选哪个快而是在回答一个问题我允许丢多少数据以及我愿意为此付出多少硬盘成本。RAID0 是把数据切成块分散写到多块盘上任何一块盘坏了整个阵列的数据就全废了它的价值只体现在读写速度上。RAID1 是镜像两块盘存一模一样的内容坏一块无所谓容量利用率只有 50%。RAID5 用分布式校验的方式在容量和安全性之间取了个中间值允许坏一块盘。RAID10 是先镜像再条带兼顾性能和可靠性代价是容量利用率同样只有一半。理解 RAID5 的关键在于校验块的位置。它不像很多人以为的那样有一块盘专门存校验而是把校验信息轮流分布在每一块盘上。三块盘做 RAID5写入时每一条带里都有一块校验、两块数据校验块由其余数据块异或运算得出。某一块盘坏了剩下的盘可以通过异或反推出丢失的数据——这就是重建的数学基础也是它为什么最少需要三块盘的原因。2.2 容量、性能与重建风险的量化对比容量计算这件事我建议直接背公式比临时推算靠谱得多。假设有 n 块容量为 C 的盘级别最小盘数可用容量容错能力典型场景RAID02n × C无坏一块全丢临时缓存、可重建的计算中间数据RAID12C坏一块两盘时仅一块系统盘、小容量高可靠分区RAID53(n-1) × C坏一块读多写少的文件存储RAID104偶数n/2 × C每镜像对坏一块数据库、虚拟化底层存储RAID5 有个容易被忽略的问题叫写洞掉电瞬间如果校验块和数据块没写完重建时可能出现校验不一致。软件 RAID 里可以通过一致性策略来缓解这个后面实操时会具体讲。另一个风险是重建窗口——四块 4TB 盘组 RAID5单盘故障后重建可能要跑十几个小时这段时间里如果再坏一块就彻底没救。这也是这几年大容量盘越来越多用 RAID10 或 RAID6 的原因。2.3 选型决策表与三个高频误区误区一RAID5 又省盘又安全肯定最优。省盘是真的安全是有条件的。盘越多、单盘越大重建失败概率越高。误区二RAID 能当备份用。RAID 解决的是硬件故障导致的可用性问题不解决误删除、误格式化、逻辑损坏。你rm -rf一个目录RAID1 会忠实地把两块盘都删干净。误区三硬盘数量越多越好。盘多了故障率也上去了。八块盘的 RAID5 和四块盘的 RAID10前者年故障概率明显更高。我的经验是系统盘和日志盘用 RAID1数据量大且读多写少用 RAID5 或者 RAID6数据库和虚拟化底层直接上 RAID10别在这上面抠硬盘成本。3. 虚拟机环境准备与多磁盘添加实操3.1 虚拟机软件与系统版本怎么挑用什么平台其实不重要VMware Workstation、VMware Player或者其他主流虚拟化工具都行只要支持给一台虚拟机挂多块虚拟硬盘就够了。我这次用的是较新的 Workstation 版本客户机装 CentOS 7.9原因是它对 mdadm 和 LVM 的工具链支持非常成熟资料多、坑少适合用来理清概念。如果你想跟着练Ubuntu 22.04 或 24.04 也完全可以命令几乎一致只是包管理换成 apt。系统安装时有个细节值得注意不要用默认的自动分区。选择手动分区根分区给个 20G 到 30G 就够剩下空间先留着不分配。这样后面添加的新硬盘是干净的不会和系统盘混在一起。安装类型选最小化安装加开发工具就够没必要装图形界面纯命令行反而看得更清楚。3.2 添加虚拟磁盘控制器类型和磁盘模式的关键选择虚拟机关机状态下进设置界面添加硬盘。这里有几个选项会实际影响后面的实验硬盘类型选 SCSI 而不是 IDE因为 SCSI 在 Linux 下的设备命名更规范而且虚拟化平台对它的队列深度支持更好。控制器类型一般默认 LSI Logic SAS 就行如果你追求性能可以选半虚拟化Paravirtual控制器内核自带驱动装完系统后能识别。磁盘模式是个容易点错的地方。默认是持久意思是所有写入立即反映到磁盘文件。另外两个选项是非持久和独立-非持久——它们的用途是做还原型实验关机后写入全部丢弃。做 RAID 实验时一定选持久模式否则你重建阵列的过程数据一关机器就没了根本观察不到结果。每块虚拟磁盘的容量建议 5G 到 10G做容量计算和重建演示足够了。虚拟磁盘太大创建和复制都会拖慢节奏。如果你要模拟 RAID5 的重建过程给五块盘比较合适三块组成阵列一块做热备一块留着做对照。热词里提到的存储为单个文件和拆分成多个文件这两个选项实验环境选单个文件IO 性能稍好如果你要在不同机器之间拷贝虚拟机目录拆分成 2G 一个会方便些。这是个纯工程取舍没有标准答案。3.3 开机后确认磁盘识别与设备命名开机后第一件事是确认系统看到了几块盘。lsblk是我的首选它以树状结构显示块设备和挂载点一眼就能看出哪些盘是裸的。如果嫌信息不够用fdisk -l或者parted -l看容量和分区表类型。Linux 对 SCSI 磁盘的命名是按识别顺序来的先识别到的叫/dev/sda然后是/dev/sdb以此类推。这里有个坑——设备名不是稳定的。你加了一块新盘、换了控制器插槽顺序sdb和sdc可能就对调了。做实验时影响不大但在生产环境里往/etc/fstab或者脚本里写/dev/sdb是极其危险的操作这方面后面的排查章节会专门讲。顺便确认一下系统有没有装 mdadmrpm -q mdadm或者mdadm --version。CentOS 7.9 的最小化安装不预装用yum install -y mdadm装一下。Ubuntu 上是apt install -y mdadm。4. 用 mdadm 把四种阵列全部搭一遍4.1 准备工作分区标记与元数据版本的选择关于要不要先分区社区里一直有两派做法。一派直接拿整块裸盘喂给 mdadm一派先把每块盘分一个区、类型标成fdLinux raid autodetect。我的做法是实验环境用整盘生产环境用分区。理由是这样整盘创建阵列操作最少适合理解流程生产环境用分区一方面是留出将来在盘头放引导或者元数据的余地另一方面分区表本身是一个明确的标记别人登录上来一看就知道这块盘被阵列占用了不容易误操作。元数据版本这个参数值得单独说。mdadm 默认用1.2把超级块放在设备偏移 4K 的位置。老版本0.90把超级块放在设备末尾有些老引导程序依赖它现在基本不用了。这三代元数据1.0、1.1、1.2的区别只在于超级块位置1.2 是当前默认直接用默认值就行不用额外加参数。创建前建议先清一遍磁盘签名尤其是反复做实验的盘mdadm --zero-superblock /dev/sdb。如果盘上残留旧的阵列信息--create有时会报设备忙或者组装出意外的结果。4.2 RAID0 与 RAID1 的创建与实时状态观察先建一个 RAID0三块盘mdadm --create /dev/md0 --level0 --raid-devices3 /dev/sdb /dev/sdc /dev/sdd。命令敲完会问你是否继续输入 y。建好之后立刻cat /proc/mdstat你会看到阵列已经 active因为 RAID0 没有初始化过程不需要同步数据。mdadm --detail /dev/md0能看到更完整的信息阵列级别、块大小chunk size、每块盘的状态、UUID、活跃设备数。chunk size 默认 512K这个值决定了数据在盘之间的切分粒度。大文件顺序读写的场景调大一些比如 1M能减少寻道小文件随机读写多的场景调小更合适。虚拟机里体验不出差异但这个参数以后调优时会用上。RAID1 的创建是mdadm --create /dev/md1 --level1 --raid-devices2 /dev/sde /dev/sdf。这次你会看到明显的区别——/proc/mdstat里会出现resync进度条。镜像需要把一块盘的数据完整复制到另一块这个过程叫初始化同步。几 G 的虚拟盘几秒钟就完事真实环境里的 TB 级盘可能要跑几个小时。提示初始化同步期间阵列是可以挂载使用的只是性能会受影响。生产环境里如果急着上线可以用--assume-clean跳过初始同步但要清楚这意味着如果你的盘本来就有坏块问题会潜伏到后面才暴露。4.3 RAID5 的创建、写洞机制与重建演示三块盘建 RAID5mdadm --create /dev/md5 --level5 --raid-devices3 /dev/sdb /dev/sdc /dev/sdd。同样会触发初始化进度条能在/proc/mdstat里看到。注意观察[UU_]这种状态表示——U 是 up下划线是缺失三块盘完全正常时显示[UUU]。RAID5 的写洞问题在软件 RAID 里可以用一致性策略缓解。创建时加--consistency-policypplmdadm 会在每条带里额外写一份部分校验日志掉电后能通过日志判断哪些条带是干净的。代价是额外写入开销性能大概降几个百分点。这个参数在老版本内核上不支持创建前用mdadm --create --help确认一下你的版本能力。重建演示是这部分最有看头的地方。先用dd往阵列里写点数据然后模拟一块盘损坏mdadm /dev/md5 --fail /dev/sdc --remove /dev/sdc。这时候--detail里那块盘的状态会变成 removed阵列降级为[UU_]。接着把盘加回去mdadm /dev/md5 --add /dev/sdc重建立刻开始/proc/mdstat会显示 recovery 的百分比和速度。重建速度可以通过sysctl dev.raid.speed_limit_max查看默认每秒 200000KB。虚拟机上这个数字没什么意义但在真实服务器上如果重建影响业务 IO把它调小比如 50000能减轻对线上服务的冲击。这是一个非常实用的技巧代价是重建时间拉长需要你在业务窗口和风险敞口之间做权衡。4.4 RAID10 的嵌套布局与参数细节RAID10 的本质是 RAID1 套 RAID0或者反过来。mdadm 里的--level10默认采用近布局near意思是同一份数据的两个副本存在物理位置相邻的盘上。--layout参数可以选 n2、n3、o2、f2 等n2 是最常见的配置四块盘两两配对每对互为镜像数据条带分布在这两个镜像组之间。四块盘mdadm --create /dev/md10 --level10 --raid-devices4 --layoutn2 /dev/sdb /dev/sdc /dev/sdd /dev/sde。建好后用--detail看你会发现设备列表里每块盘都有一个配对关系这就是镜像组的体现。RAID10 的容错逻辑需要说清楚它允许坏盘但不是任意坏两块都安全。四块盘分成两组镜像每组里各坏一块阵列还能扛住如果同一组里坏了两块整个阵列就崩了。所以它的实际风险曲线比允许坏两块盘这个说法要复杂这也是为什么在大规模部署里要严格做盘位管理和监控告警。4.5 阵列的停止、重新组装与持久化配置实验做完了要清理顺序很关键。先umount挂载点再mdadm --stop /dev/md5然后对每块盘mdadm --zero-superblock。如果不清超级块就重新建阵列mdadm 可能识别出旧的阵列签名导致新阵列信息混乱。持久化配置是新手最容易翻车的地方。开机时系统怎么知道要把哪几块盘组装成哪个阵列靠/etc/mdadm.conf。生成方式是mdadm --detail --scan --verbose /etc/mdadm.conf它会把当前所有阵列的 UUID 和成员盘写进去。开机时内核的自动组装机制会读这个文件用 UUID 而不是设备名去匹配——这就是为什么前面强调设备名不稳定。如果只想临时组装用mdadm --assemble --scan它扫一遍所有磁盘寻找阵列签名。想指定组装某一块盘上的阵列用mdadm --assemble /dev/md0 /dev/sdb /dev/sdc。这些命令在数据恢复场景里非常有用比如你从一台坏掉的服务器上拆下几块盘插到新机器上靠的就是 assemble。5. RAID 之上叠 LVM分层设计才是正解5.1 为什么要把 RAID 和 LVM 拆成职责分明的两层很多人会问阵列已经做完了直接mkfs格式化不就行了为什么还要套一层 LVM答案在于扩展性。假设你的 RAID5 有 5T 空间业务跑了一年某个分区不够用了。没有 LVM你只能先备份数据、删分区、重建更大的分区、恢复数据——这个窗口期可能是几个小时。有了 LVMlvextend加resize2fs两条命令在线完成业务无感知。更深一层的原因是RAID 和 LVM 解决的是完全不同的问题。RAID 管的是物理层面的冗余和性能它关心的是盘坏了数据还在不在。LVM 管的是逻辑层面的空间分配它关心的是这块空间怎么划、划多大、以后怎么改。把两者混在一起等于让一个工具干两件事最后两件事都干不好。5.2 PV、VG、LV 三层抽象与 PE 大小的取舍LVM 的三层结构我用一个类比来解释PV 是砖头VG 是砖头堆成的池子LV 是从池子里舀出来的一勺水。你可以随时往池子里加砖头vgextend也可以随时把水舀多舀少lvextend、lvreduce只要池子还有余量。创建流程是这样的pvcreate /dev/md0 vgcreate vg_data /dev/md0 lvcreate -L 20G -n lv_home vg_data mkfs.ext4 /dev/vg_data/lv_homepvcreate会在设备头部写一个标签标记这是 LVM 物理卷。vgcreate把 PV 纳入一个卷组默认 PE物理扩展块大小是 4M。PE 是 LVM 分配空间的最小单位一个 LV 的大小必须是 PE 的整数倍。PE 大小的选择有个权衡PE 越小空间分配的粒度越细浪费越少但元数据量越大PE 越大元数据开销越小但一个 32M 的 PE 意味着你最小也只能分配 32M。做实验时默认 4M 完全够用如果你管理的是几十 TB 的卷组用vgcreate -s 32M指定更大的 PE 会更合适。查看状态的命令要记牢pvs、vgs、lvs是三个简写输出紧凑适合快速扫一眼pvdisplay、vgdisplay、lvdisplay输出详细信息排查问题时用。我平时基本只用pvs和lvs需要看 PE 分布的时候才上pvdisplay -m。5.3 在线扩容从往池子里加盘到 home 分区变大扩容分两种情况。第一种是卷组还有剩余空间直接扩 LV 就行lvextend -L 10G /dev/vg_data/lv_home resize2fs /dev/vg_data/lv_home注意顺序先扩逻辑卷再扩文件系统。反了会报错。文件系统是 ext4 用resize2fsxfs 用xfs_growfs后者接受的参数是挂载点而不是设备路径这一点经常有人搞混。第二种情况是卷组空间用完了需要往池子里加盘。假设你已经用四块新盘建好了/dev/md1流程是pvcreate /dev/md1 vgextend vg_data /dev/md1 lvextend -L 50G /dev/vg_data/lv_home resize2fs /dev/vg_data/lv_home这几步全部可以在线执行不需要卸载文件系统。这就是 LVM 最大的价值所在。热词里提到的lvm 扩容 home指的大概就是这种场景装系统时/home分小了后来发现不够用想在不重装的前提下扩容。做法和上面完全一样只要你的卷组里还有空闲 PE 就行。装系统时如果不确定各分区该给多大我的建议是/给 50G/home给剩余的全部把灵活性留给以后。真的分错了LVM 还能救你用传统分区的就只能重装。5.4 快照、迁移与缩容的边界LVM 快照的原理是写时复制创建快照的瞬间不复制数据只有原卷发生写入时才把被覆盖的旧数据块挪到快照空间里。所以快照空间要预留足够否则写满之后快照会失效。lvcreate -L 10G -s -n lv_home_snap /dev/vg_data/lv_home快照最实用的场景是备份和测试。做一次重要变更前打个快照出问题直接lvconvert --merge回滚比任何备份都来得快。但要注意快照不是备份——它和原卷在同一组物理盘上盘坏了两个一起没。缩容是个危险操作我的建议是能不缩就不缩。ext4 支持缩容但必须先卸载文件系统、跑一遍e2fsck -f检查、再用resize2fs缩到比目标略大的值、最后lvreduce缩逻辑卷。任何一步顺序错了都可能丢数据。xfs 更干脆直接不支持缩容要缩就得备份出来重建。6. 踩坑实录与故障排查速查6.1 阵列降级、磁盘掉线与重建阵列降级最典型的信号是/proc/mdstat里出现[U_U]这种缺位标记或者--detail里某块盘状态变成 faulty。这时候先别急着操作第一件事是搞清楚是盘真坏了还是只是接触问题或者一次 IO 超时。排查顺序我是这样走的先看dmesg | tail -50内核会把 IO 错误、设备重置、超时这些信息全打在环形缓冲区里再smartctl -a /dev/sdX看盘的 SMART 数据如果出现重新分配扇区数激增、待处理扇区非零基本可以判定盘该换了。如果只是暂时性故障可以mdadm /dev/md0 --remove /dev/sdb再--re-add /dev/sdbmdadm 会尝试用位图快速同步比完整重建快得多。前提是创建阵列时加了--bitmapinternal参数这个参数我强烈建议在创建时就加上代价是轻微的性能损失收益是重建时间从几小时缩短到几分钟。现象可能原因排查动作阵列显示 degraded盘故障或掉线看 dmesg、查 SMART设备名变了导致组装失败识别顺序变化用 UUID 组装检查 mdadm.conf重建速度极慢业务 IO 抢占带宽调 dev.raid.speed_limit_max--create报设备忙残留超级块mdadm --zero-superblock挂载后容量不对文件系统未扩展执行 resize2fs / xfs_growfs6.2 开机不自动组装与 mdadm.conf 的那些坑开机后阵列不见了多数是/etc/mdadm.conf的问题。常见的有三种文件不存在UUID 写错了或者写的是设备名而设备名变了。最稳的做法是永远用 UUID。mdadm --detail --scan --verbose输出的形式就是这样ARRAY /dev/md0 levelraid5 num-devices3 metadata1.2 namehost:0 UUIDxxxx:xxxx直接追加到配置文件就好。注意不要重复追加同一个阵列在配置文件里出现两次开机时可能会尝试组装两遍虽然通常不致命但日志里会刷一堆警告。另外检查一下/etc/fstab里挂载的是不是 UUID 而不是/dev/md0。虽然 md 设备名相对稳定但用 UUID 更保险。查阅 UUID 用blkid。6.3 虚拟机特有的坑快照、克隆与磁盘扩容虚拟机环境有几个真实服务器上不会遇到的情况值得单独说。第一是虚拟机快照。如果你在阵列正在重建或者初始化同步的时候打了个快照恢复快照之后阵列内部的进度计数和实际数据可能对不上mdadm 会认为阵列状态异常。我的习惯是做存储实验时关掉自动快照操作前先手动打个干净的快照当还原点。第二是克隆虚拟机。克隆出来的机器里硬盘内容是原样复制的包括 RAID 超级块和 LVM 的 PV 标签。两台机器同时开机可能互相看到对方的阵列甚至误组装。解决方法很简单克隆完成后立刻把克隆机的所有数据盘zero-superblock清一遍重新建阵列。第三是给已经加入阵列的虚拟磁盘在线扩容。虚拟化平台允许你在虚拟机运行时把虚拟磁盘从 10G 扩到 20G但 Linux 侧需要重新扫描才能看到新容量。SCSI 设备可以用echo 1 /sys/class/scsi_device/0:0:0:0/device/rescan触发重扫然后parted或者growpart扩展分区最后处理 md 设备。不过软 RAID 成员盘扩容后还需要mdadm --grow --sizemax /dev/md0才能让阵列用上多出来的空间这一步不做的话多出来的容量永远用不上。6.4 硬件 RAID 与软件 RAID 的差异对照前面所有实操都是基于 mdadm 的软件 RAID。真实服务器上你面对的多半是硬件 RAID 卡——比如各种品牌服务器上常见的阵列卡它们有自己的配置界面、缓存、电池或者超级电容保护。两者在操作路径上差别很大。硬件 RAID 的配置通常在服务器开机自检阶段进入按提示键进入配置界面手工选择磁盘组建阵列然后保存退出。操作系统看到的是一个已经做好的逻辑盘比如一块 1T 的盘实际上背后可能是四块物理盘组成的 RAID10。这种情况下对操作系统而言它只是一块普通的 SCSI 或者 SAS 盘。硬件 RAID 的优势是性能好、不占 CPU、有缓存加速、对操作系统透明劣势是依赖特定厂商的管理工具盘坏了必须有同型号备件跨机器迁移麻烦。软件 RAID 的优势是灵活、免费、不依赖硬件、可以跨平台迁移劣势是消耗主机 CPU 和内存性能上限受主机限制。管理层面硬件 RAID 的状态可以在操作系统的带外管理模块里查也可以用厂商提供的带内工具查。很多运维事故的根源是阵列卡报警了但没人配置告警通道直到第二块盘也坏了才发现那时候已经来不及了。所以只要用了硬件 RAID一定要把阵列健康状态接入监控。7. 我个人在实际操作中的几点体会做了这么多年存储相关的操作有几件事是我反复验证过的。所有阵列创建命令先在纸上或者文本编辑器里写一遍再回车。尤其是--raid-devices和设备名列表这两处写错了可能把系统盘卷进去代价是不可逆的。我在虚拟机里养成的习惯是先用lsblk把设备截图然后对着截图敲命令这个笨办法救过我好几次。监控比修复重要。阵列降级的时候只要还有冗余你就有时间从容处理真正致命的是降级状态下没发现直到第二块盘也坏了。哪怕是最简单的做法写个定时任务每天跑一次mdadm --detail把结果发到自己邮箱也比什么都不做好得多。别在生产环境追新。新版本内核带来的新特性、新的元数据格式实验环境里随便玩生产环境等它稳定一两年再说。存储层出问题的代价往往不是重启一下就能解决的。最后分享一个虚拟机上省时间的小技巧如果你要反复做阵列创建和销毁的练习把建阵列和清阵列分别写成一个脚本清阵列的脚本里固定包含stopzero-superblock两步每次练习前先跑一遍清理脚本。这样能避免百分之九十的设备忙和组装异常问题把注意力集中在阵列本身的行为观察上而不是纠缠在环境清理上。