https://blog.csdn.net/changtao381/article/details/51626285
在上周的ceph-devel 邮件列表中,有人提到了在测试的环境中出现了 unfound object 的状态,本文试图分析这种情况发生的原理。
首先介绍一下什么是 unfoud object ? unfoud object 对象就是 完成了peering 过程,各个副本达成了一致的状态。 简单的说,就是在副本中确定了对象的正确的版本。 在recovery 过程中,要去确定该正确的版本对象 所在的osd上的位置,如果没有找到 拥有该正确 版本的 osd,该对象就被标记为 unfoud object。
通过上述分析可知,unfoud object 就是完成了peering 过程,但在 recovery 过程中找不到该对象正确版本所在的osd,无法恢复。
场景1
一个pg,两副本,其acting set 为 [osd1,osd2]
此时pg处于recovery状态,osd1上有 缺失的对象 (missing object),等待恢复。 osd2 上有完整的对象,正常情况下从osd2上同步osd1上缺失的对象即可。 这时候osd2 down掉后。 pg 重新开始peering,acting set 为[osd1,osd3],
osd1保存了权威的日志记录,peering可以完成。在恢复阶段,osd1上有缺失的对象无法恢复, 这些缺失的对象就处于 unfound object状态。
这种情况发生的实质就是: pg只有两副本,在rocovery 状态中,只有osd2是一个完整的副本。如果唯一一个拥有完整副本的osd2 也down 了, 必然出现unfoud 对象。
场景2
当有request被阻塞时, 剔除以osd。
pool 的size 为3 , min_size 为2 。给集群添加负载,使集群会出现 “requests are blocked > 32 sec” 的提示。 此时剔除一个盘,其方法如下:
移除节点操作如下:
ceph osd out osd.id
service ceph osd.1 stop
ceph osd crush remove osd.id 和host
ceph rm osd.id
ceph auth del osd.id
分析如下:
pg 的acting set 为 [osd1, osd2, osd3],当执行 ceph osd out osd.1时:
该pg上对象objA:
osd1 objA(22) objA(23) 已完成
osd2 objA(22) objA(23) 正在完成
osd3 objA(22) objA(23 正在完成
- 1
- 2
- 3
- 4
此时,osd1完成的对象objA 的版本22 和 23 的操作。而副本osd2和osd3 的对象objA的 22 和 23 操作都没有完成。
osd1被标记为out后,osd2 和 osd3 首先都收到了 monitor发送来的 osdmap的变化。 pg的 acting set 变为[osd2, osd3, osd4], pg开始触发peering,在peering的过程中能够从osd1上获取pg log(由于osd标记为out,可以继续访问到), 确定对象ojbA的版本为23.
当recovery 时, osd1 被停止,对象objA的23版本数据无法读出,就标记为unfound object。
从上可知,objA的23版本只在以 osd1上存在一个唯一副本。它参与了peering 过程,从而获取了该对象的权威版本,但是随时把该osd down后,就无法获取数据导致。
有以上原因分析可知:
1)当管理员缩容时,建议标记为osd out后,等待ceph集群处于clean 状态,确定请求没有被阻塞时,才能停止osd
2)当有 request are blocked 的情况下,osd失效导致产生 unfound object。 在这种情况,正如情况2 中的例子,无论是版本22,或者23,数据都没有应答给客户端。所以最终结果是版本22或者23或者最后一次写入成功的版本都可以接受。