背景
近期遇到两次,分别为ceph M版本和ceph N版本。客户反馈发现集群存在某个osd 离线,同时pg incomplete。尝试手动拉起该osd时,该osd可以启动,但同时会导致其他部分osd离线,继续拉起osd,最终会扩散至越来越多的osd离线,最终集群进入崩溃。
影响范围
- 三副本池和纠删池都出现过,两副本集群尚未发现
- 版本为M和N早期版本
- 均为bluestore,未配置独立高速硬盘作为db和wal分区
故障程度
大概率数据损坏,丢失数据为几个pg级,操作可能抢救回部分数据。集群可以恢复读写
日志报错
osd异常退出部分,堆栈指向pg_log_t::rewind_fron_head(eversion_t),日志中查看退出线程,如果开启了debug_osd 20,日志中可以看到具体的pgid。
由于pg log的损坏,pg无法选举权威日志和进入active状态,如果强行拉起osd,会导致承担相同pg数据的其他osd异常自杀退出。
处理方法
如果当前osd还没有离线,只是处于部分pg存在incomplete状态。
查看该pg query。如果阻塞部分提示信息为:
peering_blocked_by_history_les_bound
也就是说pg状态卡在检查历史pg log阶段。
可以通过tell注入或者ceph.conf持久化来绕过,
ceph tell osd.* injectargs '--osd_find_best_info_ignore_history_les=true'
这样在peering时不会再检查历史pglog的最后一次peering成功时的epoch记录。(不检查历史记录可能会导致选举的权威pg本身数据有可能不是最新最大最完整,但损失会比整个pg丢失小很多。)
然后对处于异常状态的pg,down一下主osd,或者执行ceph osd repeer重新一下异常pg。可能pg状态会更新成功。
如果此前osd已经离线,需要按照日志,一步一步回查,检查具体冲突的pg,然后使用ceph-objectstore-tool将异常pg从相关osd上全部export出来(如果是三副本,则为三份pgdata,使用ceph-objectstore-tool工具时,需要停止osd进程
ceph-objectstore-too --op export --pgid $pgid --data-path /var/lib/ceph/osd/ceph-$osdid --id=$pgid --file /tmp/$pgid.data
如果三副本pgid为1.111,pg upset为[0,1,2]那么该pg在三个osd中的id均为1.111
如果是纠闪码(假如是2+1),pg upset为[0,1,2],该pg在三个osd中的pgid有点区别,因为纠删码是有序的,而副本是无序的。pgid分别为 1.111s0,1.111s1,1.111s2
将无法启动的osd中的pg删除
ceph-objectsotre-tool --op remove --pgid $pgid --data-path /var/lib/ceph/osd/ceph-$osdid --id=$osdid --force
如果是副本
同时将其余副本pg进行手动比较,一般我们选择大的作为权威pg(保留的pg越大丢失的数据自然越少),将该pg拷贝到其他节点并import至其他osd。然后进行mark complete。最后拉起所有osd
ceph-objectstore-tool --op export --pgid $pgid --data-path /var/lib/ceph/osd/ceph-$osdid --id=$osdid --file /tmp/$pgid.data
ceph-objectstore-tool --op mark-complete --pgid $pgid --data-path /var/lib/ceph/osd/ceph-$osdid --id=$osdid
如果是纠删码,移除完异常osd上pg后,mark其余osd上的pg,尝试拉起。
最后osd全部起来后,仍然会有告警pg存在unfound obj或者pg状态为recover_unofund。
此时只能选择丢失部分数据恢复集群整体健康。
ceph pg $pgid mark_unfound_lost delete
最差的情况
如果真到这种情况,已经不容乐观了,最好找专业人士处理,并做好数据大量丢失准备。
当故障已经蔓延到多个osd,最终产生连锁,启动一个osd必然会导致其他osd离线时,根据日志和监控,尝试找到osd依次离线的顺序,自后至前启动osd,最后保证尽可能多的osd在线。
例如osd.0和osd.1最先退出,osd.0启动会导致osd.2和osd.3离线,osd.1启动会导致osd.4和osd.5离线,启动osd.2会导致osd.1离线。
这种情况比较简单,自后向前启动,最后保持osd.0和osd.1不要启动,此时为集群pg active最多的状态。
此时集群中必然存在down或者stale状态的pg,这部分pglog严重受损,可能所有pg数据都无法恢复,且启动离线osd会导致集群状态进一步恶化,为保证尽快恢复集群和大部分数据。只能忍痛将这些pg从异常osd上export-remove掉,然后再拉起离线osd(因为dow的pg已经从down osd上拉起,启动这些osd时已经不会load这些pg了,也不会和集群上存在这些pg的osd产生冲突)。拉起后仍会有pg incomplete,但不会存在不active得pg了,集群io可以恢复。不一致和不完整得pg按照正常处理逻辑处理即可。
这样可以使得集群所有osd在线,且最大化保全集群数据,最快恢复集群io。
尽可能避免
- 关注社区更新,使用稳定版(大部分都是很多历史老集群数据,不方便迁移,导致版本过老)
- 定期巡检,及时告警,早发现早处理,避免影响扩大
- 定期和专业人士沟通,进行维保,避免出现问题是,误操导致集群进入更危险得状态。
- 按照专业人士建议,进行集群部署规划,网络、pgnum、block/db/wal等配置,保障生产得最佳实践。
- 数据做好多级备份