记一次数据恢复过程中,踩到osd由于快照数据不完整导致无法启动的bug

本文详细记录了一次Ceph集群数据恢复过程,遇到的问题包括多个OSD离线,历史PGMap缺失及硬件错误导致的数据恢复挑战。在尝试从其他OSD恢复数据时,发现了一个可能导致OSD频繁重启的bug,该bug涉及快照集的校验恢复。解决方案探讨了如何在缺乏历史信息的情况下进行数据恢复,并强调了及时处理集群降级状态的重要性。同时,提出了集群维护的建议,包括保持pgmap历史记录和避免单副本运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  在一次集群数据恢复过程中遇到的,最终导致osd无法全部启动,数据恢复失败

踩坑环境背景

  3osd,两副本pool,三个osd同时离线,且有一个osd无法启动,已经认为out和rm了,需要恢复数据(原集群可能不是active+clean状态,和两副本集群,坏一个副本的情况不一样,可能认为因素导致某些数据没恢复完就删掉了主pg所在osd)

  • 无历史pgmap记录(由于没有历史pg map信息,pg整正常状态和原本主pg所在osd信息无法获取)
  • 异常osd已经auth del,和rm过,外加硬件错误,导致该osd已无法使用ceph-objectstore-tool进行pg export-remove和import等操作

  因此只有尽可能从另外两个osd中尽量挽回数据。

恢复过程

  取一个卡在down状态pg,在两个osd进行比对后,使用ceph-objectstore-tool在其中一个osd上mark 该pg complete,并拉起osd,pg从down状态进入active+degrade+undersize+backfilling等状态,最终可以进入active+clean状态。

  后续pg如法炮制,最终所有pg全部从down状态进入active状态,还需要等待backfill恢复。

  在恢复过程中,原本标记为完整副本的osd突然停止(如果是服务的话,应该是反复重启)。报错堆栈如下

1: (SnapSet::get_clone_bytes(snapid_t) const+0xb6) [0x707b46]#012 
2: (ReplicatedPG::_scrub(ScrubMap&)+0x9e8) [0x7c0198]#012 
3: (PG::scrub_compare_maps()+0x5b6) [0x755306]#012 
4: (PG::chunky_scrub(ThreadPool::TPHandle&)+0x1d9) [0x758999]#012 
5: (PG::scrub(ThreadPool::TPHandle&)+0x19a) [0x75b96a]#012 
6: (OSD::ScrubWQ::_process(PG*, ThreadPool::TPHandle&)+0x19) [0x657309]#012 
7: (ThreadPool::worker(ThreadPool::WorkThread*)+0xaf1) [0xa56dd1]#012 
8: (ThreadPool::WorkThread::entry()+0x10) [0xa57cc0]#012 
9: (()+0x8182) [0x7f579ce6e182]#012 
10: (clone()+0x6d) [0x7f579b5e0fbd]

  查看日志,指向osd_types.cc中如下代码段。

oid SnapSet::from_snap_set(const librados::snap_set_t& ss, bool legacy)
{
  // NOTE: our reconstruction of snaps (and the snapc) is not strictly
  // correct: it will not include snaps that still logically exist
  // but for which there was no clone that is defined.  For all
  // practical purposes this doesn't matter, since we only use that
  // information to clone on the OSD, and we have already moved
  // forward past that part of the object history.

  seq = ss.seq;
  set<snapid_t> _snaps;
  set<snapid_t> _clones;
  for (vector<librados::clone_info_t>::const_iterator p = ss.clones.begin();
       p != ss.clones.end();
       ++p) {
    if (p->cloneid != librados::SNAP_HEAD) {
      _clones.insert(p->cloneid);
      _snaps.insert(p->snaps.begin(), p->snaps.end());
      clone_size[p->cloneid] = p->size;
      clone_overlap[p->cloneid];  // the entry must exist, even if it's empty.
      for (vector<pair<uint64_t, uint64_t> >::const_iterator q =
	     p->overlap.begin(); q != p->overlap.end(); ++q)
	clone_overlap[p->cloneid].insert(q->first, q->second);
      if (!legacy) {
	// p->snaps is ascending; clone_snaps is descending
	vector<snapid_t>& v = clone_snaps[p->cloneid];
	for (auto q = p->snaps.rbegin(); q != p->snaps.rend(); ++q) {
	  v.push_back(*q);
	}
      }
    }
  }

  // ascending
  clones.clear();
  clones.reserve(_clones.size());
  for (set<snapid_t>::iterator p = _clones.begin(); p != _clones.end(); ++p)
    clones.push_back(*p);

  // descending
  snaps.clear();
  snaps.reserve(_snaps.size());
  for (set<snapid_t>::reverse_iterator p = _snaps.rbegin();
       p != _snaps.rend(); ++p)
    snaps.push_back(*p);
}

  根据代码中clone_overlap[p->cloneid];与q != p->snaps.rend(),某些clone条目已经不存在或者不完整时,此处就会出现问题。

  redhat中相关链接

Bug 1273127 - Backport tracker 12738 - OSD reboots every few minutes with FAILED assert(clone_size.count(clone))

  文中提到,复现此bug需要1.某种特定方式损坏快照集 2.正好触发损坏部分的校验恢复。实际上该osd可以单独启动,只有启动另一个osd需要进行pg的backfilling时才会报错,情况类似。

在这里插入图片描述

可能的规避或者恢复手段

  本身是小概率bug,特定情况下损坏,此处pg所有osd同时离线且出现系统问题的几率还是较小,人为因素较多,如果有历史pgmap,已经保留原本集群内所有osd,恢复难度应该小很多。与项目相关人员沟通,集群可能之前很多pg就是单副本状态运行,只存在于个别osd上,未能进入clean的ok状态。运维时发现集群有降级或异常,需立即处理,避免侥幸心理。
  网上提供的方法(指clear-snapset clone_size方式),本身只适合少量snap丢失部分内容的场景,而该集群很多snap已经获取不到,丢失程度严重,无法完成最终数据恢复。即使进行了全部的有损恢复,对块存储以及快照,虚拟机等业务基本也是致命的,部分数据损坏对于这些业务来讲,可能一小块影响整段数据无法使用,与rgw可能只是影响部分对象访问的情况不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值