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

作者:神奇的程序员日期:2025/12/17

999

前言

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

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

iPhone镜像 2025-12-17 21.18.12

定位问题

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

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

翻日志

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

1nvme nvme0: I/O timeout, aborting
2

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

找到原因

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

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

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

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

VM无法启动

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

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

2222

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

从备份中还原

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

image-20251217224605905

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

1_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
2

image-20251217225055348

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

1progress 99% (read 318901321728 bytes, duration 722 sec) 
2
3_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
4

现在狠狠的打脸了,我手里目前只有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目录,执行下述命令,忽略校验,强行解压。

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

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

挂载RAW磁盘

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

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

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

1losetup -a
2lsblk
3

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

image-20251217234910684

挂载分区

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

1mkdir -p /mnt/rescue
2

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

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

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

image-20251217235136772

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

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

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

1ls /mnt/rescue
2

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

image-20251217235434358

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

写在最后

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

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

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


从已损坏的备份中拯救数据》 是转载文章,点击查看原文


相关推荐


苹果ios手机ipad安装配置ish终端shell工具
无痕melody2025/12/9

简介 官方介绍 iSH 是一个运行在 iOS 上的 Linux Shell,用来在ARM架构的 iOS 设备上模拟 X86 架构。也就是说不光是 IPad 可以安装,IPhone 上也可以安装运行 iSH,直接在 IOS 设备上运行 Linux 环境,而且免费! 如果你正在使用的电脑是 Mac,那么可以把 iSH 比作你电脑上面的终端。 iSH 官方地址 安装 AppStore里搜索ish或手机打开链接 配置 基本操作 操作按钮 2. 这个按钮相当于电脑上的 Tab 键,用于命令


用户数据报协议(UDP)详解
CodePracticer2025/11/28

一、传输层协议UDP 1. 理解UDP协议 我们以前说过,0-1023端口号是知名端口号,它们是与指定的协议进行关联的,那么我们如何证明呢? 在指定目录下就可以查找到这些协议的端口号了(/etc/services)。 这里以两个例子来说明情况。 前面我们也说过协议就是一种约定,本质就是结构体。今天我们来正式认识一下UDP协议。 可以看到UDP协议的宽度是32位,源端口号和目的端口号分别占16位,UDP协议的报头是8字节。 前面我们说过,源主机的数据发送给目标主机需要先经历封装在解包的过程,


Vue 实例挂载的过程是怎样的?
全栈陈序员2025/12/25

一、整体流程概览 当我们执行 new Vue({ ... }) 时,Vue 会经历 初始化 → 编译模板 → 挂载 DOM 三个阶段。整个过程由 _init 方法驱动,最终通过 $mount 完成视图渲染。 核心路径: new Vue() → _init() → initState() → $mount() → mountComponent() → _render() → _update() → 真实 DOM 二、详细步骤解析 1. 构造函数与 _init 初始化 源码位


Go 项目结构总是写乱?这个 50 行代码的 Demo 教你标准姿势
Java小成2026/1/4

1. 场景复现:那个让我头疼的时刻 去年,我接手了一个"祖传" Go 项目。打开代码仓库的那一刻,我整个人都不好了——所有代码都塞在一个 main.go 里,足足 3000 多行。想加个功能?先花半小时找代码在哪。想写个单元测试?抱歉,函数全是私有的,而且互相耦合,根本没法单独测。 我当时就在想:如果当初写这个项目的人,能从第一天就用一个规范的结构,后面的人得少掉多少头发? 后来我开始研究 Go 官方和社区推荐的项目布局,发现其实规则很简单,但很多人就是不知道。于是我写了这个 50 行代码的小


Ansible自动化(十五):加解密详解
cly12026/1/12

Ansible Vault 是 Ansible 提供的一套用于保护敏感数据的机制,可以对各类配置文件进行加密,防止敏感信息(如密码、私钥、API 密钥等)以明文形式暴露在代码仓库或配置文件中。 一、为什么需要 Ansible 加密? 场景说明: Playbook 中包含数据库密码、API Token、SSH 私钥等敏感信息Inventory(主机清单)中直接写入了连接密码(如 ansible_password)变量文件(vars/main.yml)中包含机密配置 ✅ Ansible Vaul


筑牢金融底座:企业级区块链全球化数据库架构设计白皮书
China_Yanhy2026/1/20

📖 前言:Web3 业务的双重账本 在 Web3 业务中,区块链(AMB)是不可篡改的“链上真理”,而关系型数据库(RDS/Aurora)则是承载用户资产、撮合逻辑和KYC信息的“链下业务核心”。对于追求全球化的高频交易项目,数据库的架构设计必须解决两个核心矛盾:跨国访问的物理延迟 与 资金数据的一致性。 第一部分:旗舰方案 —— Amazon Aurora Global Database (深度解析) 这是针对跨国交易所(如币安、Coinbase 模式)的首选架构。 1. 核心架构


Spring注解秘籍:优雅地使用 @RequestHeader
独泪了无痕2026/1/29

前言   在 Spring Boot 开发中,HTTP 请求头(Header)是客户端和服务器之间传递元数据的重要方式。通过请求头,客户端可以传递认证信息、内容类型、语言偏好等数据。Spring Boot 提供了 @RequestHeader 注解,用于方便地从 HTTP 请求头中提取数据。本文将详细介绍 @RequestHeader 注解的使用方法,包括基本用法、默认值处理、多值头处理以及实际应用场景。 一、注解定义与核心属性 1.1 @RequestHeader 是什么   在构建现代 W


Skills.lc 是什么?为什么我会做(用)这个站
HBLOG2026/2/7

在折腾 AI Agent、CLI 工具和各种自动化脚本的过程中,我一直有一个很现实的问题: 好的 skill / workflow 到底该放哪?怎么复用? Prompt 太零散,放在 Notion、Gist、README 里,时间一长就找不到; 不同项目里反复复制粘贴,又很难维护; 看到 GitHub 上有人写了不错的 skill,也不知道怎么发现、怎么用。 Skills.lc 就是在这样的背景下出现的。 它本质上不是“又一个 AI 平台”,而是一个 技能索引与分发站点,专门用来收集、整理


我又开发了一款桌面APP,功能强大
500佰2026/2/16

最近这段时间,开始沉迷一件事,在抖音录制我AI写代码、做实战开发的视频,用opencode / claudecode / Agent skills 等大模型进行AI项目开发,耗时7个晚上,最晚的一次,写到了夜间3点,录制了5个视频,开发消耗AI大模型token 数1500左右。 这次我开发了一款桌面录屏APP,名字叫做focusME,目前已经开发完成,可一键安装在我们的桌面,接下来讲解一下整个开发过程。 开发成果 开发过程 前面我用opencode里面Agent skills去制定产品


Django 应用 OOM(Out of Memory)故障的定位思路和排查方法
哈里谢顿2026/2/24

二、定位思路总览 1. 确认现象 → 2. 内存分析 → 3. 代码审查 → 4. 复现验证 → 5. 修复优化 ↑___________________________________________________________| 三、详细排查步骤 第一步:确认内存使用趋势 1.1 系统层面监控 # 查看进程内存(RSS:实际物理内存,VSZ:虚拟内存) ps aux --sort=-%mem | head -20 # 实时观察 watch -n 1 'ps -p <PID>

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客