Ceph蹚坑笔记 - (1)

来源:互联网 发布:高仿转转网站源码 编辑:程序博客网 时间:2024/06/05 03:39

Ceph蹚坑笔记 - (1)

  • Ceph蹚坑笔记 - 1
    • 现象
    • 分析
    • 结论

现象

由于设备调度的原因,运维的哥们需要把一台服务器上的OSD移除。他做了以下操作:
1. pkill ceph-osd关闭服务器上的所有OSD
2. 在集群把这些OSD标记成down后,用ceph osd rm <osd-id>删除对应的OSD ID
3. 期待与这些OSD有关的PG转移到其它OSD上,并由degraded状态转到active+clean状态
4. 等了很久,发现集群完全没有修复这些degraded PG的意思
5. 实在没办法,再执行ceph osd crush remove osd.<osd-id>,degraded PG终于逐渐转到active+clean状态

分析

OSD的状态发生变化触发OSD Map更新,所有活着的OSD都会基于新的OSD Map和根据CRUSH算法重新计算其所承载的PG的新归宿。如果发现PG的新归宿不是当前承载它的OSD集合,集群就会触发Peering动作(自己主导Peering或通知其他OSD发动Peering),进而进行必要的Recovery或Backfill。

OSD变为down后,相应的PG转入degraded状态是符合预期的。按常理说,在ceph osd rm <osd-id>之后集群应该注意到OSD的状态又发生了一些变化,并为degraded PG寻找新的归宿。

既然ceph osd rm <osd-id>没有触发Peering,很有可能是因为OSD不认为PG的归宿发生了变化。按照这个思路,查看了代码。OSDMap::_raw_to_up_osds()的如下代码确认了这个推测(环境中用的是ReplicatedPG)。这里!existsis_down被认为是等价的,在OSD变为down后,集群的决策是:幸存下来的OSD继续承载degraded PG。ceph osd rm <osd-id>之后,OSDMap::_raw_to_up_osds()的结果和OSD变为down时结果是一样的,所以不认为degraded PG需要新的OSD来承载,也就没有触发Peering和相应的Recovery或Backfill。

    up->clear();    for (unsigned i=0; i<raw.size(); i++) {      if (!exists(raw[i]) || is_down(raw[i]))    continue;      up->push_back(raw[i]);    }

后来,尝试了以下操作序列,就没有问题了
1. pkill ceph-osd关闭服务器上的所有OSD
2. 在集群把这些OSD标记成down后,用ceph osd out <osd-id>把对应OSD标记为out(也可以清除noout标志位,等待足够长的时间,让集群自动把OSD标记为out)
3. 用ceph osd rm <osd-id>删除对应的OSD ID
4. 相应的PG逐渐从degraded状态转到active+clean状态

本来以为ceph osd rm <osd-id>会隐含ceph osd out <osd-id>。从这次的观察看,这样的想当然是错误的。查看了一下OSDMonitor::prepare_command_impl()中的如下代码发现,原来out操作修改的是OSD ID的权值(OSDMap::osd_weight[id]OSDMap::_pg_to_osds()被使用),而rm是修改OSD ID的状态信息(OSDMap::osd_state[id]OSDMap::_raw_to_up_osds()中被间接使用)。

    } if (prefix == "osd out") {      if (osdmap.is_out(osd)) {        ss << "osd." << osd << " is already out. ";      } else {        pending_inc.new_weight[osd] = CEPH_OSD_OUT;        ss << "marked out osd." << osd << ". ";        any = true;      }    }     // ...    } else if (prefix == "osd rm") {      if (osdmap.is_up(osd)) {        if (any)          ss << ", ";        ss << "osd." << osd << " is still up; must be down before removal. ";        err = -EBUSY;       } else {         pending_inc.new_state[osd] = osdmap.get_state(osd);         pending_inc.new_uuid[osd] = uuid_d();         pending_metadata_rm.insert(osd);         if (any) {           ss << ", osd." << osd;         } else {           ss << "removed osd." << osd;         }         any = true;      }    }

OSDMap::_pg_to_osds()被先调用,然后OSDMap::_raw_to_up_osds()基于OSDMap::_pg_to_osds()的结果做运算。out的OSD在OSDMap::_pg_to_osds()先被清理出局,down的或被rm的OSD在OSDMap::_raw_to_up_osds()才被清理出局。

假设两副本的PG X最先是由osd.1和osd.11承载的。然后,osd.1进入down状态而不是out。这时,OSDMap::_pg_to_osds()还是选出了osd.1和osd.11,然后OSDMap::_raw_to_up_osds()从中选出了osd.11。接着osd.1被执行ceph osd rm,由于is_down!exists是等价的,OSDMap::_raw_to_up_osds()还是为PG X选择了osd.11。

假设两副本的PG X最先由osd.1,osd.11承载。但osd.1从down状态进入out状态之后才被执行ceph osd rmOSDMap::_pg_to_osds()会把osd.1淘汰并为PG X选择osd.11和另一个存活的OSD(假设是osd.21),而OSDMap::_raw_to_up_osds()也在此基础上选出了存活的osd.11和osd.21。这样集群就知道PG X应该重新分布到osd.11和osd.21上了。

ceph osd crush remove之所以也能能够触发PG的重分布,也是因为它修改CRUSH Map(OSDMap.crush)而促使OSDMap::_pg_to_osds()为PG X选择osd.11和osd.21而不是osd.1和osd.11。

结论

  • 这里的ceph osd rm <osd-id>不是很有必要,除非永远都不想再使用这些OSD ID了
  • ceph osd rm <osd-id>ceph osd out <osd-id>不同,ceph osd rm <osd-id>也不隐含ceph osd out <osd-id>
  • ceph osd rm <osd-id>之前最好等待对应的OSD变成out
0 0
原创粉丝点击