
做运维这几年我一直跟人说RAID这个概念没有多神秘它就是“用一堆磁盘干大事”的方法论。真正动手的时候最常用的反而不是阵列卡里那些花哨的菜单而是Linux命令行下的软RAID命令。我见过不少同事一说RAID就想到磁盘阵列卡、想到机房其实在测试环境或者中小型服务上mdadm这套命令完全撑得起场面甚至比硬RAID卡更灵活、更容易排查。这篇文章就直接从RAID概念讲起一直讲到软RAID命令的完整使用方法适合刚入门的运维、自学Linux存储的开发者也适合那些正纠结“到底用软RAID还是硬RAID”的人。1. RAID的底层逻辑如何用多块物理盘拼出一块“虚拟盘”1.1 为什么会有RAID这种设计RAID全称是“独立磁盘冗余阵列”但这个翻译容易让人误会以为RAID就一定要冗余。实际上RAID最初的核心动机有两个一个是把多块小盘拼成一个大盘另一个是让多块盘一起工作来提升性能。后来人们发现多块盘还能互相备份数据才有了“冗余”这个附加属性。在早期的服务器环境里单块磁盘的容量和速度都落后于业务需求。想存更多数据就把几块盘并成一个逻辑盘想让数据读写更快就让几块盘同时参与IO。与此同时磁盘又是最容易坏的硬件之一一旦坏了数据就全丢。RAID就是在这三个诉求的拉扯下发展出来的既要容量扩展又要性能提升还要尽量避免单盘故障导致的数据灾难。理解RAID的关键是先理解它把多块盘抽象成一个“存储池”。操作系统看到的要么是一个块设备要么是一个卷组而不再是一块块孤立的盘。你在上面建文件系统、存数据剩下的条带、镜像、校验这些事情都在RAID层替你处理了。越明白这层抽象后面看软RAID的几条命令就越不费劲。1.2 条带化与镜像两个最基础的动作RAID里所有复杂机制追到根上就是两个动作条带化和镜像。条带化striping就是把连续的数据切成固定大小的块轮流写到不同磁盘上。举个例子一个文件分成8块两块盘做条带第1块写盘A、第2块写盘B、第3块写盘A、第4块写盘B……这样两块盘同时工作写入速度理论上接近单盘的数倍。看起来非常美好代价是没有冗余任何一块盘坏了整个文件都不完整。镜像mirroring则正好相反同一个数据同时写到两块盘上每块盘都保留一份完整副本。读的时候两块盘可以同时响应相当于读性能翻倍写的时候要写两份写入速度会受制于慢的那一块盘。好处是任何一块盘坏了数据都还在。你可能会问条带化为什么能提升性能核心是“并行”。单盘写入像一个单人窗口无论数据多大都得排队两块盘条带化之后任务分成了两条流水线同时干活。生活里最接近的类比是接力赛一个人跑完全程和四个人各跑一段同时出发总时间完全不同。RAID 0是纯条带RAID 1是纯镜像后面所有级别都是在这两个动作之上叠加运算逻辑。1.3 奇偶校验怎么工作只有条带和镜像还不够人们还想要一种更省空间的冗余方式不复制完整数据只存一点点“校验信息”等某块盘坏了能用剩下盘的信息把坏盘的内容推算回来。这个推算用到的就是异或运算XOR。异或的规则很直白两个比特相同结果为0不同结果为1。假设数据A和数据B分别存在两块盘上第三块盘存A XOR B的结果。如果存A的盘坏了我们就可以用B和校验值去反推出A因为 A (A XOR B) XOR B。校验信息占用的空间只有一块盘却能让阵列在坏掉一块盘时还能继续工作这就是RAID 5的雏形。RAID 5比较聪明的一点是把校验信息分散到所有盘上而不是固定放在某一块盘里。早期RAID 4把校验固定在专用盘上导致那块校验盘永远是写瓶颈。RAID 5让数据块和校验块轮流分布在各个盘上写入压力被摊开了。至于RAID 6相当于同时用两套校验算法来容错允许两块盘同时坏掉。理解了校验逻辑你就能明白为什么RAID 5最少要三块盘、RAID 6最少要四块盘——不是命令限制而是数学上就需要这么多盘才能算出缺失的数据。2. 常见RAID级别拆解容量、性能、冗余一次说清2.1 RAID 0和RAID 1两个最典型的极端RAID 0是纯条带化。N块盘组成阵列后可用容量是N块盘的总和读写性能理论上随盘数线性提升但容错能力为零。任何一块盘坏了阵列直接降级甚至失效所有数据都无法访问。它适合那些数据丢了也无所谓的场景比如临时计算目录、视频渲染缓存、游戏缓存盘等。在真生产环境里我通常不推荐RAID 0除非你非常清楚自己在做什么。RAID 1是纯镜像。两块盘互为副本可用容量只有总容量的一半。读取时可以从两块盘同时读随机读取性能提升明显写入则要双写速度不会翻倍。两块盘同时坏的概率远低于一块盘坏所以RAID 1提供的保护是实实在在的。系统盘、配置目录、关键小文件用RAID 1非常稳。这两者是最好理解的极端其余级别的逻辑都建立在它们之上要么“条带镜像”要么“条带校验”。2.2 RAID 5和RAID 6用校验换冗余RAID 5是条带化加分布式校验。最少需要3块盘N块盘的可用容量是(N-1)块盘的容量允许任意一块盘故障而不丢数据。写入时不仅要把数据写进目标盘还要读取旧数据和旧校验块计算新校验值再分别写回数据盘和校验盘一次写操作实际会产生多次内部IO这就是所谓的“写惩罚”。RAID 6在RAID 5的基础上增加一个独立的校验块最少需要4块盘可用容量是(N-2)块盘的容量允许任意两块盘故障。写入惩罚比RAID 5更重因为要同时维护两份校验数据。它适合大容量文件存储、备份仓库这些对单盘故障容忍度要求更高的场景。代价也很直接盘位变多、容量打折、写入性能下降。2.3 RAID 10镜像加条带的组合RAID 10不是另一种独立算法而是RAID 1和RAID 0的叠加先把偶数块盘两两做成镜像再把多组镜像条带化。最少4块盘可用容量为总容量的一半。它继承了RAID 1的可靠性和RAID 0的并行读写能力随机读写性能都很不错而且重建速度通常比RAID 5快因为重建时只要从镜像盘复制数据不需要用校验去推算。生产数据库和高IO业务里RAID 10一直是很多运维的首选。虽然它同样需要浪费一半容量但换来的是稳定可预测的性能以及故障重建时更短的风险窗口。2.4 选型时容易忽略的容量与盘型规则先给出一个常用对比表方便一目了然RAID级别最少盘数可用容量容错能力写惩罚典型场景RAID 02总容量无1倍缓存、临时计算RAID 12总容量/21块盘2倍系统盘、关键配置RAID 53(N-1)×单盘1块盘4倍文件存储、影音库RAID 64(N-2)×单盘2块盘6倍备份仓库、大容量存储RAID 104总容量/2每组各1块2倍数据库、高IO业务选型时有三个容易被忽视的规则第一阵列容量按最小的那块盘计算。比如一块4TB和一块8TB组RAID 1阵列容量按4TB算8TB盘多出来的4TB全部浪费。所以组建新阵列时尽量保证同批次、同容量、同型号的盘。第二不要混合不同转速或者不同接口类型的盘。机械盘之间转速差异大条带化的性能会被慢盘拖住SSD和HDD混合组阵列更是灾难会导致持续性能波动。第三热备盘spare不是冗余的替代品。热备盘只是坏了之后能自动顶上来重建但在重建完成之前阵列仍处于降级状态此时再坏一块就彻底危险了。3. 软RAID与硬RAID的取舍为什么命令行方式仍然值得学3.1 硬RAID卡的收益与限制硬RAID卡有专用的芯片独立完成条带化、镜像和校验计算CPU完全不用参与而且自带缓存甚至带掉电保护模块。系统里看到的就是一个普通的块设备不关心你底层组的是什么级别。这种“黑盒换便利”的方式确实让很多传统企业的数据存储省心了不少。但硬RAID卡也有明显局限。首先是价格入门级和主流级之间差价不小其次是故障排查透明性差卡坏了以后如果你没有同型号备件恢复阵列会很麻烦还有一个容易被忽略的点很多低端“硬卡”本质上还是软件模拟只是主板给了个BIOS界面性能和稳定性并没有真正到硬件的级别。我自己的使用感受是硬RAID卡适合那种环境固定、预算充足、希望系统层面无感知的生产机房。如果是在学习环境、测试环境或者成本敏感的小型业务里硬卡的优势并不明显反而增加了硬件依赖。3.2 软RAID的适用场景Linux内核自带的md模块就是纯软件RAID实现配套命令是mdadm。它让普通磁盘变成一个逻辑阵列计算由CPU完成不需要额外硬件。所有状态都能用命令查到配置文本可以备份整组盘拆下来搬到新机器上也能重新组装阵列这是硬RAID卡不容易做到的。软RAID非常适合这些场景个人NAS、虚拟机数据盘、测试开发环境、临时文件服务器、边学边折腾的实验机。在这些环境里CPU性能普遍过剩偶发的校验计算开销几乎可以忽略而软RAID带来的灵活性反而很实在。3.3 “软RAID很慢”这个印象靠谱吗这个印象有一定历史原因。早期CPU算力弱RAID 5的XOR运算确实会吃掉不少性能。但放在现在一台普通服务器的CPU做软RAID校验占用率通常可以忽略不计。我实测过用软RAID 5跑大文件读写性能瓶颈基本都落在磁盘本身的吞吐上而不是CPU。真正要区分的点是“缓存”。硬RAID卡如果带合理容量的缓存随机写入性能会好看很多软RAID没有硬件缓存写入完全靠内核和磁盘控制器自身的缓存。但只要你不是拿它做极高IOPS的OLTP数据库存储差距并不明显。即便真要做数据库很多人也会选择RAID 10而不是RAID 5写惩罚小软RAID表现同样稳定。所以我的结论是软RAID“慢”的说法现在并不成立它更应该在可靠性和调度上下心思而不是一概否定。4. mdadm完整实战从磁盘识别到创建阵列4.1 准备环境安装mdadm与识别磁盘在Debian/Ubuntu系统上安装apt install mdadm在CentOS/RHEL系列上yum install mdadm装好之后先用lsblk或fdisk看看系统里有哪几块盘lsblk fdisk -l我特别建议不要只记sdX盘符因为重启后设备名可能变化。用下面的路径识别磁盘更安全ls -l /dev/disk/by-id/创建阵列之前最好确认目标盘上没有残留的RAID元数据。对单块盘执行mdadm --examine /dev/sdb如果提示“no superblock found”说明这块盘是干净的如果显示出旧阵列信息说明它之前被软RAID用过需要清掉元数据再使用mdadm --zero-superblock /dev/sdb这一步非常重要。我遇到过不止一次拿旧盘组新阵列时因为superblock残留导致mdadm直接拒绝创建或者在重装系统后md设备名和挂载点全乱套。养成“先用examine检查、再动盘”的习惯能少踩很多坑。4.2 创建不同级别RAID的完整命令mdadm创建阵列的基本语法是mdadm --create /dev/md0 --level1 --raid-devices2 /dev/sdb /dev/sdc创建RAID 0两块盘mdadm --create /dev/md0 --level0 --raid-devices2 /dev/sdb /dev/sdc创建RAID 1两块盘mdadm --create /dev/md0 --level1 --raid-devices2 /dev/sdb /dev/sdc创建RAID 5三块盘mdadm --create /dev/md0 --level5 --raid-devices3 /dev/sdb /dev/sdc /dev/sdd创建RAID 10四块盘mdadm --create /dev/md0 --level10 --raid-devices4 /dev/sdb /dev/sdc /dev/sdd /dev/sde参数含义很好记--create表示新建--level指定级别--raid-devices指定实际参与阵列的磁盘数后面跟着的是成员盘列表。创建完成后立即查看状态cat /proc/mdstat mdadm --detail /dev/md0刚创建完的阵列会有一段初始化同步时间此时mdstat里能看到resync进度。RAID 5和RAID 6尤其明显因为它们要计算并写入校验信息。阵列创建好后就可以把它当成普通块设备使用。格式化文件系统mkfs.ext4 /dev/md0或者用XFSmkfs.xfs /dev/md0这里有个chunk大小的概念值得多说两句。chunk是条带化的最小单位可以理解为条带切块的颗粒度场景chunk建议原因大文件顺序读写512KB或1MB减少切块碎片保持连续吞吐数据库随机读写64KB或128KB减少小IO带来的校验放大普通文件服务器256KB左右在两者之间取平衡mdadm默认创建的chunk大小通常够用。除非你明确知道业务IO模型否则我不建议为调chunk而折腾默认值对绝大多数场景是合适的。4.3 写配置让阵列开机自动组装软RAID创建完毕如果什么都不配重启后存在两个风险一是md设备名可能漂移成md127二是阵列未必能自动识别。解决办法是把阵列信息写入配置文件。Debian/Ubuntu路径是/etc/mdadm/mdadm.confCentOS/RHEL通常是/etc/mdadm.conf不过现在很多新版也统一了。我建议直接用下面的命令追加扫描结果mdadm --detail --scan /etc/mdadm.conf这条命令生成的内容大致长这样ARRAY /dev/md0 metadata1.2 nameserver:0 UUIDxxxxxxxx:xxxxxxxx:xxxxxxxx:xxxxxxxx这个配置文件的意义是告诉系统“这些UUID对应的盘应该组合成md0”。为了确保启动镜像里也包含这些配置Debian系更新initramfsupdate-initramfs -uRHEL系则要运行dracut --force最后把挂载信息写进/etc/fstab。建议用UUID而不是设备名例如UUIDxxxx-xxxx /data ext4 defaults 0 2到这一步一个完整的软RAID才算是“交付”了重启后能自动组装、自动挂载。很多新人创建完阵列能同步、能挂载觉得大功告成结果重启后系统进不去或者数据目录空中十有八九就是漏写了配置文件这一环。5. 软RAID日常维护、故障模拟与扩容5.1 实时状态怎么看日常维护最常用的命令是cat /proc/mdstatwatch -n 1 cat /proc/mdstat使用watch每秒刷新一次能实时看到同步进度和阵列健康状态。mdstat输出的关键部分是类似[UUUU]这样的字符每个U代表一块健康的活动盘_代表丢失或故障盘。常见状态我整理成了表格状态显示含义处理建议[UUUU]所有盘正常无需处理[UU_U]有一块盘失效正在重建尽快把备件换上[UU_]有多块盘异常阵列已降级数据存在风险[____]多盘同时失效数据大概率不可用检查备份更详细的信息看mdadm --detailmdadm --detail /dev/md0可以看到每一块成员盘的盘符、状态、重建进度、坏块统计等。这类信息很适合接入监控脚本定期解析后发到值班系统。5.2 模拟磁盘故障与热备盘使用软RAID里模拟磁盘故障非常简单而且很有用。你可以先在测试环境里演练一遍真出问题时就不会手忙脚乱。先给阵列添加一块热备盘mdadm --manage /dev/md0 --add /dev/sde然后模拟一块成员盘故障mdadm --manage /dev/md0 --fail /dev/sdb执行完立即查看mdstat会发现阵列进入降级重建状态。热备盘会自动顶替故障盘参与重建整个过程中阵列不需要停机业务IO只是降速不会中断。等重建结束后把故障盘从阵列中移除mdadm --manage /dev/md0 --remove /dev/sdb再插上一块新盘加入热备池mdadm --manage /dev/md0 --add /dev/sdb演练的价值在真出故障时体现得最明显。我见过有些环境平时不测重建流程真到盘坏了才发现热备盘没插、备件型号不对、监控没告警只能惊慌失措地停机排查。软RAID花了你十分钟做的演练关键时刻能省下半天。5.3 在线扩容mdadm --grow与文件系统扩展软RAID另一个好用的能力是在线扩容。RAID 5三块盘想扩成四块先加入新盘作为热备mdadm --manage /dev/md0 --add /dev/sde然后执行扩容mdadm --grow /dev/md0 --raid-devices4mdstat里会开始一次reshape这个过程的耗时取决于数据量和新盘性能。重点提醒reshape期间阵列入负荷运行不要强行重启更不要在这个时间窗口里做大规模写入。等到reshape完成再去扩展文件系统。ext4用resize2fs /dev/md0XFS用xfs_growfs /挂载点顺序不能反。文件系统必须在底层块设备扩展完成之后才能扩大如果先扩了文件系统要么报错要么产生不一致。RAID 1扩容的含义是把两块镜像扩成更多磁盘阵列依旧保持镜像形态RAID 0扩容因为条带布局要重排风险比RAID 5高动手前务必把数据备份清楚。5.4 踩过的坑和养成的习惯最后把几年里反复踩过的坑集中说一遍每一条都是用时间和数据换来的。第一不要把盘符写进脚本里。状态监控、自动挂载、阵列组装都尽量用UUID或磁盘by-id路径。Linux盘符会随着磁盘插拔顺序改变用固定标识才能保证行为可预期。第二RAID不是备份。RAID保护的是磁盘硬件损坏保护不了误删、文件系统损坏、软件锁死这些问题。软RAID做得再好备份和恢复演练也要持续做。第三重建期间千万不要随意热拔盘。很多时候盘并没有物理损坏只是瞬时IO错误或者链路抖动。直接拔盘会让阵列以为盘离线触发大规模重建反而增加风险。发现异常后先看dmesg确认是物理故障再操作。第四开机启动顺序要注意。如果是用软RAID承载根文件系统建议把/boot也放在RAID支持的范围内但要注意引导程序对md设备的支持情况。测试环境里最稳妥的做法是先验证重启能自动组装再正式投入使用。第五养成三个习惯每个新阵列记录UUID创建后立即做一次重启验证每月抽查一次mdadm --detail的输出。这三个习惯花不了几分钟但能避免绝大多数“重启后找不到阵列”的悲剧。每次弄完软RAID我都会顺手把UUID记到内部的配置清单里并在值班脚本里留一个接口去定期解析mdstat。几年下来这套纯命令行的软RAID方案在中小规模项目里一直很稳也让我对那些花哨的阵列卡界面渐渐没了依赖。RAID并不复杂说到底就是把几个基础动作做扎实然后把纪律执行到位。