ceph 分布式存储mds 修复
解决:两种方法:[*]方法一:#ceph mds repaired AI_Spacefs:0
[*]
[*]#ceph mds repaired AI_Spacefs:1
[*]
此方法一般情况下是好使,当有osd stuck的状态时也会失效。这个时候要重启osd,若未发现stuck就要手动触发数据迁移把stuck的osd暴露出来。然后再执行上面的操作。
经测试,有两次都是通过上述方法解决问题的。[*]方法二:
这次问题要严重的多,所有的mds都没有active的状态,造成元数据无法恢复,方法一失效,所以此时需要放弃原来的cephfs,重建构建基于原来data池生成新的cephfs.
元数据故障恢复设置允许多文件系统ceph fs flag set enable_multiple true --yes-i-really-mean-it
[*]
创建一个新的元数据池,这里是为了不去动原来的metadata的数据,以免损坏原来的元数据ceph osd pool create recovery 8
[*]
将老的存储池data和新的元数据池recovery关联起来并且创建一个新的recovery-fsceph fs new recovery-fs recovery AI_Spacefs_data --allow-dangerous-metadata-overlay
[*]
做下新的文件系统的初始化相关工作#cephfs-data-scan init --force-init --filesystem recovery-fs --alternate-pool recovery
2020-03-18T16:22:50.508+0800 7f4a11a1d700 -1 NetHandler create_socket couldn't create socket (97) Address family not supported by protocol
[*]
出现上述的错误可以忽略进行下一步。reset下新的fs#ceph fs reset recovery-fs --yes-i-really-mean-it若失败,要把所有mds fail掉或者stop掉,再快速执行上面命令。#cephfs-table-tool recovery-fs:all reset session#cephfs-table-tool recovery-fs:all reset snap#cephfs-table-tool recovery-fs:all reset inode出现Address family not supported by protocol的错误忽略掉
[*]
做相关的恢复做下一步之前确保新建的recovery-fs没有active的mds,有则stop掉,不然该mds容易crashed。#cephfs-data-scan scan_extents --force-pool --alternate-pool recovery --filesystem AI_Spacefs AI_Spacefs_data
#cephfs-data-scan scan_inodes --alternate-pool recovery --filesystem AI_Spacefs -force-corrupt --force-init AI_Spacefs_data
#cephfs-data-scan scan_inodes --alternate-pool recovery --filesystem AI_Spacefs --force-corrupt --force-init AI_Spacefs_data
#cephfs-data-scan scan_links --filesystem recovery-fs
出现Address family not supported by protocol的错误忽略掉
# systemctl start ceph-mds@node82等待mds active 以后再继续下面操作
# ceph daemon mds.node82 scrub_path / recursive repair
事实上上面这一步并没有操作数据就已经恢复了。
设置成默认的fs
# ceph fs set-default recovery-fs
[*]
挂载检查数据# lsDATASETlost+foundSYSTEMUSER
# ll
lost+found/total 1-r-x------ 1 root root 237 Mar 11 13:21 1000172efb8
[*]
可以看到在lost+found里面就有数据了这个生成的文件名称就是实际文件存储的数据的prifix,也就是通过原始inode进行的运算得到的。如果提前备份好了原始的元数据信息# ceph daemon mds.node82 dump cache > /tmp/mdscache
[*]
那么可以比较轻松的找到丢失的文件原作者总结通过文件的inode可以把文件跟后台的对象结合起来,在以前我的恢复的思路是,把后台的对象全部抓出来,然后自己手动去对对象进行拼接,实际是数据存在的情况下,反向把文件重新link到一个路径,这个是官方提供的的恢复方法,mds最大的担心就是mds自身的元数据的损坏可能引起整个文件系统的崩溃,而现在,基本上只要data的数据还在的话,就不用担心数据丢掉,即使文件路径信息没有了,但是文件还在通过备份mds cache可以把文件名称,路径,大小和inode关联起来,而恢复的数据是对象前缀,也就是备份好了mds cache 就可以把整个文件信息串联起来了虽然cephfs的故障不是常发生,但是万一呢后续准备带来一篇关于cephfs从挂载点误删除数据后的数据恢复的方案,这个目前已经进行了少量文件的恢复试验了,等后续进行大量文件删除的恢复后,再进行分享
元数据故障恢复
设置允许多文件系统
ceph fs flag set enable_multiple true --yes-i-really-mean-it
创建一个新的元数据池,这里是为了不去动原来的metadata的数据,以免损坏原来的元数据
ceph osd pool create recovery 8
将老的存储池data和新的元数据池recovery关联起来并且创建一个新的recovery-fs
# ceph fs new recovery-fs recovery data --allow-dangerous-metadata-overlay
new fs with metadata pool 3 and data pool 2
做下新的文件系统的初始化相关工作
#cephfs-data-scan init --force-init --filesystem recovery-fs --alternate-pool recovery
reset下新的fs
#ceph fs reset recovery-fs --yes-i-really-mean-it
#cephfs-table-tool recovery-fs:all reset session
#cephfs-table-tool recovery-fs:all reset snap
#cephfs-table-tool recovery-fs:all reset inode
做相关的恢复
# cephfs-data-scan scan_extents --force-pool --alternate-pool recovery --filesystem cephdata
# cephfs-data-scan scan_inodes --alternate-pool recovery --filesystem ceph --force-corrupt --force-init data
# cephfs-data-scan scan_links --filesystem recovery-fs
# systemctl start ceph-mds@lab102
等待mds active 以后再继续下面操作
# ceph daemon mds.lab102 scrub_path / recursive repair
设置成默认的fs
# ceph fs set-default recovery-fs
挂载检查数据
#mount -t ceph 192.168.19.102:/ /mnt
# ll /mnt
total 0
drwxr-xr-x 1 root root 1 Jan11970 lost+found
# ll /mnt/lost+found/
total 226986
-r-x------ 1 root root 569306 May 25 16:16 10000000001
-r-x------ 1 root root 16240627 May 25 16:16 10000000002
-r-x------ 1 root root1356367 May 25 16:16 10000000003
-r-x------ 1 root root 137729 May 25 16:16 10000000004
-r-x------ 1 root root 155163 May 25 16:16 10000000005
-r-x------ 1 root root 118909 May 25 16:16 10000000006
-r-x------ 1 root root1587656 May 25 16:16 10000000007
-r-x------ 1 root root 252705 May 25 16:16 10000000008
-r-x------ 1 root root1825192 May 25 16:16 10000000009
-r-x------ 1 root root 156990 May 25 16:16 1000000000a
-r-x------ 1 root root3493435 May 25 16:16 1000000000b
-r-x------ 1 root root 342390 May 25 16:16 1000000000c
-r-x------ 1 root root1172247 May 25 16:16 1000000000d
-r-x------ 1 root root2516169 May 25 16:16 1000000000e
-r-x------ 1 root root3218770 May 25 16:16 1000000000f
-r-x------ 1 root root 592729 May 25 16:16 10000000010
可以看到在lost+found里面就有数据了
# file /mnt/lost+found/10000000010
/mnt/lost+found/10000000010: Microsoft PowerPoint 2007+
# file /mnt/lost+found/10000000011
/mnt/lost+found/10000000011: Microsoft Word 2007+
# file /mnt/lost+found/10000000012
/mnt/lost+found/10000000012: Microsoft Word 2007+
# file /mnt/lost+found/10000000013
/mnt/lost+found/10000000013: Microsoft PowerPoint 2007+
这个生成的文件名称就是实际文件存储的数据的prifix,也就是通过原始inode进行的运算得到的
如果提前备份好了原始的元数据信息
# ceph daemon mds.lab102 dump cache > /tmp/mdscache
那么可以比较轻松的找到丢失的文件 解决:两种方法:
方法一:
#ceph mds repaired AI_Spacefs:0
#ceph mds repaired AI_Spacefs:1
此方法一般情况下是好使,当有osd stuck的状态时也会失效。这个时候要重启osd,若未发现stuck就要手动触发数据迁移把stuck的osd暴露出来。然后再执行上面的操作。
经测试,有两次都是通过上述方法解决问题的。
方法二:
这次问题要严重的多,所有的mds都没有active的状态,造成元数据无法恢复,方法一失效,所以此时需要放弃原来的cephfs,重建构建基于原来data池生成新的cephfs.
元数据故障恢复
设置允许多文件系统
ceph fs flag set enable_multiple true --yes-i-really-mean-it
创建一个新的元数据池,这里是为了不去动原来的metadata的数据,以免损坏原来的元数据
ceph osd pool create recovery 8
将老的存储池data和新的元数据池recovery关联起来并且创建一个新的recovery-fs
ceph fs new recovery-fs recovery AI_Spacefs_data --allow-dangerous-metadata-overlay
做下新的文件系统的初始化相关工作
#cephfs-data-scan init --force-init --filesystem recovery-fs --alternate-pool recovery
2020-03-18T16:22:50.508+0800 7f4a11a1d700 -1 NetHandler create_socket couldn't create socket (97) Address family not supported by protocol
出现上述的错误可以忽略进行下一步。
reset下新的fs
#ceph fs reset recovery-fs --yes-i-really-mean-it
若失败,要把所有mds fail掉或者stop掉,再快速执行上面命令。
#cephfs-table-tool recovery-fs:all reset session
#cephfs-table-tool recovery-fs:all reset snap
#cephfs-table-tool recovery-fs:all reset inode
出现Address family not supported by protocol的错误忽略掉
做相关的恢复
做下一步之前确保新建的recovery-fs没有active的mds,有则stop掉,不然该mds容易crashed。
#cephfs-data-scan scan_extents --force-pool --alternate-pool recovery --filesystem AI_Spacefs AI_Spacefs_data
#cephfs-data-scan scan_inodes --alternate-pool recovery --filesystem AI_Spacefs -force-corrupt --force-init AI_Spacefs_data
#cephfs-data-scan scan_inodes --alternate-pool recovery --filesystem AI_Spacefs --force-corrupt --force-init AI_Spacefs_data
#cephfs-data-scan scan_links --filesystem recovery-fs
出现Address family not supported by protocol的错误忽略掉
# systemctl start ceph-mds@node82
等待mds active 以后再继续下面操作
# ceph daemon mds.node82 scrub_path / recursive repair
事实上上面这一步并没有操作数据就已经恢复了。
设置成默认的fs
# ceph fs set-default recovery-fs
挂载检查数据
# ls
DATASETlost+foundSYSTEMUSER
# ll lost+found/
total 1
-r-x------ 1 root root 237 Mar 11 13:21 1000172efb8
可以看到在lost+found里面就有数据了这个生成的文件名称就是实际文件存储的数据的prifix,也就是通过原始inode进行的运算得到的。
如果提前备份好了原始的元数据信息
# ceph daemon mds.node82 dump cache > /tmp/mdscache
那么可以比较轻松的找到丢失的文件 针对原因一:
此次情况比较特殊,ceph health detail命令竟然看不到stuck的osd,解决如下:
把 使用率比较高的osd降权重,手动触发osd的数据迁移。
重新ceph health detail命令,此时会发现stuck的osd,重启相应的osd,mds状态恢复。
针对原因二(收效甚微):
调小mds mds_cache_memory_limit到40G 以下
# ceph tell mds.\* injectargs '--mds_cache_memory_limit=40000000000
在/etc/ceph/ceph.conf修改,传到所有ceph节点
针对原因三(主要原因):
方法一 mds多活热备调低敏感度,有两个操作:
调高mds_beacon_grace=300,调高超时时间。
写到/etc/ceph/ceph.conf里,传到所有mds节点,然后重启mds
1
mds采用热备模式,替换原来冷备模式,加快mds加入速度。
ceph fs set <fs name> allow_standby_replay true
1
方法二 mds多活热备静态目录方法,即给目录划分不同的mds
命令:
setfattr -n ceph.dir.pin -v 2 path/to/dir
mkdir -p a/b
# “a” and “a/b” both start without an export pin set
setfattr -n ceph.dir.pin -v 1 a/
# a and b are now pinned to rank 1
setfattr -n ceph.dir.pin -v 0 a/b
# a/b is now pinned to rank 0 and a/ and the rest of its children are still pinned to rank 1
1.创建 cephfs
一个cephfs至少要求两个librados存储池,一个为data,一个为metadata。
step 1.创建cephfs存储池fs_metadata,fs_data
# 元数据库存储池
ceph osd pool create cephfs_metadata 8 8
# 数据
ceph osd pool create cephfs_data 8 8
step 2.使用fs new命令enable 文件系统
ceph fs new cephfs cephfs_metadata cephfs_data
使用mds来观察
# ceph fs ls
name: cephfs, metadata pool: fs_metadata, data pools:
#
文件系统创建完毕后, MDS 服务器就能达到 active 状态了,比如在一个单 MDS 系统中:
# ceph mds stat
cephfs:0
#
查看集群监控状态:
# ceph -s
cluster:
id: db51539c-d566-11eb-a3e9-e6f1aaf957fd
health: HEALTH_ERR
2 filesystems are offline
2 filesystems are online with fewer MDS than max_mds
services:
mon: 3 daemons, quorum ceph-stroage01,ceph-stroage02,ceph-stroage03 (age 9m)
mgr: ceph-stroage01.cdthyk(active, since 9m), standbys: ceph-stroage03.dtasrq
mds: cephfs:0 cephfs_k8s:0
osd: 6 osds: 6 up (since 9m), 6 in (since 2w)
data:
pools: 8 pools, 201 pgs
objects: 68 objects, 87 MiB
usage: 6.6 GiB used, 593 GiB / 600 GiB avail
pgs: 201 active+clean
#
# ceph health detail
HEALTH_ERR 2 filesystems are offline; 2 filesystems are online with fewer MDS than max_mds
MDS_ALL_DOWN: 2 filesystems are offline
fs cephfs is offline because no MDS is active for it.
fs cephfs_k8s is offline because no MDS is active for it.
MDS_UP_LESS_THAN_MAX: 2 filesystems are online with fewer MDS than max_mds
fs cephfs has 0 MDS online, but wants 1
fs cephfs_k8s has 0 MDS online, but wants 1
#
所有的mds都没有active的状态,造成元数据无法恢复,所以此时需要放弃原来的cephfs,重建构建基于原来data池生成新的cephfs.
2.元数据故障恢复
step 1.设置允许多文件系统
ceph fs flag set enable_multiple true --yes-i-really-mean-it
step 2.创建一个新的元数据池,以免损坏原来的元数据
ceph osd pool create recovery 8
step 3.将存储池fs_data和新的元数据池recovery关联创建一个新的recovery-fs
ceph fs new recovery-fs recovery fs_data --allow-dangerous-metadata-overlay
step 4.文件系统的初始化相关工作
cephfs-data-scan init --force-init --filesystem recovery-fs --alternate-pool recovery
step 5.reset fs
ceph fs reset recovery-fs --yes-i-really-mean-it
若失败,要把所有mds fail掉或者stop掉,再快速执行上面命令。
cephfs-table-tool recovery-fs:all reset session
cephfs-table-tool recovery-fs:all reset snap
cephfs-table-tool recovery-fs:all reset inode
出现Address family not supported by protocol的错误忽略掉
step 6.恢复相关
确保新建的recovery-fs没有active的mds,有则stop掉,不然该mds容易crashed。
cephfs-data-scan scan_extents --force-pool --alternate-pool recovery --filesystem cephfs fs_data
cephfs-data-scan scan_inodes --alternate-pool recovery --filesystem cephfs --force-corrupt --force-init fs_data
cephfs-data-scan scan_links --filesystem recovery-fs
出现Address family not supported by protocol的错误忽略掉
systemctl start ceph-mds@node82
等待 mds active 以后再继续下面操作
ceph daemon mds.node82 scrub_path / recursive repair
设置成默认的fs
ceph fs set-default recovery-fs
可以看到在lost+found里面就有数据了这个生成的文件名称就是实际文件存储的数据的prifix,也就是通过原始inode进行的运算得到的。
备份原始的元数据信息
ceph daemon mds.node82 dump cache > /tmp/mdscache
元数据恢复原理
一般文件系统采用的fsck命令来维护文件系统一致性,但是fsck对cephfs的难度是非常大的,主要原因在于其机制存在根本的区别:
cephfs修复的是一个rados集群数据而非一块磁盘设备;
需要精确的识别数据的所有数据片,及这些数据片所属的inode
大量的元数据不可能全部保存到内存中
数据丢失原因可能在于
(1)系统bug导致;
(2)由于RADOS同步的灾难性故障——可能到时大量数据丢失;
(3)bit位翻转(bitrot)
cephfs-data-scan
cephfs-data-scan根据数据存储池中的内容重新生成丢失文件和目录的元数据对象。
step 1.初始化
cephfs-data-scan init
step 2.扫描所有对象以计算索引节点的尺寸和 mtime 元数据;
cephfs-data-scan scan_extents <datapool>
```bash
step 3.从每个文件的第一个对象扫描出元数据并注入元数据存储池。
```bash
cephfs-data-scan scan_inodes <datapool>
如果数据存储池内的文件很多、或者有很大的文件,这个命令就要花费很长时间。要加快处理,可以让这个工具多跑几个例程。先确定例程数量、再传递给每个例程一个数字 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
3.mds rank 0 is damaged
启动ceph后,出现如下错误:
# ceph health detail
HEALTH_ERR mds rank 0 is damaged; mds cluster is degraded
mds.0 is damaged
mds cluster is degraded
提示 mds.0 不可用。
在部署ceph时,安装了3个mds, 分别运行在3台服务器上。并且参考官方的配置,使其中一个作为 master 对外提供服务,另外两个作为 standby。来预防单点故障。(max_mds 设置为 2)
http://docs.ceph.com/docs/jewel/cephfs/standby/#examples
该错误发生后,3 个mds,均为 standby 状态。按照官网的描述来看,当所有 mds 均处于 standby 状态时,其中一个 mds 会选举称为 master.
于是挨个停止mds, 随后又逐个启动并查看/var/log/ceph/ceph-mds.xx.log。发现 mds 在称为 master 时,出现了如下错误:
...
2017-09-26 11:30:48.976326 7f9ee39417000 mds.0.journaler(ro) _finish_read got less than expected (4194304)
2017-09-26 11:30:48.976354 7f9ee17347000 mds.0.log _replay journaler got error -22, aborting
2017-09-26 11:30:49.071230 7f9ee39417000 mds.0.journaler(ro) _finish_read got less than expected (4194304)
2017-09-26 11:30:49.071472 7f9ee1734700 -1 log_channel(cluster) log : Error loading MDS rank 0: (22) Invalid argument
2017-09-26 11:30:49.076129 7f9ee17347001 mds.k8s-node1 respawn
...
2017-09-26 11:30:49.099291 7f99e58be1800 pidfile_write: ignore empty --pid-file
2017-09-26 11:30:49.571643 7f99dfacf7001 mds.k8s-node1 handle_mds_map standby
提示在读取 journal 的时候出现差错,因此可以确定问题出在 mds journal 上。
$ ceph mds repaire 0 step 1.导出 journal
在执行有风险的操作之前,先将 journal 备份:
ceph-journal-tool journal export backup.bin
Note : 这个文件大小和ceph集群存储数据量成正比,会很大
step 2.从 journal 恢复
当 mds 因为 journal 损坏或者其他原因无法读取,为了恢复文件元数据可以执行:
ceph-journal-tool event recover_dentries summary
默认会从 mds.0 中恢复, 使用 –rank=<n> 来指定其他mds
这条指令会将 journal 中所有可回收的 inodes/dentries 写到后端存储,前提是要写入的 innodes/dentries 版本比后端存储里面的要高。 如果某个区块的 journal 丢失或者损坏,那么就不会被写到后端存储中。
Note: 除了将inodes/dentries 写入之外, 这条命令还会更新每个 MDS 的 InoTables, 标明被写入的 inodes 号在使用中,在一般情况下,会让后端存储恢复正常状态。
此操作不能保证后端存储的状态达到前后一致,而且在此之后有必要执行 MDS 在线 scrub。此命令不会更改日志内容,恢复了能恢复的部分后应该把journal截短。
Note : 然而在执行这个命令之后,集群并未恢复正常,因此还需要往下看
step 3. 截断日志
cephfs-journal-tool journal reset
重置journal 将会造成metadata丢失,除非你提前通过诸如 recover_dentries 的方式将metadata保存。该操作可能会在数据池里面产生一些孤儿对象。这会造成已写入的inodes再次被重新分配, 权限规则可能因此被违反。
Note : 有个类似的 issue中也提到了上述步骤(link),但执行到这一步后,就没往下走了。
And mds rejoined again and everything seems to work fine now. 这点我没验证过,担心会有隐患。于是按照文档步骤继续执行了。
step 4. 清除 MDS 表
在 journal 被 reset 之后, 它可能不再符合MDS表的内容(包括:InoTable, SessionMap, SnapServer). 重置 SessionMap (即擦除所有Session) , 通过命令:
cephfs-table-tool all reset session
这条命令会在所有mds中生效, 可以将 all 替换为指定 mds 标号。
step 5.MDS MAP RESET
一旦文件系统底层的 RADOS 状态(即元数据存储池的内容)有所恢复,有必要更新 MDS 图以反映元数据存储池的内容。可以用下面的命令把 MDS MAP 重置到单个 MDS :
ceph fs reset <fs name> --yes-i-really-mean-it
运行此命令之后, MDS rank 保存在 RADOS 上的任何不为 0 的状态都会被忽略:因此这有可能导致数据丢失。
Note : fs name 可通过 ceph fs ls 查看
step 6. RECOVERY FROM MISSONG METADATA OBJECT
# Session table
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
# Root inodes ("/" and MDS directory)
cephfs-data-scan init
最后,会基于数据池中丢失的文件和目录来重新创建 METADATA OBJECT。分为2步。
扫描所有对象并计算出inodes 的大小和 mtime metadata
cephfs-data-scan scan_extents <data pool>
扫描每个文件中的第一个对象来收集METADATA,随后注入到 metadata pool
cephfs-data-scan scan_inodes <data pool>
Note : 这两个步骤太耗时了,应该考虑起多个workers来同步处理。data pool 可通过 ceph fs ls 查看
# 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
Note : 一定要确保在所有 workers 完成 scan_extents 之后再进行scan_inodes操作。==
待所有操作执行完毕之后:
# ceph -s
cluster e61d687d-f43d-4f50-af66-da96e5856be9
health HEALTH_OK
monmap e5: 3 mons at {k8s-master=172.16.18.30:6789/0,k8s-node1=172.16.18.6:6789/0,k8s-node2=172.16.18.7:6789/0}
election epoch 676, quorum 0,1,2 k8s-node1,k8s-node2,k8s-master
fsmap e4970: 1/1/1 up {0=k8s-node1=up:active}, 2 up:standby
osdmap e2914: 6 osds: 6 up, 6 in
flags sortbitwise,require_jewel_osds
pgmap v10110565: 256 pgs, 4 pools, 25575 MB data, 372 kobjects
58730 MB used, 11115 GB / 11172 GB avail
256 active+clean # ceph fs dump
dumped fsmap epoch 135
e135
enable_multiple, ever_enabled_multiple: 1,0
compat: compat={},rocompat={},incompat={1=base v0.20,2=client writeable ranges,3=default file layouts on dirs,4=dir inode in separate object,5=mds uses versioned encoding,6=dirfrag is stored in omap,8=no anchor table,9=file layout v2}
legacy client fscid: 3
Filesystem 'filefs' (3)
fs_name filefs
epoch 135
flags c
created 2022-07-27 11:43:28.889488
modified 2022-08-03 10:23:42.173444
tableserver 0
root 0
session_timeout 60
session_autoclose 300
max_file_size 1099511627776
last_failure 0
last_failure_osd_epoch 386
compat compat={},rocompat={},incompat={1=base v0.20,2=client writeable ranges,3=default file layouts on dirs,4=dir inode in separate object,5=mds uses versioned encoding,6=dirfrag is stored in omap,8=no anchor table,9=file layout v2}
max_mds 1
in 0
up {0=84099}
failed
damaged
stopped
data_pools
metadata_pool 6
inline_data disabled
balancer
standby_count_wanted 1
84099: 192.168.120.31:6800/2291079756 'ceph-3' mds.0.117 up:active seq 40
Standby daemons:
84111: 192.168.120.16:6800/463439748 'ceph-2' mds.-1.0 up:standby seq 2
84120: 192.168.120.23:6800/4181220800 'ceph-1' mds.-1.0 up:standby seq 1 1、前言
这里实验在使用cephfs时,如果cephfs的元数据损坏或丢失了,那该如何恢复出用户数据。下面就为大家演示下如何恢复。
2、准备测试环境
2.1、准备测试集群
我是基于L版本做的实验,J版也是可以的。测试环境如下:
# ceph -v
ceph version 12.2.11 (26dc3775efc7bb286a1d6d66faee0ba30ea23eee) luminous (stable)
# ceph osd tree
ID CLASS WEIGHTTYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.07397 root default
-3 0.03699 host ceph05
0 hdd 0.01799 osd.0 up1.00000 1.00000
1 hdd 0.01900 osd.1 up1.00000 1.00000
-5 0.03699 host ceph06
2 hdd 0.01900 osd.2 up1.00000 1.00000
3 hdd 0.01900 osd.3 up1.00000 1.00000
# ceph -s
cluster:
id: 176feab8-ca22-47bf-b809-202deac53c6f
health: HEALTH_WARN
crush map has straw_calc_version=0
services:
mon: 1 daemons, quorum ceph05
mgr: ceph05(active)
mds: cephfs-1/1/1 up{0=ceph05=up:active}
osd: 4 osds: 4 up, 4 in
data:
pools: 10 pools, 304 pgs
objects: 918 objects, 2.60GiB
usage: 6.70GiB used, 71.3GiB / 78.0GiB avail
pgs: 304 active+clean
2.2、准备测试数据
挂载kc
# mount -t ceph 192.168.10.30:/ /cephfs
# df -h|grep ceph
···
192.168.10.30:/ 78G6.8G 72G 9% /cephfs
···
写入数据(这里我写入了几个比较有代表性的文件类型:txt、jpg、png、pdf、word、excel)
# ll /cephfs/
total 5912
-rw-r--r-- 1 root root 31232 Mar 15 12:18 111.doc
-rw-r--r-- 1 root root 20593 Mar 15 12:18 22.xlsx
-rw-r--r-- 1 root root 12494 Mar 15 12:17 5be23a3eec2c0.png
-rw-r--r-- 1 root root 3189 Mar 15 12:17 cmap.txt
-rw-r--r-- 1 root root 5985243 Mar 15 12:17 hello0.pdf
3、模拟故障
这里直接模拟元数据丢失的情况,删除metadata池里面所有的元数据对象:
# rados -p metadata ls|xargs -i rados -p metadata rm {}
# ceph df
GLOBAL:
SIZE AVAIL RAW USED %RAW USED
78.0GiB 71.3GiB 6.71GiB 8.60
POOLS:
NAME ID USED %USED MAX AVAIL OBJECTS
.rgw.root 1 1.09KiB 0 63.3GiB 4
default.rgw.control 2 0B 0 63.3GiB 8
default.rgw.meta 3 720B 0 63.3GiB 5
default.rgw.log 4 0B 0 63.3GiB 207
default.rgw.buckets.index 5 0B 0 63.3GiB 1
default.rgw.buckets.data 6 1.02KiB 0 63.3GiB 2
pool01 7 2.60GiB 3.94 63.3GiB 666
rbd 8 36B 0 63.3GiB 4
metadata 17 0B 0 63.3GiB 0
data 18 5.77MiB 0 63.3GiB 6
看到metadata池里面没有对象了已经,重启下mds看效果,因为mds里面会缓存元数据信息,所以要重启下mds:
# systemctl restart ceph-mds@ceph05
#
#
# ceph -s
cluster:
id: 176feab8-ca22-47bf-b809-202deac53c6f
health: HEALTH_WARN
1 filesystem is degraded
1 filesystem has a failed mds daemon
crush map has straw_calc_version=0
services:
mon: 1 daemons, quorum ceph05
mgr: ceph05(active)
mds: cephfs-0/1/1 up , 1 failed
osd: 4 osds: 4 up, 4 in
data:
pools: 10 pools, 304 pgs
objects: 905 objects, 2.60GiB
usage: 6.71GiB used, 71.3GiB / 78.0GiB avail
pgs: 304 active+clean
看到集群现在不正常了,访问kc里面的数据卡住,说明数据已经无法正常读取了。
4、开始恢复
使用我编写的py脚本(文末给出了源码)恢复,把脚本放到集群任意一台节点上执行:
# python recovery_cephfs.py -p data
-p指定cephfs的数据池,运行完之后会在当前目录下产生两个文件夹和一个运行脚本的日志文件。
# ll
total 16
-rw-r--r-- 1 root root 3826 Mar 15 13:57 recovery_cephfs.py
drwxr-xr-x 2 root root120 Mar 15 13:57 recoveryfiles
-rw-r--r-- 1 root root 4804 Mar 15 13:57 recovery.log
drwxr-xr-x 2 root root 4096 Mar 15 13:57 recoveryobjs
查看恢复出来的文件在recoveryfiles文件夹下:
# ll recoveryfiles/
total 12364
-rw-r--r-- 1 root root 5985243 Mar 15 13:57 10000000000-pdf
-rw-r--r-- 1 root root 3189 Mar 15 13:57 10000000001-text
-rw-r--r-- 1 root root 12494 Mar 15 13:57 10000000002-png
-rw-r--r-- 1 root root 31232 Mar 15 13:57 10000000003-text
-rw-r--r-- 1 root root 20593 Mar 15 13:57 10000000004-excel
文件名格式为”文件在cephfs里面的inode-该文件可能的类型“。恢复出来的文件名后面会给出该文件的类型。这样就可以使用合适的软件打开该文件来验证文件是否完整。
5、总结
在cephfs文件系统的元数据完全损坏的情况下,只要数据池对象不丢失,就可以恢复出完整的数据。恢复的思路如下:
获取数据池对象
根据inode找到该文件的所有对象
拼接对象
使用脚本注意事项:
现在的脚本在只加入了txt、jpg、png、pdf、word、excel这些文件类型的识别,需要其他的就需要自己加入到脚本里面了
只适合副本池
如果数据量特别大,不适合使用脚本,不过可以参考脚本的思路去一个一个文件恢复
6、脚本
# coding: utf-8
import os
import shutil
import json
import sys
import subprocess
import copy
import logging
import argparse
__auth__ = 'ypdai'
SLEEP_INTERVAL = 1
logging.basicConfig(filename='./recovery.log', format='%(asctime)s : %(levelname)s%(message)s',
level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
RECOVERY_OBJ_DIR = os.path.join(BASE_DIR, 'recoveryobjs')
RECOVERY_FILE_DIR = os.path.join(BASE_DIR, 'recoveryfiles')
def exec_cmd(cmd):
"""
执行shell命令,并返回标准输出和执行状态码
:param cmd:
:return:
"""
logging.info('exec_cmd():: cmd: {}'.format(cmd))
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.wait()
out = p.stdout.read()
code = p.returncode
logging.info('exec_cmd():: cmd exec out: {}, code: {}'.format(out, code))
return out, code
def prepare(pool_name):
"""
准备恢复条件
1、检查所给pool name是不是cephfs的数据池
2、创建recoveryobjs和recoveryfiles文件加
:param pool_name:
:return:
"""
cmd = 'ceph fs ls -f json-pretty'
out, code = exec_cmd(cmd)
out = json.loads(out)
for cnt in out:
if pool_name not in cnt.get('data_pools'):
return False
if os.path.isdir(RECOVERY_OBJ_DIR):
shutil.rmtree(RECOVERY_OBJ_DIR)
os.mkdir(RECOVERY_OBJ_DIR)
if os.path.isdir(RECOVERY_FILE_DIR):
shutil.rmtree(RECOVERY_FILE_DIR)
os.mkdir(RECOVERY_FILE_DIR)
return True
def get_file_type(file_path):
cmd = 'file %s' % file_path
out, code = exec_cmd(cmd)
out = out.split(':')[-1].lower()
file_type = 'text'
if 'word' in out:
file_type = 'word'
elif 'excel' in out:
file_type = 'excel'
elif 'pdf' in out:
file_type = 'pdf'
elif 'text' in out:
file_type = 'text'
elif 'jpeg' in out:
file_type = 'jpg'
elif 'png' in out:
file_type = 'png'
return file_type
def do_recovery(pool_name):
"""
具体执行恢复,大概恢复逻辑如下:
1、从数据池里面获取所有的数据对象
2、找到每个文件的head对象,然后把数据这个文件的其他对象内容写入head对象里面
3、根据head对象的文件类型,推测该文件的实际类型
:param pool_name:
:return:
"""
cmd = 'for obj in $(rados -p %s ls);do rados -p %s get ${obj} %s/${obj};done' % (
pool_name, pool_name, RECOVERY_OBJ_DIR)
out, code = exec_cmd(cmd)
if code != 0:
logging.error('do_recovery():: get obj from rados failed.')
return
cmd = 'ls %s' % RECOVERY_OBJ_DIR
out, code = exec_cmd(cmd)
if code != 0:
logging.error('do_recovery():: list obj failed.')
return
done_lst = []
objects = out.split()
for obj in objects:
inode, number = obj.split('.')
if inode in done_lst:
continue
cmd = '''ls -l %s | awk '{print $NF}' | grep ^%s |sort''' % (RECOVERY_OBJ_DIR, inode)
out, code = exec_cmd(cmd)
files = out.split('\n')
head_file = files
file_type = get_file_type('%s/%s' % (RECOVERY_OBJ_DIR, head_file))
cmd = 'cp %s/%s %s/%s-%s' % (RECOVERY_OBJ_DIR, head_file, RECOVERY_FILE_DIR, inode, file_type)
out, code = exec_cmd(cmd)
for f in files:
if not f:
continue
cmd = 'cat %s/%s >> %s/%s-%s' % (RECOVERY_OBJ_DIR, f, RECOVERY_FILE_DIR, inode, file_type)
out, code = exec_cmd(cmd)
done_lst.append(inode)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--pool', required=True, type=str, dest='pool',
help='select given cephfs data pool by name')
args = parser.parse_args()
if not prepare(args.pool):
logging.error('main():: invalid pool name.')
sys.exit(1)
logging.info('=== main():: recovery start')
do_recovery(args.pool)
logging.info('=== main():: recovery done')
页:
[1]