![从单个旧镜像恢复/导入 ZFS 池](https://linux22.com/image/166583/%E4%BB%8E%E5%8D%95%E4%B8%AA%E6%97%A7%E9%95%9C%E5%83%8F%E6%81%A2%E5%A4%8D%2F%E5%AF%BC%E5%85%A5%20ZFS%20%E6%B1%A0.png)
前几天,我在处理 ZFS 池时犯了几个严重错误(同时误读了一些修复错误的在线建议),并且意外地“创建”了一个名为 的现有 2 驱动器镜像池backup
。 (是的,我-f
在它抱怨后使用了该选项。现在我知道再也不会这样做了。)
无论如何,几个月前我碰巧从同一个池中取出了第三个镜像驱动器,因为它已经老化了,我不想等到它开始出现故障。所以,我想我可以交换这个驱动器并用它来恢复池。 (我只是错过了过去几个月的备份,这主要是这个池的用途。)
但是,我似乎无法使用这个旧驱动器导入池。起初,我认为这可能与backup
我意外创建(然后销毁)的新池的名称冲突有关。但即使尝试通过 GUID 导入,我也什么也得不到。
这是 zdb -l /dev/sdb1 (这是第三个驱动器)的输出
------------------------------------
LABEL 0
------------------------------------
version: 5000
name: 'backup'
state: 0
txg: 0
pool_guid: 3936176493905234028
errata: 0
hostid: 8323329
hostname: [omitted]
top_guid: 14695910886267065742
guid: 17986383713788026938
vdev_children: 1
vdev_tree:
type: 'mirror'
id: 0
guid: 14695910886267065742
whole_disk: 0
metaslab_array: 34
metaslab_shift: 33
ashift: 12
asize: 1000197324800
is_log: 0
create_txg: 4
children[0]:
type: 'disk'
id: 0
guid: 17914838236907067293
path: '/dev/sdd1'
whole_disk: 0
DTL: 143
create_txg: 4
children[1]:
type: 'disk'
id: 1
guid: 17986383713788026938
path: '/dev/sdb1'
whole_disk: 0
DTL: 141
children[2]:
type: 'disk'
id: 2
guid: 1683783279473519399
path: '/dev/sdc1'
whole_disk: 0
DTL: 145
create_txg: 4
features_for_read:
com.delphix:hole_birth
com.delphix:embedded_data
create_txg: 0
labels = 0 1 2 3
因此,根据 zdb 的说法,驱动器和驱动器上的池数据似乎完好无损。但是,导入池(即使使用-f
和/或-F
)只会出现“无法导入...没有这样的池可用”错误。我也尝试使用上述信息中的各种 GUID(因为我不确定 GUID 是否是相关的),但这些命令(例如zpool import 3936176493905234028
)都没有得到除“没有此类可用池”消息之外的任何内容。
自从删除该驱动器后,我已经安装了新版本的 Linux 操作系统,因此我认为使用zpool.cache
我设法从旧操作系统恢复的旧文件可能会有所作为。但该命令 zpool import -c zpool.cache
只是给出:
pool: backup
id: 3936176493905234028
state: UNAVAIL
status: One or more devices contains corrupted data.
action: The pool cannot be imported due to damaged devices or data.
see: http://zfsonlinux.org/msg/ZFS-8000-5E
config:
backup UNAVAIL insufficient replicas
mirror-0 UNAVAIL insufficient replicas
sdd1 FAULTED corrupted data
sdc1 FAULTED corrupted data
这在某种程度上是可以预料的。这些是我的创建命令覆盖池的两个磁盘。然而,sdb1 没有被列为潜在的驱动器——可能是因为我在取出磁盘后将其从池中删除了。尽管如此,我认为我在 sdb1 上有一份完整的旧镜像数据副本,zdb 也同意。为什么不导入呢?
还有什么建议可以尝试吗?要运行其他诊断命令吗?
注意:我尝试过在服务器故障中询问这个问题(有关我的情况的更多详细信息,请参阅链接),但我没有得到任何反馈,并意识到特定的 Linux 实现对于弄清楚如何解决此问题可能很重要。我真诚地感谢任何意见或建议。
更新:我想我可能已经发现了问题。我以为在发出detach
命令之前我已经移除了备用驱动器。事实上,我仍然看到标签信息(当其他在线来源似乎表明detach
破坏池元数据时)似乎证实了这一点。我注意到我可以简单地键入zdb -l backup
并获取标签信息(并使用 获取 uberblock 信息-u
),因此即使没有明确指向设备,zfs 似乎也能看到池。它只是出于某种原因不想导入它。
然而,我不再确定状态detach
。我偶然发现这个旧线程关于从分离的镜像恢复 ZFS 池,它隐晦地引用了txg
零值。其他地方也提到超级区块被归零于detach
.
backup
好吧,我的池的 uberblock确实列出了txg = 0
(而我在其他地方拥有的活动 zpool 在该字段中有大量数字,而不是零)。虽然存在一个现有的超级区块,但只有一个,其他区块都backup
被列为“无效”。不幸的是,我似乎无法zdb
在网上轻松找到任何有关任何内容的文档。
我认为这意味着备用的第三个驱动器已分离?有人能证实我的解释吗?但是,如果驱动器数据完好无损,有什么方法可以恢复吗?尽管网上的一些建议表明如果不重新同步,分离的镜像将无法恢复,我上面链接的线程具有 Solaris 代码,该代码似乎执行了一个相当简单的函数来欺骗标签,使其认为 uberblock 没有问题。进一步探索发现我该实用程序的更新 Solaris 版本仅从三年前开始。
假设我的理解是正确的并且我的第三个镜像已分离,我可以在 Linux 中尝试类似的 uberblock 标签修复吗?我尝试重写 Solaris 代码以便将其移植到 Linux 是唯一的选择吗? (我不确定我是否能胜任。)
老实说,鉴于网上多次引用此类场景,我对 ZFS 缺乏合理的数据恢复工具感到惊讶。它似乎终于有一些选择了用于常见问题的基本数据恢复(包括恢复被命令覆盖的池的可能性create
;这似乎对我不起作用),但除了这个用于 Solaris 的一次性脚本之外,我没有看到任何用于处理分离设备的内容。令人沮丧的是,至少有十几个原因导致 ZFS 池可能无法导入(有时是一些可以轻松恢复的琐碎事情),而且几乎没有故障排除、正确的错误代码或文档。
再次强调,任何帮助、想法或建议将不胜感激。 即使有人可以推荐一个更好的地方来询问这个问题,我也非常感激。
更新2:也有可能该设备只是offline
按照我的想法放置的。我读过各种帖子,说离线设备最终也可能无法作为单个镜像导入。由于 ZFS 的元数据和 zdb 输出记录很少,我真的不知道如何在不阅读数千行源代码的情况下确定 uberblock 和标签数据的含义。
答案1
好吧,我已经很接近了,并且认为我已经找到了康复之路。由于我还没有收到其他人的建议,所以我将发布到目前为止我学到的东西。
概括:
- 有一个未维护的、非官方支持的
labelfix
实用程序,用于修复某些类型的损坏(和脱机/分离)ZFS 卷上的标签,可用于使不可导入的池变得可导入。 - 在执行任何操作之前,请务必克隆旧的备用设备,并且仅对克隆进行操作。
- 如果您遇到问题中所述的情况,有两个同名的池(由于错误
create
或其他错误),请确保仅插入要恢复的特定池的设备。 - 此外,删除可能曾经与您要恢复的池关联但出现故障的任何设备。 (即使您认为您已经完全破坏了任何其他池并断开了这些设备的关联,这也适用。恢复工具将尝试将旧池的碎片拼凑在一起,并可能读取旧标签/超级块以以不可预测的方式组合设备和数据。)
更多细节:
似乎有一种方法可以从 Linux 上的 zpool 恢复脱机和分离的驱动器。用户 jjwhitney 创建了labelfix 实用程序的端口我在问题中提到,最初由 Jeff Bonwick(ZFS 的发明者)撰写近12年前。由于我无法理解的原因,该实用程序尚未合并到 ZFS 版本中,尽管它允许在导入因无效标签而因多种原因失败时恢复完整池的数据。 (关于这个问题的一些讨论这里.)
(旁注:这个过程让我意识到一件事是 ZFS 恢复工具严重缺乏,任何人都不应该使用这个文件系统任何事物没有始终运行的数据的完整备份。并且不要依赖衣柜里的旧镜像驱动器作为最后的备份机会,除非您确定它是重要的。当 ZFS 协作时,ZFS 显然非常擅长维护数据完整性,但非常脆弱。当它损坏时——或者你做了一些小但愚蠢的事情——你的数据可能完全无法访问和读取,即使完好无损。)
无论如何,labelfix 实用程序已经 5 年没有更新了,因此它不能使用现代 ZFS 库文件进行编译。幸运的是,我仍然安装了原始操作系统版本,并且可以启动到该版本,然后下载旧的操作系统版本Linux 上的 ZFS源 tarball 并使用它来获取适当的 ZFS 库并在一切仍然有效的系统上构建环境。 (我开始调整 labelfix 实用程序以尝试使用现代 ZFS 库,但这似乎有点危险,因为我对需要修复以对应当前代码库的所有内部结构了解甚少。更容易在其上构建它旧版本。)
看哪,labelfix
立即轻松地将我设备上的标签重写为zpool import
至少可以解释的内容!
我应该说,ddrescue
在尝试执行任何操作之前,我曾经从原始驱动器复制整个内容。我强烈建议这样做,因为可能会犯错误,就像我所做的那样。我不小心写的原始池被命名为backup
,因此zdb
开始看到不同backup
池的多个版本,并且无法弄清楚为什么所有元数据都不匹配。我必须调整vdev_validate_skip=1
ZFS 内核模块才能导入池,但随后只导入了较新的 backup
游泳池(不是我想要的)。请注意,即使我指定了我想要的驱动器的确切路径,也会发生这种情况import
:当使用此方法强制导入时,它似乎完全忽略了我的规范,并使用与未在列表中列出的设备完全不同的配置。命令。
幸运的是,我已经对驱动器进行了另一个克隆,因此我可以尝试另一次运行。然而,labelfix
它也很聪明,似乎可以读取当前的驱动器配置,因此它发现我有两个旧驱动器,其中第一个backup
池中的“数据已损坏”。不幸的是,腐败意味着“固定”标签不仅将池列为DEGRADED
而且也FAULTED
将其列为“无法” import
。
此时我意识到我只需拔掉所有旧驱动器并在系统中完全没有它们的情况下工作,以避免破坏恢复尝试。不幸的是,labelfix
似乎只能修复一次,所以我现在要克隆该驱动器的#3(当前正在从我的第一个备份克隆进行复制)。一旦克隆过程完成,我将labelfix
在没有任何其他旧驱动器存在的情况下运行,并希望我能获得一个DEGRADED
可以使用的池import
。