看了一下代码,是否能够完全保住所有数据呢
写在前面
松鼠哥的ceph专业课程上线啦!
面向新手同学,从0实战,全面入门ceph安装部署与运维,有需要的同学赶紧扫码订购吧:
新的一年开始了,新的一年充满机遇和挑战啊,大家尤其要注意身体。
说到机遇,就不得不提一下咱们天翼云科技,机遇多多,目前还在大力招聘存储相关人才,有意向的老铁私聊起来!
上篇松鼠哥从操作层面恢复了一个被删除了的rbd存储池,对比了删除前后数据的情况,有部份数据已经完全被删除回收了,很多时候,尤其对于块存储,如果被回收的数据是块的元数据,那恢复出来其他的数据也许就没有意义了,因为块本身无法正常组织起来,因而,我们更关注的是能否完全做到不丢失数据!
答案是可以做到完全不丢数据!但是需要修改代码
代码的探索
首先,我们先理清楚当一个存储池被删除后,osd是如何处理删除pg流程的,这个很关键。
在测试集群vstart中,我们通过观察其日志,可以窥见其处理流程
1 | 2023-01-05 10:49:33.634 osd.1 15 queue_for_pg_delete on 1.0 e 15 |
日志太长,这里只截取了部份关键的信息,简单来说,PG删除的OP到达osd后,osd开始删除PG对应的object,然后开始清理这些object对应的空间,try_finish_pg_delete
完成收尾工作,最后bluestore.OnodeSpace
进行了空间的回收,即删除OP一到,立刻开始pg的删除及空间的回收。
经过分析,代码中主要完成PG删除任务的是_delete_some
函数,这个函数有个很有意思的地方,就是它自带了一个延迟PG删除的功能
1 | ghobject_t PG::_delete_some(ObjectStore::Transaction *t, |
真不错,自带了延迟删除功能!这样一来,如果我们启用了延迟删除PG,就能在它延迟期间进行数据的抢救!
进入延迟删除的两个条件是osd_delete_sleep
和delete_needs_sleep
,其中osd_delete_sleep
可以在配置文件中配置,我们可以设定一个比较合理的时间,比如1小时,而delete_needs_sleep
这个值比较麻烦。
从代码来看,当它为true时,才有可能进入延迟删除的流程,但它并不能通过配置文件进行配置,也没有其他地方能够对它进行修改,通过跟踪发现,它作为一个PG类的保护成员变量,初始值为false,在PG.h
的2902行中定义
1 | bool delete_needs_sleep = false; |
这就非常奇怪,默认为false,因而一开始就无法进入到延迟删除,但这个值又不给修改或者配置(虽然函数后面有改为true的操作,但是没用,因为走到后面pg都删掉了),那这个延迟删除流程就怎么都跑不进去,这么设计是什么意思呢????有明白的读者朋友希望赐教。
修改代码后的初步测试
delete_needs_sleep
默认是false不行,我们将其修改为true,然后重新编译代码,看看效果。
修改PG.h
后,重新编译,再重新起测试集群,将osd delete sleep
配置为300,再来一次删除存储池,然后观察其处理流程有何变化
1 | 2023-01-05 11:58:28.169 osd.1 15 queue_for_pg_delete on 1.0 e 15 |
出现了Delete scheduled at 2023-01-05 12:03:28.169538
推迟的日志!而且在既定的时间PG继续了之前的删除工作,这表明,让osd延迟删除pg是行得通的!我们将有可能在这段延迟的时间段内将所有数据恢复回来!
我们还需要关注当pg延迟删除后,在此期间如果恢复存储池,其后续是否真的能够恢复到完好如初的程度!推迟的op是否直接作废。
那么做法上,我们从测试集群将修改代码并完成编译后的二进制ceph-osd
对准生产集群对应文件进行替换,看看其实际的效果如何。
准生产场景下的恢复验证
我们这里直接开搞,配置延迟删除时间为10分钟,并打开相关osd日志
1 | [twj@osd-node-66 ~]$ tail -n3 /etc/ceph/ceph.conf |
严谨一点,我们将rbd map后,格式化为ext4,然后往里面写入2个大文件,并计算md5值,记录pool的对象数量
1 | [root@mon-node-01 twj]# ceph df |
接下来,删除这个存储池,预料之中,osd.1962的日志显示延迟删除,推迟时间为10分钟
1 | 2023-01-05 14:30:20.816 7f2ff50ee700 20 osd.1962 pg_epoch: 3540 pg[21.527( v 3539'115 (0'0,3539'115] lb MIN (bitwise) local-lis/les=3538/3539 n=0 ec=3531/3527 lis/c 3538/3538 les/c/f 3539/3539/0 3540/3540/3540) [] r=-1 lpr=3540 DELETING pi=[3538,3540)/1 crt=3539'115 lcod 3539'114 unknown NOTIFY mbc={}] _delete_some Delete scheduled at 2023-01-05 14:40:20.817426 |
ok,接下来模拟线上,我们先等待5分钟,然后将对应的osd全部stop掉,接着进行存储池的恢复。
如果不down掉的话,恢复存储池的时间过长,就会导致数据丢失,实际上我们在线上处理也应该是这样,保险起见,在条件允许的情况下(比如pool不共用osd),应该把osd先down掉,以确保数据的安全。
接下来就是**”成熟”**的技术了,上篇及之前的文章已经操作过了,这里直接快进
- 回滚集群osdmap到删除存储池之前的版本,这个要根据时间戳来确定
- force-create一个pg激活pool
- 当集群重新显示被删除的pool后,对相关osd进行手工mark complete
- 启动osd
1 | [twj@mon-node-01 twj]$ cat mon_osdmap.sh |
集群完全恢复后,我们再次验证数据
1 | data: |
数据完全一致!yes! i did it!
pool恢复后检查osd日志,完全没有pg删除的相关操作了!很明显,原来的删除op失效了,数据完完全全恢复了!真的是人类福音^_^
总结
这波验证意义还是很大的,通过修改代码层面的配置及ceph.conf的设置,完全恢复被删除存储池的数据很显然是可以做到的,不过遗留的delete_needs_sleep
的问题,默认是false,逻辑上还有点迷糊,接下来还是要再搞搞懂才行~
另外,本次演示操作是针对3副本的pool,而ec的pool是有点不同的,毕竟pg的设计差异很大,后面有时间和精力了,再深挖一下关于ec存储池恢复的问题。
不管怎么说,手工恢复被删除的存储池属于迫于无奈的极限操作,希望大家在日常维护中打醒12分精神,希望这种骚操作,大家都没有机会用上^_^
如果觉得松鼠哥的文章写得不错,就请赏杯咖啡吧。
- 本文作者: 奋斗的松鼠
- 本文链接: http://www.strugglesquirrel.com/2023/01/17/恢复已删除的存储池(下)/
- 版权声明: 本博客所有文章除特别声明外,创作版权均为作者个人所有,未经允许禁止转载!