ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

硬RAID崩盘数据救援实录:从Foreign Config到软RAID重建

硬RAID崩盘数据救援实录:从Foreign Config到软RAID重建 凌晨1点23分监控平台推了一条告警核心存储心跳丢失。我盯着那台已经服役十年的Dell PowerEdge R710心里其实早有预感——这段时间风扇声音忽大忽小阵列卡电池早就提示过Learning Cycle failed只是没人舍得停机去处理。这次断电重启之后PERC H700 BIOS直接甩出一句“Foreign Configuration Found”RAID5虚拟盘从系统里蒸发接近10TB的仓库数据像被没收了钥匙的保险柜。这篇文章就是记录我从硬RAID崩盘到把数据全部捞出来、再用软RAID给老盘续命的全过程适合所有正在维护老旧服务器、或者对磁盘阵列数据恢复有需求的运维朋友。如果你也遇到类似情况希望这篇记录能帮你少走几个弯路。1. 事故现场一台10年老服务器的“临终症状”1.1 这台“老伙计”的履历与故障前兆先说清楚这台机器的背景。R710是Dell在2009年到2013年前后非常主流的一代机架式服务器2U的高度双路Xeon X565032GB内存阵列卡是PERC H700配512MB缓存和BBU电池。存储侧用了6块2TB企业级SATA盘做成RAID5可用容量大概在10TB左右。它的日常工作很杂内部Samba文件共享、几台测试虚拟机镜像存储、以及各种部门数据的集中备份目标。我在这里想强调的是这台机器并不是“突然暴毙”的。翻看iDRAC日志过去三个月里已经连续出现BBU voltage low、battery learn cycle failed这类的提示。RAID控制器的BBU电池是负责给写缓存供电的一旦电池失效控制器会强制把写策略从Write Back降到Write Through性能大打折扣同时每次断电之后缓存里可能遗留未落盘的写请求。更麻烦的是电池出问题往往意味着阵列卡上的配置数据也存在潜在风险只是当时没当回事。另外iDRAC里还出现过某块盘的pending sector警告但SMART整体状态还是Passed所以也没有及时换盘处理。这里必须要说一句运维这种工作所有故障几乎都有前兆区别只在于你有没有注意到以及愿不愿意为“还没坏”的设备停机检查。我们当时恰恰是因为业务部门说存储不能停就把这些问题记在工单里搁置了。结果呢一次机房UPS电池挂掉导致的意外断电就把这些问题全部引爆了。1.2 硬RAID崩盘的现场表现虚拟盘人间蒸发意外断电之后R710再次上电屏幕直接卡在PERC开机自检阶段。我当时看到三行字心就凉了半截Controller cache contains invalid dataForeign configuration foundVirtual Disk Degraded or Offline按CtrlR进入PERC BIOS配置界面以后VD Mgmt页面里看不到原来那个RAID5虚拟盘了或者看到某个卷但状态直接是Offline。系统自然也无法引导因为整台机器的系统盘和数据库盘都在这组RAID5上面。这时候能感受到的就是标题里说的那种“临终”氛围——机器硬件还在六块硬盘指示灯也都亮着但逻辑上数据已经“蒸发”了。硬RAID的设计思路是每块硬盘上不仅存业务数据还会在盘头区域写入控制器的厂商私有元数据包括RAID级别、条带大小、磁盘在阵列里的序号、阵列UUID等信息。正常情况下控制器启动时读取这些元数据重建出虚拟盘。但当控制器本身的配置区损坏、缓存内容与磁盘元数据不一致时它就会认为这是一组“外部配置”也就是Foreign Config。如果控制器连解析自己的能力都失去了那就只能看到六块孤零零的物理盘整个逻辑卷像中介跑路后的仓库——货都还在但钥匙和账本都不在你手里。1.3 硬RAID与软RAID的本质区别关键时刻谁更可靠这次事故让我把硬RAID和软RAID的界限想得特别清楚。硬RAID的优点在于性能稳定、有独立缓存和电池保护系统层面看不到底层物理盘管理和部署都比较省心。但它的软肋也恰恰在这里配置信息依赖阵列卡这套私有的元数据格式。一旦阵列卡本体损坏、固件出错、电池失效导致缓存和盘上元数据不一致你就只能靠“换同型号卡导入配置”或者“第三方软件解析私有元数据”这两条路来恢复。换句话说硬RAID把数据安全的一部分押在了控制器硬件身上而控制器恰恰是整台服务器里故障率不低的部件。软RAID也就是Linux下常用的mdadm采用的是开源标准的元数据格式。每块盘上会记录阵列UUID、该盘在阵列中的编号、条带大小、RAID级别等信息。只要操作系统能识别到物理盘mdadm就有机会通过--assemble把阵列完整组起来完全不依赖某一张特定的“卡”。换个机器、换块主板、换套系统只要磁盘本身的元数据没有被破坏阵列就能认回来。软RAID的劣势主要是没有独立缓存、随机写性能比不上硬RAID以及CPU会承担一部分校验计算开销。但对我们这次的数据抢救场景来说“可迁移性”比“性能”重要得多。这也是为什么我后面会强调硬RAID崩盘后用软RAID的思路去镜像、分析和重组数据甚至救完数据后直接改成软RAID来兜底往往比死磕原厂阵列卡更务实。2. 抢救思路先稳住别让手比脑子快2.1 数据恢复第一原则不要乱动原始盘看到Foreign Config很多人的第一反应是进PERC界面选一个“Clear Foreign Configuration”或者“Create New VD”把配置清掉想直接重建RAID。这个动作在数据还有可能恢复的时候等于亲手把最后的目录给烧了。Foreign Config的含义是控制器认出了这些盘上有一套它不完全认可的配置盘上还有希望Clear之后控制器会把这些盘当作全新空盘所有阵列元数据会被重新初始化。第二个绝对不能做的事就是看到RAID5降级就马上“Rebuild”。RAID5本来允许坏一块盘但在阵列处于非正常状态、配置还不完整的时候触发重建控制器会往所有完好的盘上写入大量校验数据这一写很可能就会覆盖掉真正用来定位数据的元信息。Reconstruct等操作也是一样在没有完整备份前任何向原始盘写入的动作都是危险的。我自己的原则很简单先给每块物理盘做盘级镜像之后的任何分析、试验、尝试都在镜像上进行。原始盘只在必要时被挂载为只读而且尽量使用blockdev --setro这类手段从内核层面把写保护打开防止操作系统在挂载文件系统时偷偷改掉部分块。数据恢复这件事最大的敌人不是技术而是“着急”。2.2 三条可行的救援路线换卡导入、软件重组、镜像离线我根据当时的条件整理了三套方案列个表方便你对比方案核心操作优点缺点/风险适合场景A. 更换同型号阵列卡导入买一块同型号、固件版本接近的阵列卡替换旧卡进PERC导入Foreign Config恢复速度快配置可被控制器直接识别业务停机窗口短需硬件采购周期新旧卡固件差异可能导致无法识别元数据控制器硬件损坏但盘组物理完整B. 物理盘直通后用软件重组拆除阵列卡或改成直通模式让Linux直接看到物理盘用R-Studio/UFS Explorer等软件自动分析盘序、条带大小、旋转方向不依赖阵列卡厂商可离线分析原始盘只读需专业软件授权对RAID5参数识别错误可能导致恢复失败耗时较长没有同型号卡、或卡完全无法识别盘组C. 逐盘ddrescue镜像后离线拯救将每块物理盘完整复制成镜像文件再从镜像中提取文件系统或重组RAID原始盘完全不受二次损害遇到坏道可断点续跑镜像时间极长6块2TB可能需要一整天以上需要额外的镜像存储空间原始盘有坏道、现场不允许长时间反复折腾这三条路线并不互斥甚至应该串联起来用。我的实操顺序是C优先起步同时推进A如果A失败再用B作为兜底。2.3 我这次为什么选择“双保险”方案其实我当时最理想的做法是马上找一块能兼容R710的拆机H700阵列卡。但问题在于这台十年老设备的配件已经不太好找同型号、带BBU、固件版本还要差不多的卡本地渠道至少需要两到三天的物流周期。在等待期间我不能让六块盘就这么躺着因为谁也不敢保证它们在搬运、通电过程中不会出现新的坏道。所以我的决定是“镜像先行”。先用一台空闲的Linux服务器把六块物理盘逐块做成全盘镜像镜像文件放在另一台相对新的存储服务器上。这样即便接下来换卡导入失败、或者某块盘再次通电后彻底掉线我们手里都有一份不会变的“磁盘级快照”随时可以退回方案B或C继续进行数据恢复。软RAID的思想在这里已经开始体现了不去依赖那台老掉的R710和那张旧阵列卡而是以标准块设备为最小单位去保护数据。顺便说一句也有朋友建议我直接用mdadm --build把六块盘按RAID5参数手工绑成一个设备来抢救数据。这个思路理论上可行但前提是你必须准确知道每块盘在原始阵列中的顺序、条带大小、左异步还是右异步、校验旋转方向等参数。哪怕只有一个参数搞错读出来就是一堆乱码而且这种手工绑定对盘序极其敏感万一你把盘顺序排错后面的分析会非常痛苦。我的建议是如果你不是对这个硬RAID阵列的创建参数有百分之百把握不要轻易用mdadm --build硬拼原始盘组。专业数据恢复软件会自动计算这些参数比手工猜要可靠得多。软RAID真正可靠的地方是数据恢复完成之后把老盘重新做成一个干净可靠的存储池。3. 实操记录从镜像备份到软RAID重建3.1 第1步按槽位拍照记录逐盘做ddrescue镜像先把R710断电拔掉所有硬盘托架。我在每个托架和盘体上贴了标签标注1到6的槽位号同时用笔记下每块盘的SN序列号。这一步看起来简单但关键时刻能省命——后面无论是换卡导入还是用软件重组盘序和磁盘标识都是最重要的参数。镜像用的是一台闲置的Linux服务器上面有6个空闲SATA口外加一块专门存镜像的新存储。我用smartctl -i /dev/sdX查看每块盘的Serial Number反复和标签核对确保设备名和盘号一一对应。然后对每块盘执行mkdir -p /data/images ddrescue -f -n /dev/sdb /data/images/disk1.img /data/images/disk1.log-f表示覆盖目标文件-n表示第一次扫描不执行读后校验速度更快。如果盘上已经有坏道ddrescue会把坏道区块记录到log里之后再加-r参数重试几次。执行完之后我用sha256sum分别对盘和镜像做了抽样校验确认镜像没有静默损坏。这里有个容易被忽略的细节ddrescue的log文件一定要保留好。万一镜像过程中断重新运行时只要指定同一个log文件ddrescue会自动从上次断点继续而不是从头再来。六块2TB盘做完整镜像总耗时差不多一天一夜所以我把任务放在tmux里后台执行期间反复检查cat /proc/mdstat和df -h确认镜像存储空间不会写满。3.2 第2步替换阵列卡并导入Foreign Config镜像全部完成之后我才开始动R710本体。关机、拔电源线、拆下旧的H700换上从渠道买来的拆机H700。这里有一个关键点新换的卡固件版本最好和旧卡接近。如果差异太大控制器在解析盘上元数据的时候可能会因为格式理解不一致而失败。我那台旧卡的固件版本是H700的某个中期版本渠道发的拆机卡正好是同一个版本运气还算不错。装好新卡之后把六块盘按原槽位插回上电开机。自检阶段屏幕照例跳出Foreign Config提示按CtrlR进入PERC配置界面选择F2 - Foreign Config - Import。导入过程花了大概四十多分钟期间阵列卡LED一直在闪我没有断电也没有手贱去点其它选项。导入完成后VD Mgmt里终于重新出现了原来的RAID5卷状态是Online。如果此时状态是Degraded也不要急着点Rebuild先想办法把数据挂载出来再谈重建。Rebuild会对所有盘执行大量写入而写入本身就是风险。如果你的环境里不太方便进BIOS界面也可以用管理工具直接导入。比如megacli -CfgForeign -Import -a0或者storcli /c0 /fall import导入失败时先检查电池状态和写缓存策略。如果BBU状态是Failed尽量先在PERC里把Write Policy改成Write Through避免导入过程中缓存再次积累不一致的数据。3.3 第3步挂载虚拟盘把数据“捞”出来导入成功后我用一个Ubuntu live USB引导系统lsblk里能看到一个接近10TB的大设备这就是原RAID5虚拟盘。分区是ext4我直接mount到/mnt/recoverymount /dev/sdb1 /mnt/recovery挂载之后先别急着拷文件我习惯先做一次“冒烟测试”在根目录touch一个测试文件确认文件系统是否能正常写入再用df -h确认容量和大文件目录结构与自己记忆中的一致。确认没问题后开始rsync拷贝到新存储服务器rsync -av --infoprogress2 /mnt/recovery/ /mnt/newstore/整个拷贝过程持续了一整夜。为了不让长时间运行的命令行因为SSH断开而中断我把rsync放进tmux会话里执行。拷贝完成后又对一些关键的大文件目录做了sha256sum抽样校验确保文件内容没有损坏。这里要特别提醒数据量越大越不要迷信rsync的默认行为最好在拷贝完成后再做一轮文件大小、时间戳甚至内容的比对尤其是那些长期没有打开过的旧文件。3.4 第4步清盘后用mdadm重组成软RAID6数据确认完整之后这台R710的原始使命就算完成了。接下来我给老盘找到了新身份把它从硬RAID改造成一台纯粹的软RAID备份存储。先清理控制器上的阵列配置。如果还留着H700可以进PERC界面把所有VD删除再Clear Foreign Config如果不打算再用这张老卡直接拆掉把六块盘接到主板自带的SATA口上。然后清掉每块盘头部残留的RAID元数据避免系统误判dd if/dev/zero of/dev/sdb bs1M count100 statusprogress清完盘用mdadm创建软RAID6mdadm --create /dev/md0 --level6 --raid-devices6 --chunk256K /dev/sdb /dev/sdc /dev/sdd /dev/sde /dev/sdf /dev/sdg为什么选RAID6而不是RAID5因为这几块盘都服役十年了任何一块随时都可能彻底报废。RAID6允许同时坏两块盘在重建窗口内再挂一块也不至于全盘覆没对老机械盘来说这个冗余度更安心。chunk选256K是兼顾备份场景的连续大文件读写性能如果是大量小文件随机读写128K可能更合适。创建完成后调整重同步速度避免把CPU占满echo 50000 /proc/sys/dev/raid/speed_limit_min然后把阵列信息写入配置保证重启后能自动识别mdadm --detail --scan /etc/mdadm.conf mkfs.ext4 /dev/md0 mkdir -p /mnt/backup mount /dev/md0 /mnt/backup把挂载项写进/etc/fstab时我习惯用UUID而不是设备名因为重启后盘符可能漂移。用blkid查一下阵列的UUID然后写成类似这样UUIDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/backup ext4 defaults 0 2如果你想把兼容性做得好一点在创建mdadm阵列时也可以指定--metadata1.0但1.2已经能覆盖绝大多数现代发行版通常不需要特地去改。4. 常见问题与排查技巧实录4.1 阵列卡和Foreign Config最折磨人的几个坑换卡导入这个环节我见过太多翻车案例很多都不是盘坏了而是操作认知出了问题。第一个坑是导入失败却不知道原因。最常见的原因是新旧卡固件版本差异太大。控制器对盘上元数据的解析是严格按照固件逻辑来的老卡组出来的卷新卡固件如果经过大规模升级很可能拒绝导入。遇到这种情况先别急着Clear找一块和旧卡固件版本相同或非常接近的卡再试成功率会高很多。第二个坑是电池状态导致写缓存策略异常。H700这类控制器带BBU电池如果电池显示Failed控制器会认为掉电时无法保护缓存于是导入配置时可能拒绝加载某些数据。这时候进入PERC BIOS把Write Policy改成Write Through或者用命令行设置megacli -LDSetProp -WT -L0 -a0让控制器尽量降低对缓存和电池的依赖往往能提高导入成功率。第三个坑是导入后自动触发Rebuild。有些情况下控制器判断RAID5处于降级状态会自动开始重建。Rebuild是对整组磁盘的大量写入对正在抢救的数据风险很大。如果你还没完全备份数据这时应该优先取消或暂停重建先把虚拟盘挂载、把关键数据拷出来再考虑后续操作。4.2 软RAID组建与长期维护的实战细节软RAID组建本身并不难难在后期维护。最容易翻车的是重启后阵列设备名漂移。我第一次用mdadm的时候直接写了/dev/md0结果有一次系统启动顺序变化启动脚本加载的盘符和/etc/fstab里的不一致整个备份分区差点挂不上。后来学乖了所有挂载一律用UUID并确保/etc/mdadm.conf里的ARRAY记录完整。第二个常见问题是resync速度太慢。创建RAID6后会有一轮全盘同步如果机器负载较高速度可能只有几千KB/s心急的人会以为卡死了。可以动态调整两个内核参数echo 100000 /proc/sys/dev/raid/speed_limit_min echo 200000 /proc/sys/dev/raid/speed_limit_max数值越大同步越快但CPU占用和磁盘I/O也会上升。备份服务器如果夜里没有业务可以调大白天要正常使用就调回适中值。第三个坑是某块盘掉线后没有及时恢复。软RAID虽然不怕单盘故障但如果掉线的盘长期不处理第二块盘再坏的时候阵列就会退化到不可用状态。我之前写过一个巡检脚本每天凌晨检查/proc/mdstat和smartctl健康状态有异常直接发通知。几千块钱的数据盘不值钱值钱的是上面的数据。4.3 镜像与数据校验避坑指南很多人在救援时喜欢直接把原盘挂载成只读然后用文件系统工具去检查。这里有个容易被忽视的细节某些文件系统即使只读挂载也可能会更新日志区或元数据比如ext4在挂载时会根据日志状态做一些处理。出于绝对安全考虑建议先做盘级镜像所有文件系统层面的分析都在镜像文件上做或者至少用blockdev --setro把物理盘设为内核级只读。镜像的坑主要在效率和校验上。第一次扫描用ddrescue -n速度快如果盘上坏道多再用-r参数重试。千万不要对着一块物理盘反复读坏道区域那会让机械盘磁头持续反复寻道反而加剧损坏。镜像文件要存放在独立存储上不要和原始盘放在同一个逻辑卷里防止存储满导致镜像中断。校验方面全盘sha256sum在实际工作中太耗时没必要。我通常对超过100MB的大文件、数据库备份文件、以及关键业务目录做抽样哈希比对或者直接用rsync -c对源目录和目标目录做内容级校验。这样既控制了时间又能覆盖绝大多数数据安全风险。5. 善后与长期保存建议别等“临终”才想起抢救5.1 给老服务器补一份“数字遗嘱”数据抢救成功之后我给这台R710补了一套“数字遗嘱”机柜里每台服务器的硬盘槽位、SN序列号、RAID级别、条带大小、控制器型号和固件版本、虚拟盘分区布局全部整理成文档放到内部Wiki和纸质运维手册里各一份。以前这些信息只存在于我的记忆里出了这次事故我意识到记忆是最不可靠的存储介质。另外一个容易被忽略的点是时间同步。老服务器主板上的CMOS电池早就不行了每次断电重启系统时间都会乱掉这个问题会直接影响日志排查。我在善后时顺手把NTP时间同步装好确保所有服务器都能自动对时。日志时间戳不一致在故障排查时会造成极大的判断干扰。5.2 软RAID并不低端备份存储的务实选择以前团队里谈到软RAID总有一种“不如硬件卡正规”的偏见。经过这次事故我反而觉得对老硬件来说软RAID是一种更务实的选择。它不依赖特定控制器的私有元数据格式只要机器能识别磁盘mdadm就可以把阵列组回来。对于一台十年老服务器来说硬RAID的优势——性能稳定、独立缓存——已经不再重要甚至老旧控制器的私有格式反而成了数据可迁移性的障碍。现在这台R710的定位就是一台安静的冷备机6块老盘组着软RAID6每天凌晨接收新存储推来的增量备份。它的性能确实谈不上好但作为最后一道防线重要的是“能认盘、能重建、不绑定配件”。我也建议每一个还在用古董服务器的团队认真评估一下自己的数据链路如果主板坏了、阵列卡坏了、机器被偷了、机房进不了你还能不能快速把数据拿出来答案越明确心里越有底。最后再分享一个我个人的体会数据抢救这件事拼的从来不是临场用了什么惊为天人的工具而是日常有没有给意外留好退路。这次能从硬RAID崩盘里全身而退靠的是提前做了盘级镜像、没有乱Clear配置、以及运气够好。如果你手边也有一台濒临退役的老服务器请记住这次事故里最痛的教训见到Foreign Config先拍照、先做镜像再考虑导入或重建不要相信任何阵列卡电池“还能再撑一年”的自我安慰老数据只有多副本才叫备份。救得回来是运气救不回来往往是因为我们太相信运气。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进