灾难恢复

Danger

本章节是为专家准备的,尽可能地恢复损坏的文件系统。这些操作有可能改善你的处境,也可能更糟糕。如果你不太确定,最好别下手。

导出日志

尝试危险的操作前,先备份个日志副本,像这样:

cephfs-journal-tool journal export backup.bin

需要注意的是,此命令在日志损坏严重时也许会失效,在这种情况下,应该进行 RADOS 级的复制( http://tracker.ceph.com/issues/9902 )。

从日志恢复 dentry

如果日志损坏、或因其它原因导致 MDS 不能重放它,可以这样尝试恢复文件元数据:

cephfs-journal-tool event recover_dentries summary

此命令默认会操作 rank 0 的 MDS ,用 –rank=<n> 指定其它 rank 。

在条件满足的情况下,此命令会把日志中可恢复的 inode/dentry 写入后端存储,比如这些 inode/dentry 的版本号高于后端存储中的版本。如果日志中的某一部分丢失或损坏,就会被跳过。

注意,除了写出 dentry 和 inode 之外,此命令还会更新各 MDS rank “内”的 InoTables ,以把写入的 inode 标识为正在使用。在简单的案例中,此操作即可使后端存储回到完全正确的状态。

Warning

此操作不能保证后端存储的状态达到自我一致,而且在此之后有必要执行 MDS 在线洗刷。此命令不会更改日志内容,所以把能恢复的给恢复之后,应该分别裁截日志。

日志裁截

如果日志损坏或因故 MDS 不能重放它,你可以这样裁截它:

cephfs-journal-tool journal reset

Warning

重置日志导致元数据丢失,除非你已经用其它方法(如 recover_dentries )提取过了。此操作很可能会在数据存储池中留下一些孤儿对象,并导致已写过的索引节点被重分配,以致权限规则被破坏。

擦除 MDS 表

重置日志后,可能 MDS 表( InoTable 、 SessionMap 、 SnapServer )的内容就不再一致了。

要重置 SessionMap (擦掉所有会话),用此命令:

cephfs-table-tool all reset session

此命令会在所有 MDS rank “内”的表中执行。如果只想在指定 rank 中执行,把 all 换成对应的 MDS rank 。

会话表是最有可能需要重置的表,但是如果你知道你还需要重置其它表,那就把 session 换成 snap 或者 inode 。

MDS 图重置

一旦文件系统底层的 RADOS 状态(即元数据存储池的内容)恢复到一定程度,也许有必要更新 MDS 图以反映元数据存储池的内容。可以用下面的命令把 MDS 图重置到单个 MDS :

ceph fs reset <fs name> --yes-i-really-mean-it

运行此命令之后, MDS rank 保存在 RADOS 上的任何不为 0 的状态都会被忽略:因此这有可能导致数据丢失。

也许有人想知道 ‘fs reset’ 和 ‘fs remove; fs new’ 的不同。主要区别在于,执行删除、新建操作会使 rank 0 处于 creating 状态,那样会覆盖所有根索引节点、并使所有文件变成孤儿;相反, reset 命令会使 rank 0 处于 active 状态,这样下一个要认领此 rank 的 MDS 守护进程会继续、并使用已存在于 RADOS 中的数据。

元数据对象丢失的恢复

取决于丢失或被篡改的是哪种对象,你得运行几个命令生成这些对象的默认版本。

# 会话表
cephfs-table-tool 0 reset session
# SnapServer 快照服务器
cephfs-table-tool 0 reset snap
# InoTable 索引节点表
cephfs-table-tool 0 reset inode
# Journal 日志
cephfs-journal-tool --rank=0 journal reset
# 根索引节点( / 和所有 MDS 目录)
cephfs-data-scan init

最后,根据数据存储池中的内容重新生成丢失文件和目录的元数据对象。这要分两步完成,首先,扫描所有对象以计算索引节点的尺寸和 mtime 元数据;其次,从每个文件的第一个对象扫描出元数据并注入元数据存储池。

cephfs-data-scan scan_extents <data pool>
cephfs-data-scan scan_inodes <data pool>

如果数据存储池内的文件很多、或者有很大的文件,这个命令就要花费很长时间。要加快处理,可以让这个工具多跑几个例程。先确定例程数量、再传递给每个例程一个数字 N ,此数字应大于 0 且小于 (N - 1) ,像这样:

# Worker 0
cephfs-data-scan scan_extents <data pool> 0 1
# Worker 1
cephfs-data-scan scan_extents <data pool> 1 1

# Worker 0
cephfs-data-scan scan_inodes <data pool> 0 1
# Worker 1
cephfs-data-scan scan_inodes <data pool> 1 1

切记!!!所有运行 scan_extents 阶段的例程都结束后才能开始 scan_inodes 。