注意

本文档适用于 Ceph 开发版本。

防止陈旧读取

我们在向客户端发送ACK之前同步写入所有副本,这限制了写入路径中不一致的可能性。然而,默认情况下,我们仅从每个PG的领导/主OSD提供读取服务,客户端将使用其拥有的OSDMap来选择从中读取的OSD。在大多数情况下,这是没问题的:要么客户端映射是正确的,要么我们认为是对象的主OSD知道它不再是主OSD了,并且可以向客户端提供更新的映射,该映射指示更新的主OSD。

关键在于确保这一点始终是真的。特别是,我们需要确保一个被隔离在其同伴之外且未了解映射更新的OSD不会在新的主OSD可能被允许写入的任何时间点后继续为类似陈旧的客户端服务读取请求。

我们通过一个类似于读取租约的机制来实现这一点。每个池可能有一个属性来定义这个租约的持续时间,尽管默认情况下我们只是将其设置为read_lease_interval property which defines how long this is, although by default we simply set it to osd_pool_default_read_lease_ratio(默认:.8)倍的osd_heartbeat_grace。(这样,租约通常在我们标记失败的OSD时已经过期了。)

readable_until

主OSD和副本都跟踪几个值:

  • readable_until是我们允许服务(读取)请求的时间长度,直到我们的“租约”过期。

  • readable_until_ub是任何在执行集中的OSD的可读性的上限。readable_until for any OSD in the acting set.

主OSD通过向副本发送pg_lease_t消息来管理这两个值,这些消息会增加上限。一旦所有执行OSD都确认它们看到了更高的界限,主OSD就会增加它自己的readable_until并在随后的pg_lease_t消息中共享这个。由此产生的不变量是任何执行OSD的readable_until总是 <= 任何执行OSD的readable_until_ub.

为了避免任何与时钟偏移相关的问题,我们使用单调时钟(这些时钟仅在本机准确且不受时间调整的影响)来管理这些租约。同伴OSD计算OSD本地时钟之间的差值的上下限,允许主OSD基于其本地时钟共享时间戳,而副本将这个时间戳转换为它们自己的本地时钟的适当界限。

先前间隔

每当有间隔变化时,我们需要对先前间隔中任何OSD的readable_until值有一个上限。该间隔中的所有OSD都有这个值 (readable_until_ub),并在对等过程中共享它作为

由于对等可能涉及在之前没有通信的OSD,并且可能没有它们时钟差值的界限,所以在上限过期之前,在pg_history_t中共享的界限是一个简单的持续时间。这意味着由于对等消息的传输时间,界限会随着时间的推移而滑动,但这通常相当短,并且将界限移到时间更晚的位置是安全的,因为它是一个上限。在PG活跃期间,

PG“迟缓”状态

如果对等完成但先前间隔的OSD可能仍然可读,PG将进入pg_lease_tpg_lease_ack_t消息会定期交换。但是,如果客户端请求进来并且租约已经过期(readable_until已经过去),PG将进入LAGGY状态,请求将被阻止。一旦租约更新,请求将被重新排队。

PG“等待”状态

If peering completes but the prior interval’s OSDs may still be readable, the PG will go into the WAIT状态,直到经过足够的时间。在此期间,任何OSD请求都将被阻止。在此状态下可以进行恢复,因为对象逻辑的用户可见内容不会改变。

死OSD

一般来说,我们需要等待先前间隔的OSD知道它们不再应该是可读的。如果一个OSD已知已经崩溃(例如,因为进程不再运行,这可能是因为我们收到一个ECONNREFUSED错误),那么我们可以推断它不可读。

类似地,如果一个OSD被标记下来,收到一个告诉它这个信息的映射更新,然后通知监视器它知道它被标记下来,我们同样可以推断它不再为先前间隔提供服务。

When a PG is in the WAIT状态,它将监视新的映射以查找OSD的dead_epoch值,该值指示它们知道自己的死亡状态。如果先前间隔中所有下线的OSD都这样知道,我们就可以提前退出WAIT状态。

由 Ceph 基金会带给您

Ceph 文档是一个社区资源,由非盈利的 Ceph 基金会资助和托管Ceph Foundation. 如果您想支持这一点和我们的其他工作,请考虑加入现在加入.