从已损坏的备份中拯救数据 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
MagicCoder
V2EX    程序员

从已损坏的备份中拯救数据

  •  
  •   MagicCoder 4 天前 1028 次点击

    999

    前言

    12 月 15 号早上,一觉醒来,拿起手机看到我的邮箱收到了内网服务无法访问的告警邮件,本以为只是简单的服务卡死,将服务器重启后就去上班了。

    后来,陆续有好友联系我说网站挂了。

    iPhone 镜像 2025-12-17 21.18.12

    定位问题

    晚上下班回家后,尝试将电脑断电重启,发现 pve 只能存活 2 分钟左右,然后整个系统卡死,无法进行任何操作。首先,我想到的是:会不会某个 vm 虚拟机或者 ct 容器影响到宿主机了。

    因为系统只能存活几分钟,在执行禁用操作的时候,强制重启了好几次服务器。当所有的服务都停止启动后,卡死的问题依旧存在。

    翻日志

    没辙了,这已经不是简单的软件问题了,只好翻日志,看报错信息了。

    nvme nvme0: I/O timeout, aborting 

    如上所示,日志中出现了好几条 I/O 超时消息,顿感不妙,该不会硬盘坏了吧....

    找到原因

    找了一圈方案,大部分都说这个错误是 nvme 硬盘的通病,他有一个省电模式,在某些硬件+内核的组合下会导致控制器假死。

    解决方案也很简单,找到 GRUB 的配置文件,关闭他的自动睡眠和省电模式,在 pve 中这个文件位于/etc/default/grub,打开这个文件后,找到 GRUB_CMDLINE_LINUX_DEFAULT 属性,添加两个值:

    • nvme_core.default_ps_max_latency_us=0
    • pcie_aspm=off
    GRUB_CMDLINE_LINUX_DEFAULT="quiet nvme_core.default_ps_max_latency_us=0 pcie_aspm=off" 

    保存文件后,执行:update-grub 命令,随后重启整个 pve 主机。

    VM 无法启动

    pve 启动卡死的问题解决了,现在又有了新的问题。启动我那台跑了整个网站服务的 vm 虚拟机时,出现了如下所示的错误:

    mount: mounting /dev/sda3 /dev/sda3 on /sysroot failed: No error information Mounting root failed. initramfs emergency recovery shell launched. 

    2222

    这下坏事了,linux 的根分区无法挂载了,应该是刚才频繁的卡死,我不断的启动 pve ,容器不停的启动、强制终止导致盘里这块区域的数据受损了,处于半死不活状态了。

    从备份中还原

    幸好我之前设置了 vm 容器的整机备份,连续备份并存储 3 天,全部放在了内网另一台机器的机械硬盘中,通过网络挂载到 pve 上的。

    image-20251217224605905

    本以为一切都会很顺利,还原的时候出现了错误,zstd 解码时,发现压缩块损坏,导致还原失败。

    _15-03_00_03.vma.zst : Decoding error (36) : Corrupted block detected vma: restore failed - short vma extent (2801635 < 3801600) /bin/bash: line 1: 2131 Exit 1 zstd -q -d -c /mnt/pve/nfs_usb_4t/dump/vzdump-qemu-100-2025_12_15-03_00_03.vma.zst 

    image-20251217225055348

    于是,我又尝试了另外两个备份,结果都无法还原,全部都是相同的错误。当初做备份的时候,想着我都整机备份了,而且保存了 3 天的备份,总不可能三个全坏吧。

    progress 99% (read 318901321728 bytes, duration 722 sec) _13-03_00_02.vma.zst : Decoding error (36) : Restored data doesn't match checksum progress 100% (read 322122547200 bytes, duration 755 sec) total bytes read 322122547200, sparse bytes 196604751872 (61%) space reduction due to 4K zero blocks 0.414% temporary volume 'local:121/vm-121-disk-0.qcow2' sucessfuly removed no lock found trying to remove 'create' lock error before or during data restore, some or all disks were not completely restored. VM 121 state is NOT cleaned up. TASK ERROR: command 'set -o pipefail && zstd -q -d -c /mnt/pve/nfs_usb_4t/dump/vzdump-qemu-100-2025_12_13-03_00_02.vma.zst | vma extract -v -r /var/tmp/vzdumptmp10764.fifo - /var/tmp/vzdumptmp10764' failed: exit code 1 

    现在狠狠的打脸了,我手里目前只有2023 年 11 月迁移技术栈时,那份 docker compose 的初始数据。相当于我丢失了 2 年的数据,这我是不能接受的。

    吧我累了- 吧我累了 updated their profile picture.

    折腾到这里,我一看时间,已经凌晨 1:30 了,明天还要上班,带着郁闷的心情去睡觉了。

    强行提取数据

    睡醒后,不愿接受这个现实,想到改造的那个练习英语单词的开源项目,这 1 年多时间下来,平均的日活跃人数已经有 40 多个了,数据库存储 8w 多条单词数据了,太难受了

    实在是想不到什么好法子了,只好在 v 站和朋友圈都发了求助帖

    IMG_0911

    找到方案

    在此,感谢 v 站老哥DylanC,给了我一组关键词。

    image-20251217231654428

    晚上回家后,开始找资料,问 GPT ,经过一番折腾总算是把数据提取出来了。

    跳过校验

    从上述的错误日志中能看出,我在还原的时候已经读了 99%的数据了,只是文件的完整性校验过不了,我的 vm 虚拟机里一整个全是 docker compose 编排的服务( mysql 、redis 、java 、nginx 等),理论上是比较好找回的。

    pve 的定时备份采用的是 vzdump 服务,备份出来的产物是.vma.zst格式的,他的本质是:

    • zstd 压缩
    • 内部是 vma 归档
    • 包含:
      • qemu-server.conf
      • disk-drive-scsi0.raw

    知道这些后,我们先把网络存储中的备份文件拷贝到 pve 主机的/var/lib/vz/dump目录,执行下述命令,忽略校验,强行解压。

    zstd -d -c --no-check vzdump-qemu-100-2025_12_13-03_00_02.vma.zst \ | vma extract -v - ./extract.partial 

    等待一段时间后,程序执行结束,你会发现报错依然存在,但是这不影响已经读取的数据,cd 到./extract.partial 目录,你应该能看到xxx.confxxx.raw文件,然后看下.raw 后缀文件的空间占用,只要不是太小(占用<1GB),那么这份数据基本是没问题的,磁盘的 RAW 文件也算是被解出来了。

    挂载 RAW 磁盘

    为了防止数据遭到破坏,我们需要做只读挂载,命令如下:

    losetup -fP /var/lib/vz/dump/extract.partial/disk-drive-scsi0.raw 

    然后,执行命令查看结果。

    losetup -a lsblk 

    执行后,应该能看到类似loop0loop0p1loop0p2这样的数据,找到那块空间跟你在 extract.partial 目录下看到的空间差不多大小的盘。

    image-20251217234910684

    挂载分区

    首先,我们通过下述命令来创建一个挂载点:

    mkdir -p /mnt/rescue 

    随后,尝试挂载分区( loop0p1 、loop0p2....等),找你的根分区,如果你运气好,p1 就挂载成功了,那就不需要挂载其他的了。

    我的根分区是 p3 ,那么我挂载 p3 即可。

    mount -o ro,norecovery /dev/loop0p3 /mnt/rescue 

    image-20251217235136772

    如果失败的话,代表它不是文件系统,需要继续尝试挂载其他分区,直到成功为止。

    umount /mnt/rescue 2>/dev/null mount -o ro,norecovery /dev/loop0p2 /mnt/rescue 

    最后,查看挂载点里是否有你的数据。

    ls /mnt/rescue 

    不出意外的话,你应该能看到类似下图所示的内容。

    image-20251217235434358

    文件成功恢复,接下来要做的就是把这些文件拷贝到安全的地方即可。

    写在最后

    至此,文章就分享完毕了。

    我是神奇的程序员,一位前端开发工程师。

    如果你对我感兴趣,请移步我的个人网站,进一步了解。

    第 1 条附言    3 天前
    12 条回复    2025-12-18 18:23:08 +08:00
    WizardLeo
        1
    WizardLeo  
       4 天前
    使用
    nvme_core.default_ps_max_latency_us=0
    pcie_aspm=off
    这两条命令不一定能解决问题的。
    我用的 unraid 系统+三星 980pro ssd 遇到了一样的主控死机+文件系统保护性关闭问题,使用各种解决方案包括但不限于加上前面那两条命令、关闭主板全部省电功能、更换 ssd 插槽、更新 ssd 固件+主板 bios+更新 linux 内核到最新版等,问题都没有解决。
    最后把这块 ssd 和笔记本上的闪迪至尊高速对换了一下,问题解决了。服务器上 ssd 不再假死,笔记本上的 980pro 也在没有出过问题。
    所以这大概率就是一个 ssd 固件和 linux 的兼容性问题,op 可以注意一下以后还会不会再发生。
    sillydaddy
        2
    sillydaddy  
       3 天前
    似乎没看到 3 个备份都损坏的原因,楼主有没有查一下呢?同时损坏感觉很奇怪啊。
    xclimbing
        3
    xclimbing  
       3 天前
    对呀,我更关注备份文件出错的原因,而且,全部备份文件都有错,这肯定是哪里出了问题。
    Ketteiron
        4
    Ketteiron  
       3 天前
    大概率内存出问题了,基本上 99%的文件静默错误来源于内存比特纠正失败。
    生成的压缩包带上了错误的校验和,那肯定会失败,一开始就不存在正确的数据。再一次证明了 ECC 内存的重要性。
    MagicCoder
        5
    MagicCoder  
    OP
       3 天前
    @xclimbing
    @sillydaddy
    我感觉问题出在通过 nfs 协议向这块内网的硬盘写数据过程中,网络抖动丢包导致的内容写入不完整。他这个备份是直接传输数据到那块盘的。

    我感觉正确的姿势应该是在 pve 的主硬盘做备份,生成 zst 格式的包后,我再通过 nfs 协议传输到内网其他机器的的硬盘上,这样就不会有问题。
    MagicCoder
        6
    MagicCoder  
    OP
       3 天前
    @Ketteiron 这块硬盘是 nfs 协议挂载的内网其他机器的盘,只要存在网络波动,就会导致丢包。大概率是这个原因
    MagicCoder
        7
    MagicCoder  
    OP
       3 天前
    @WizardLeo 嗯嗯 我再观察一阵看看,要是还出现假死问题,我也得换硬件了。
    panai
        8
    panai  
       3 天前
    我也有一个类似的问题,不知道能不能按照你这个步骤修复?
    当时用 pve 装了一个黑群晖,添加了一块硬盘(不是直通的,和 pve 用的是一块盘)。后来磁盘损坏了,我就按照网上的方案把里面虚拟机编号开头的文件都复制走了,然后按教程修复过,不过只能看到群辉的分区,但是之前磁盘路径/volume1 里面看不到任何内容。
    Ketteiron
        9
    Ketteiron  
       3 天前
    不太可能是网络波动导致的,nfs 默认使用 tcp ,tcp 是解决网络不可靠的传输协议,要么完整地传输过去,要么抛出一个错误提示传输失败。
    "Corrupted block detected"
    "Restored data doesn't match checksum"
    这已经说明了文件在存储前/后发生了变更,我是觉得你的内存或者硬盘至少坏了一个,另外系统卡死大概率是相同问题,全部排查一遍吧。
    MagicCoder
        10
    MagicCoder  
    OP
       3 天前
    @Ketteiron 好吧,那我估计硬盘可能出问题了
    xclimbing
        11
    xclimbing  
       3 天前
    @MagicCoder 那你就本地备份一个再测试一下数据完整性呗。如果本地备份没问题,那么问题要么出在网络(nfs )上,要么就出在目标硬盘上。
    birdvdsk
        12
    birdvdsk  
       3 天前 via Android
    备份损坏,是不是因为文件系统一致性问题,看了一下 vzdump 文档,提到虚拟机备份有三种模式,若是未能保证数据一致性,会导致文件系统错误。
    https://pve.proxmox.com/pve-docs/vzdump.1.html#_backup_modes
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     968 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 18:16 PVG 02:16 LAX 10:16 JFK 13:16
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86