注意

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

对等

概念

Peering

使存储放置组(PG)的所有 OSD 就该 PG 中所有对象的状态以及与这些对象相关的所有元数据达成一致的过程。两个 OSD 可以就放置组中对象的状态达成一致,但仍不一定拥有最新内容。

Acting set(活动集)

负责特定 PG 的 OSD 的有序列表(或在某个纪元时负责的 OSD 列表)。

Up set(启动集)

根据 CRUSH,在特定纪元负责特定 PG 的 OSD 的有序列表。这与活动集相同,除非活动集已通过 OSDMap 中的 PG temp 被明确覆盖。

PG temp(临时 PG)

在回填主 OSD 时使用的临时放置组活动集。假设活动集是 [0,1,2] 并且我们处于 active+clean 状态。现在假设发生了一些事情,活动集变为 [3,1,2]。在这种情况下,OSD 3 是空的,无法提供读取服务,尽管它是主节点。osd.3 将通过使用 MOSDPGTemp 消息向监视器请求 [1,2,3]PG temp 来响应,osd.1 将暂时成为主节点。osd.1 将选择 osd.3 作为回填对等节点,并继续提供读取和写入服务,同时 osd.3 被回填。回填完成后,PG temp 被丢弃。活动集变回 [3,1,2]osd.3 成为主节点。

current interval(当前间隔)past interval(过去间隔)

OSD 映射纪元序列,在此期间特定 PG 的活动集启动集没有变化。

primary(主节点)

活动集中负责协调对等的成员。唯一接受客户端对放置组中对象发起写入的 OSD。按照惯例,主节点是活动集的第一个成员。

replica(副本)

放置组的活动集中的非主 OSD。副本已被识别为非主 OSD,并已由主节点激活

stray(流浪者)

不是当前活动集成员且尚未被告知删除其特定放置组副本的 OSD。

recovery(恢复)

确保 PG 中所有对象的副本都在活动集中的所有 OSD 上的过程。执行对等后,主节点可以开始接受写入操作,并且恢复可以在后台进行。

PG info(PG 信息)

有关 PG 创建纪元、对 PG 的最近写入的版本、上次启动纪元上次清理纪元以及当前间隔开始的基本元数据。任何关于 PG 的 OSD 间通信都包含 PG info,这样任何知道 PG 存在(或曾经存在)的 OSD 都会有一个 last epoch cleanlast epoch started 的下限。

PG log(PG 日志)

对 PG 中对象进行的最新更新列表。在活动集中的所有 OSD 都确认更改后,可以截断这些日志。

missing set(缺失集)

尚未更新其内容以匹配日志条目的所有对象的集合。缺失集由每个 OSD 整理。缺失集以 <OSD,PG> 为基础进行跟踪。

Authoritative History(权威历史记录)

一套完整且完全有序的操作,用于将 OSD 的放置组副本更新到最新。

epoch(纪元)

(单调递增的)OSD 映射版本号。

last epoch start(上次启动纪元)

给定放置组的活动集中的所有节点就权威历史记录达成一致的最后一个纪元。在上次启动纪元开始时,对等被认为已成功完成。

up_thru(直至...启动)

在主节点成功完成对等过程之前,它必须通过让监视器在 OSD 映射中设置其 up_thru 来通知监视器,它在当前 OSD 映射纪元中是存活的。这有助于对等忽略以前的活动集,对于这些活动集,对等从未在某些故障序列(例如下面的第二个间隔)之后完成,例如:

  • 活动集 = [A,B]

  • 活动集 = [A]

  • 活动集 = [] 很快之后(例如,同时发生故障,但交错检测)

  • 活动集 = [B] (B 重新启动,A 没有)

last epoch clean(上次清理纪元)

给定放置组的活动集中的所有节点完全是最新的最后一个纪元(这包括 PG 的日志和 PG 的对象内容)。此时,恢复被认为已完成。

对等过程描述

黄金法则是,对任何 PG 的写入操作只有在被该 PG 的活动集的所有成员持久化后才能向客户端确认。这意味着,如果我们能与自上次成功对等以来每个活动集的至少一个成员通信,那么就会有人记录自上次成功对等以来的每一次(已确认的)操作。这意味着当前主节点应该能够构建和传播新的权威历史记录

同样重要的是要理解 OSD 映射(所有已知 OSD 及其状态的列表,以及有关放置组的一些信息)在对等过程中的作用

当 OSD 启动或停止(或被添加或删除)时,这有可能影响许多放置组的活动集

在主节点成功完成对等过程之前,OSD 映射必须反映 OSD 在当前间隔的第一个纪元时是存活且正常的。

只有在成功对等后才能进行更改。

因此,新的主节点可以使用最新的 OSD 映射以及过去映射的最新历史记录来生成一组过去间隔,从上次启动纪元开始,以确定在成功对等之前必须咨询哪些 OSD。过去间隔的集合以上次启动纪元为界,即我们知道对等完成的最新的过去间隔。OSD 首次发现 PG 存在的过程是通过交换 PG info 消息,因此 OSD 始终有一个 last epoch started 的下限。

高级过程是让当前 PG 主节点执行以下操作:

  1. 获取最新的 OSD 映射(以识别所有感兴趣的活动集的成员,并确认我们仍然是主节点)。

  2. 生成自上次启动纪元以来的过去间隔列表。考虑那些 up_thru 大于第一个间隔纪元且小于最后一个间隔纪元的 OSD 映射的子集;也就是说,那些在活动集更改为另一组 OSD 之前对等可能已完成的子集。

    成功的对等将要求我们能够联系到每个过去间隔活动集中的至少一个 OSD。

  3. 向该列表中的每个节点询问其 PG info,其中包括对 PG 的最新写入,以及 last epoch started 的值。如果我们了解到比我们自己的更新的 last epoch started,我们可以修剪较旧的过去间隔并减少我们需要联系的对等 OSD。

  4. 如果其他任何人拥有我没有的操作(在其 PG 日志中),指示他们向我发送缺失的日志条目,以便主节点的 PG log 是最新的(包括最新的写入)。

  5. 对于当前活动集的每个成员

    1. 向它询问自上次启动纪元以来的所有 PG 日志条目副本,以便我验证它们是否与我的匹配(或者知道我将要告诉它删除哪些对象)。

      如果集群在操作被活动集的所有成员持久化之前发生故障,并且随后的对等没有记住该操作,并且一个记住该操作的节点稍后重新加入,其日志将记录与故障后重建的权威历史记录不同的(发散的)历史记录。

      由于发散事件未记录在该活动集的其他日志中,因此它们未向客户端确认,丢弃它们没有坏处(以便所有 OSD 在权威历史记录上达成一致)。但是,我们将不得不指示存储来自发散更新数据的任何 OSD 删除受影响的(现在被认为是伪造的)对象。

    2. 询问它的缺失集(在其 PG 日志中记录的对象更新,但它没有新数据)。这是在接受写入之前必须完全复制的对象列表。

  6. 此时,主节点的 PG 日志包含放置组的权威历史记录,并且 OSD 现在有足够的信息来更新活动集中的任何其他 OSD。

  7. 如果当前 OSD 映射中的主节点的 up_thru 值不大于或等于当前间隔的第一个纪元,则向监视器发送请求以更新它,并等待直到收到反映更改的更新的 OSD 映射。

  8. 对于当前活动集的每个成员

    1. 向它们发送日志更新,使它们的 PG 日志与我自己的(权威历史记录)保持一致……这可能涉及决定删除发散对象。

    2. 等待确认它们已持久化 PG 日志条目。

  9. 此时,活动集中的所有 OSD 都同意所有元数据,并且(在未来的任何对等中)将返回所有更新的相同帐户。

    1. 开始接受客户端写入操作(因为我们对正在接受这些更新的对象的状态达成一致)。但是请注意,如果客户端尝试写入对象,它将被提升到恢复队列的前面,并且写入将在其完全复制到当前活动集之后应用。

    2. 更新我们本地 PG info 中的 last epoch started 值,并指示其他活动集 OSD 执行相同的操作。

    3. 开始拉取其他 OSD 拥有但我没有的对象数据更新。我们可能需要查询 last epoch started(上次对等完成时间)之前和 last epoch clean(上次恢复完成的纪元)之后的额外过去间隔中的 OSD,以查找所有对象的副本。

    4. 开始将对象数据更新推送到尚未拥有它们的其他 OSD。

      我们从主节点推送这些更新(而不是让副本拉取它们),因为这允许主节点在向副本发送更新写入之前确保副本具有当前内容。这也使得单个读取(来自主节点)可以用于将数据写入多个副本。如果每个副本都进行自己的拉取,数据可能必须读取多次。

  10. 一旦所有副本存储了所有对象的所有副本(在当前纪元开始之前存在),我们就可以更新 PG info 中的 last epoch clean,并且我们可以解散所有流浪者副本,允许它们删除不再属于活动集的对象的副本。

    在此之前我们不能解散流浪者,因为那些流浪者之一可能持有旧对象的唯一幸存副本(所有副本都在它们被复制到当前活动集的成员上之前消失了)。

生成状态模型

使用 gen_state_diagram.py 脚本生成最新对等状态模型的副本

$ git clone https://github.com/ceph/ceph.git
$ cd ceph
$ cat src/osd/PeeringState.h src/osd/PeeringState.cc | doc/scripts/gen_state_diagram.py > doc/dev/peering_graph.generated.dot
$ sed -i 's/7,7/1080,1080/' doc/dev/peering_graph.generated.dot
$ dot -Tsvg doc/dev/peering_graph.generated.dot > doc/dev/peering_graph.generated.svg

示例状态模型

../../_images/peering_graph.generated.svg

由 Ceph 基金会为您呈现

Ceph 文档是由非营利性 Ceph 基金会 资助和托管的社区资源。如果您希望支持这项工作和我们的其他努力,请考虑 立即加入