首页 / 资讯中心 / 文章详情

固态硬盘坏块导致数据库无法拷贝?从故障定位到镜像修复全复盘

固态硬盘坏块导致数据库无法拷贝?从故障定位到镜像修复全复盘 ★ FEATURED ARTICLE
前两天接了个挺典型的求助客户说公司一台文件服务器上的普通固态硬盘最近经常卡顿昨天直接蓝屏重启之后系统能进但C盘系统分区已经不太正常D盘里放数据库文件的目录能看见真正去拷贝MDF和LDF文件时进度条走到百分之十几就彻底卡死取消都没反应。听完整个人的心都往下沉——这种“固态硬盘坏块 系统崩溃 数据库无法拷贝”的组合恰恰是数据修复场景里最经典、也最容易被错误操作搞砸的故障类型。这篇文章就把这个案例完整复盘一遍从故障判断、底层镜像、文件系统修复到数据库文件的抢救每一步为什么这么做、踩了哪些坑、有哪些替代方案都会写清楚对运维、DBA以及遇到类似崩溃又不知道怎么处理的普通用户都有直接参考价值。1. 故障现场从“系统还能进”到“数据库拷不出来”1.1 客户描述里的几个关键破绽客户最初给我发的消息只有一句话“D盘数据库拷不出来系统蓝屏了几次现在开机很慢。”这种描述太笼统了我让他补充了几个细节蓝屏之前电脑是不是已经慢了大概一两周答是尤其打开大文件、复制大目录时特别明显。蓝屏代码还记得吗答拍了一张照片是KERNEL_DATA_INPAGE_ERROR后面跟着WHEA_UNCORRECTABLE_ERROR的字样。重启之后D盘是整个打不开还是目录能进但文件拷不动答目录能打开文件名能看到但是点进去复制就卡死鼠标还能动复制窗口进度条不动。有没有试过对D盘做磁盘检查答试过一次跑到一半卡住重启后又进系统了。这几个细节合在一起基本可以排除“单纯的文件系统逻辑损坏”。文件系统逻辑问题通常表现为目录结构错乱、文件名乱码、提示文件或目录损坏且无法读取但一般不会让整个复制操作彻底无响应更不会伴随多次系统蓝屏。KERNEL_DATA_INPAGE_ERROR这个报错尤其关键它说明内核在从页面文件或普通文件读取数据时失败底层原因大概率是硬盘介质读取错误而不是应用层文件坏了。1.2 十分钟定位先别碰文件看SMART和底层读取接手之后我没有先让客户继续在原盘上复制文件而是把盘拆下来接入一台Linux机器做了两件事看SMART健康信息和做底层读取测试。看SMART用的是 smartctlsudo smartctl -a /dev/sdb重点关注这几个属性属性ID名称意义05Reallocated_Sector_Ct已经被重映射到备用区的坏块数量C5Current_Pending_Sector待重映射的扇区/页读取失败但还没替换C6Offline_Uncorrectable无法纠正的错误页数量B1Wear_Leveling_Count磨损均衡计数能辅助判断盘的写入寿命消耗C7CRC_Error_Count传输线路CRC错误往往和线缆/接口有关这块盘的05已经涨到两位数C5和C6都出现了非零计数而且数值还在增长。C5非零尤其值得警惕它表示某些逻辑地址的数据已经处于“待重映射”状态主控尝试读这些地方时已经失败过只是还没找到备用块来替换或者备用块池已经紧张。这才是后面系统崩溃和文件拷不动的根源。然后做了一次底层读取测试不是去复制文件而是用 dd 直接读取设备节点sudo dd if/dev/sdb of/dev/null bs4M iflagdirect count100分别从盘的开头、中间、靠近坏块的区域各读一段观察速度。正常的消费级固态硬盘未损坏时持续读速应该在几百MB/s以上这块盘读开头区域时速度正常但一接近某个LBA范围速度突然掉到十几MB/s甚至完全停顿几十秒。到这一步故障性质就基本定性了这是介质层的物理坏块问题不是Windows里“文件系统损坏”能解释的。2. 原理拆解一块坏块怎么拖垮整个系统2.1 NAND颗粒的坏块不是“文件碎片”是物理损坏很多人对固态硬盘坏块有误解以为坏块就像机械硬盘的坏道一样是某个扇区“受伤了”数据可能还在只是读起来费劲。这个理解不太准确。NAND闪存的存储介质是一层浮栅晶体管以“页”为单位读写以“块”为单位擦除。每个页的擦写次数是有限的TLC颗粒通常只有几百到一千次左右的P/E寿命QLC更低。使用时间长了颗粒内部的氧化层被击穿、电荷保持能力下降某些页就会出现“读出来的数据无法通过ECC校验”的情况这就是物理坏页。坏块大致分两类。第一类是出厂坏块颗粒在生产时就被厂家标记好主控初始扫描时会避开。第二类是运行期增长坏块也就是使用过程中因为P/E擦写磨损、写干扰、读干扰、电荷泄漏等原因新出现的坏块。普通固态硬盘的主控会通过ECC纠错、坏块管理、磨损均衡这些机制去兜底但兜底的前提是备用块池还有容量主控固件还认为自己能把数据安全搬走。如果坏块数量超过了主控的容错能力情况就会失控。数据读取失败、写入失败、垃圾回收时搬移老数据失败各种问题会接踵而至。很多初期的坏块甚至不是永久损坏而是“读十次能成四次”这种半死不活的状态最折磨人因为主控尝试重试、尝试搬移数据整个盘的内部队列都会被堵住。2.2 FTL映射和备用块机制货架管理员模型把固态硬盘想象成一个巨大的仓库仓库里的货架就是闪存块每个货架上的箱子就是页。主控是仓库管理员手里拿着一张台账——这就是FTL映射表记录着“哪个逻辑地址对应哪个物理页”。正常情况下操作系统说要读某个逻辑地址管理员查台账去对应货架取箱子一切顺畅。坏块出现后管理员有两种处理方式如果备用货架还够就把这个货架的数据先读出来、写到备用货架上然后在台账上更新一条新记录旧货架标记为废弃这个过程就是重映射。但如果备用货架已经用完了或者数据本身已经读到一半就错误率爆表、物理上读不出完整内容管理员就只能反复去那个损毁货架翻找一遍遍试试不出来也不放弃。结果就是仓库门口排队的取货请求全部被堵住整个系统越来越慢直到操作系统忍无可忍宣告设备无响应。系统层面看到的现象就是IO请求超时。Windows的存储驱动会在超时后重试重试仍失败时触发蓝屏常见的就是KERNEL_DATA_INPAGE_ERROR、CRITICAL_PROCESS_DIED、WHEA_UNCORRECTABLE_ERROR。Linux下则通常表现为I/O error、blk_update_request报错、文件系统被强制重新挂载为只读严重的会直接panic。这不是操作系统“太脆弱”而是设备本身已经无法在协议保证的时间内完成最基本的IO操作。2.3 为什么全盘跟着变慢不只坏块那一个区域遭殃还有一个现象值得解释明明只有一个区域有坏块为什么整个盘都变卡复制任何文件都像老牛拉车一方面SSD主控是单任务或多任务有限的控制器架构。当一个逻辑地址反复读取失败时主控固件会持续尝试内部恢复流程包括调整读取电压阈值、多次读重试、甚至触发邻近块的搬运。这些操作会占用主控大量资源普通用户读盘时的请求被挤到后面等很久才轮到。另一方面闪存是“写前擦除”的介质持续写入时主控要不断做垃圾回收把旧数据搬去新块。坏块区域的错误让垃圾回收流程反复失败形成连锁堵塞。表现就是整盘速度雪崩式下降所有操作都卡顿但偶然某个区域又能正常读出来。客户说的“只能读取无法做其它任何操作”本质上就是这种状态。我在这个案例中自始至终没有尝试在Windows里做chkdsk因为在这种状态下做任何写操作都可能让主控疲于奔命进一步扩大损坏区域。3. 抢救第一步只读镜像不在原盘上做任何事3.1 这条规矩为什么必须死守数据修复的原则非常简单粗暴任何可能产生写入的操作都不能在原盘上执行。chkdsk /f会写盘格式化会写盘反复重启还是可能触发元数据更新。坏块区域的闪存单元本来已经不稳定再叠加主控在写操作时的搬移、重映射风险成倍增长。而且这里要提醒一句就算你没有主动执行写操作只要Windows正常启动系统可能也会向盘里写入日志、临时文件、页面文件等。所以从故障机器里拆盘之后最好直接接在另一台机器上不要挂载分区不要碰卷直接用底层工具做只读镜像。还有个容易踩的坑是量产工具。有人看到“固态硬盘坏块”就想到用量产工具低格、修复坏块这是数据恢复场景下的禁忌。量产和低格会让主控重建FTL映射表几乎必然导致原有逻辑地址到物理页的映射关系全部失效数据相当于被整体清空。我在不少案例里见过用户拿着量产工具把“还能救的盘”变成了一块完全空白的盘。如果是空盘想修坏块去量产那是另一回事但只要里面有你还想要的数据就绝对不要量产。3.2 ddrescue镜像参数怎么设为什么这么设这次选用的主力工具是GNU ddrescueLinux环境。这个工具和普通dd最大的区别在于它带日志文件可以从断点续跑而且对错误区域有智能跳过策略非常适配这种“大部分区域健康、少部分区域坏块”的硬盘。环境上我先把固态硬盘通过SATA直连方式接到备用电脑上没有用USB桥接。原因很简单USB转SATA桥接芯片是额外一层故障点很多桥接芯片在硬盘IO超时时会自己先失去响应甚至出现掉盘直连SATA虽然也会受主板电源管理影响但整体少一层转换稳定很多。如果笔记本没法直连只能用USB那就准备一根靠谱的线别用那种十几块钱的。镜像命令大概是这样的sudo smartctl -a /dev/sdb sudo ddrescue -d -f -r 3 -S 4096 --min-read-rate1M /dev/sdb /mnt/rescue/ssd_image.img /mnt/rescue/ssd_map.log参数含义逐个说明-d直接IO模式绕过Linux页缓存避免脏数据缓存影响镜像一致性。-f允许覆盖已存在的输出文件。-r 3读取失败时的重试次数。第一次跑全盘镜像时重试次数别设太大试一次失败就跳过快速建出“大部分数据 坏块分布图”后面再精细重试。-S 4096遇到错误后跳出4MB再继续读。这个设计非常关键坏块往往一小片但读取坏块附近的区域会非常耗时如果一步一卡整个镜像要跑几天几夜。跳过一段再接续等于先把好数据拿到手。--min-read-rate1M如果实际读速低于1MB/sddrescue会认为这一步不可靠主动跳过避免在一个错误区卡死。输出文件和日志文件都放在另一块健康盘上千万别放在源盘自己身上。第一阶段的逻辑是快扫跑完之后查看map.logsudo ddrescue -d -r 1 /dev/sdb /mnt/rescue/ssd_image.img /mnt/rescue/ssd_map.log不加-S不做大跳过专门回头处理之前标记为错误或未读取的区域重试次数也调低。第二阶段跑完绝大多数还能抢救的小块数据都会被捞出来。如果时间充裕我习惯再做一遍按反向顺序的重试因为有些控制器的坏块表现和方向有关正向读不出来反向能读出来也是常有的事。这次案例里整块盘的镜像阶段花了四个多小时总读取量里只有一小段长时间卡顿。map.log里显示最终还有大约1.8GB的数据彻底无法读出分布很零散主要集中在当时发生蓝屏的那个区域附近。好在数据库文件的大部分数据不在这片区域内。3.3 镜像过程中必然会遇到的乱子做镜像的时候最怕的不是读不出来而是盘在过程当中直接掉线。ddrescue日志的存在就是为了解决这个问题设备断了重启机器、重新插盘再执行同一条命令它会根据map.log判断从哪里继续不会从头再来。我还遇到过一次盘体过热导致的掉线。固态硬盘持续高强度读取坏块区域时主控和颗粒发热很快机箱散热不好就容易掉盘。处理方式是给它加了个风扇对着吹把盘从机箱内部的位置挪到有风道的区域之后掉线频率明显下降。这里多说一句固态硬盘不要学机械硬盘那样拍打敲击本来就不是机械结构拍它没用还可能造成电路板接触不良。镜像完成后我习惯把map.log和镜像文件的哈希值记在案方便后面验证副本完整性。虽然DDRescue镜像因为坏块原因无法和源盘完全一致但最后得到的镜像文件就是最完整的物理副本后面的所有修复动作都应该基于这个镜像而不是继续动原盘。4. 镜像之后的数据库二次抢救4.1 文件系统层先在副本上把“外部伤”处理好镜像文件拿到手之后第一步不是直接去附加数据库而是先把文件系统层面能够读取的文件完整提取出来。因为即使底层坏块存在文件系统元数据损坏往往也是局部的大部分数据文件依然可以被读取。这次客户使用的是Windows NTFS分区。我在Linux里通过losetup把镜像关联为回环设备然后只读挂载NTFS分区尝试把财务数据库的MDF和LDF文件复制出来。实际操作时发现D盘根目录能列出但是读取数据库文件夹里的几个大文件时依然会卡顿Linux内核会反复报告IO错误复制到一半进程被挂住。这种情况其实就是镜像中标记为错误区域的映射还在影响文件读取。处理办法是在Linux下先用ntfsfix之类的工具做检查不ntfsfix是尝试修复NTFS内部结构的对这种介质级的坏块用处不大而且一个误操作还会增加风险。更稳妥的做法是先把整个镜像挂载后用ddrescue的“跳过坏区”思路导出单个文件或者直接用工具比如R-Studio的Linux版本打开镜像按文件提取模式把MDF、LDF捞出来。R-Studio对NTFS支持很好能够跳过损坏区域尽可能输出完整文件。这次我就是用它直接从镜像里把数据库文件拖到了另一块健康盘上整个过程花了近两小时因为几个坏块刚好落在MDF数据范围内的几个页上。文件复制出来之后在健康盘上对数据库副本做一次文件系统级验证是必要的。如果是Windows环境可以用chkdsk /f但注意一定要在副本上执行不是原盘也不是镜像本身。chkdsk在副本上即使写坏内容也无所谓因为硬盘数据还能重新从镜像里提取。4.2 数据库引擎的“页级损伤”判定文件拷贝能完成不代表数据库能正常打开。数据库文件是高度结构化的大文件内部按固定大小的页组织。损坏只要落在任何一个关键页上引擎启动时都会报错。这次客户使用的是SQL Server启动附加操作时报了比较典型的错误The header for file DateBase.mdf is corrupt. Page (1:45789) verification failed. Msg 824, Level 24, State 2824这个错误意味着读取页面的数据后校验和不一致或者页头结构不合法。这正好印证了之前的判断坏块导致页内容物理损坏但坏块范围很零散很多页可能只有某一小段数据不对而整页依然能被读出来。这个时候最忌讳的反应是“完了数据没了”。SQL Server本身提供了基于备份的恢复机制但客户没有备份——这几乎是数据修复案例里的标准开场。只能在副本上尝试一致性检查和修复。我先把MDF和LDF复制了一份作为修复副本然后执行ALTER DATABASE FinancialDB SET EMERGENCY; GO DBCC CHECKDB (FinancialDB) WITH NO_INFOMSGS, ALL_ERRORMSGS;EMERGENCY模式允许数据库以只读状态打开即使物理结构有问题也不会启动正常恢复流程。DBCC CHECKDB用来明确哪些页损坏、哪些页可以通过重建索引等方式修复。确认具体问题后我再次复制副本才在第二个副本上跑DBCC CHECKDB (FinancialDB) WITH REPAIR_REBUILD。这样做的原因是REPAIR操作本身可能对页内容进行修改甚至丢弃数据如果跑了REPAIR发现效果不好至少还有一份未修复的完整副本可以回到原点。这种“副本加副本”的备份纪律在整个修复流程里是最重要的经验之一。4.3 引擎修不动时还能靠页级扫描捞数据如果CHECKDB之后依然无法附加或者修复结果里大量核心表数据仍然缺失就要考虑更低层级的抢救方式直接扫描数据库数据文件识别页头特征把能够读到的页重新组装起来然后从中提取可读数据。SQL Server数据页的页头在每一页开头都有固定标记包含PageID、文件ID、对象ID、LSN、槽数等信息。使用类似数据库修复工具比如dbx数据库工具或专门的数据页扫描工具读取MDF文件按页号扫描出所有尚未受损的页再交给数据库引擎去解析记录。这些工具的原理其实就是“把损坏文件视为一批8KB块保留结构完整的块放弃无法校验的块”效果不如完整恢复但在没有备份的情况下往往能再抢救回大量表数据尤其是那些存放在健康页上的历史数据。这个阶段的操作非常耗时而且结果高度依赖坏块的位置分布。这次案例中数据库核心账务表的大部分页都避开了坏块区域最后通过页级解析和导出脚本拿回了大约九成以上的业务记录。不过这个结果也只代表这次运气尚可换一个坏块位置不同、密集度更高的盘修复比例可能就差很多。在这一步也要留意MySQL InnoDB、达梦数据库等不同数据库的页结构和校验机制不同。比如InnoDB可以通过innodb_force_recovery参数逐级尝试启动从1到6每次级别提升都代表跳过更多内部校验直到允许只读方式把表数据用mysqldump导出来。但它的强制恢复级别6会让共享表空间进入只读模式并且可能导致无法导出部分二级索引需要权衡取舍。无论什么引擎核心原则一致只操作副本避免在原盘和原始文件上写任何一比特。5. 复盘与预防坏块从来不是突然出现的5.1 这次案例的时间线和决策点事后复盘可以看到整个故障拉长了来看是一条很清晰的恶化链条时间点现象当时最该做的事大约三周前系统偶尔卡顿SMART中C5出现非零值立即备份数据库安排换盘大约一周前复制大文件开始偶尔卡死开机变慢停止业务写入做全盘镜像故障当天蓝屏几次系统能进但D盘数据库复制卡死拆盘只读镜像不要再做任何写操作客户实际选择多次强制重启跑过chkdsk反复试复制让坏块区域反复受力损伤扩散最可惜的其实是前两个决策点。SMART里C5已经报警的盘还继续作为生产文件服务器的系统盘和数据库盘用了快三周。很多普通用户不知道C5的含义但企业环境中监控脚本应该早就在告警了。如果当时立刻做一次全量备份后面所有这些事都不会发生。事故中客户还犯了一个很常见但代价不小的错多次强制重启和反复试复制。每重启一次系统引导和日志写入都会落在已经脆弱的分区上每试复制一次都会让主控在坏块区域反复重试。不是每次重试都必然扩大损伤但风险完全不可控而且没有任何收益。正确动作应该是第一时间停用把盘交给数据修复人员做镜像。5.2 面向数据库场景的SSD预防清单如果看完这篇文章只记住一件事那就是数据库文件所在的主机和硬盘必须配置SMART监控和自动备份两者缺一不可。措施具体做法解决的问题SMART监控告警Windows/Linux下配置smartd或计划任务定时读取SMARTC5/C6/05出现非零即告警在坏块扩大前发现介质隐患数据库自动备份每日全备加日志备份定期做恢复演练不只看备份是否生成文件级丢失时能够通过正常恢复流程解决生产库选型数据库盘优先使用企业级SSD不选消费级确保盘上有足够OP预留空间和掉电保护降低坏块发生概率提升主控容错和掉电安全存储架构冗余关键库至少做RAID1或者双副本但切记RAID不是备份单盘故障不再等于业务中断备用盘预案机器里常备一块健康盘一旦SMART告警直接在线镜像并切换缩短故障窗口期减少客户决策成本这套清单对普通办公电脑同样适用。很多人觉得SMART是服务器才看的指标但实际上随便一块固态硬盘都内置这些健康数据Windows下用CrystalDiskInfo就能看到。看到05和C5出现黄块或红块数据就处于风险中下一个蓝屏可能就在几天或几周后差别只在于运气。5.3 修复类操作的最后一条原则数据修复做得多了最深的体会是修复手段越来复杂成功率反而越依赖“是否早停手”。越早拆盘、越早做镜像、越少折腾越有机会拿到完整镜像反之反复在原盘上尝试各种工具每增加一次写入和重试都等于把客户数据的存活性往下降一档。这个案例里能最终拿回大部分数据库数据最大的功臣不是我用的那些工具而是客户运气好坏块集中在非核心区域但如果再来一次我不会指望同样运气。结尾这次案例结束之后我给自己这边又重新强调了一遍老规矩任何检修性质的命令先确认它不是写操作任何数据库修复操作先在副本上执行任何坏块告警都按最高优先级处理。普通用户可能一辈子遇不到一次“数据库拷不出来”这种故障但只要遇到一次前面这些准备和原则就能决定业务数据是完整回归还是只能从历史归档里去拼凑。最后还是那句老话固态硬盘的坏块不是突然冒出来的它在SMART里早就喊过很多遍救命了。
阅读完成 · 觉得有帮助?
咨询建站