注意
本文档适用于 Ceph 的开发版本。
Map 和 PG 消息处理
概述
OSD 负责将传入的消息路由到 PG,在某些情况下,如果需要,还会创建 PG。
PG 消息通常有两种类型:
对等消息 (Peering Messages)
操作/子操作 (Ops/SubOps)
消息可能会被丢弃或延迟有多种方式。重要的是,消息延迟不能导致在到达相关 PG 处理逻辑的途中违反某些消息排序要求:
指向同一对象的操作不得重新排序。
对等消息不得重新排序。
子操作不得重新排序。
MOSDMap
MOSDMap 消息可能来自监视器或其他 OSD。收到后,OSD 必须执行以下几项任务:
将新 map 持久化到 filestore。一些 PG 操作依赖于访问可追溯到 PG 上次 clean 时的 map。
更新并持久化 superblock。
更新与当前 map 相关的 OSD 状态。
通过 OSDService 将新 map 暴露给 PG 进程。
由于池移除而移除 PG。
排队虚拟事件以触发 PG map 追赶。
在处理事件之前,每个 PG 都会在 process_peering_events 期间异步追赶当前发布的 map。因此,不同的 PG 可能对“当前”map 有不同的视图。
这种设计的一个后果是,包含来自多个 PG 的子消息(MOSDPGInfo、MOSDPGQuery、MOSDPGNotify)的消息必须为每个子消息标记 PG 的 epoch,并为整个消息标记 OSD 当前发布的 epoch。
MOSDPGOp/MOSDPGSubOp
参见 OSD::dispatch_op、OSD::handle_op、OSD::handle_sub_op
MOSDPGOp 用于客户端发起 rados 操作。MOSDSubOp 用于 OSD 之间协调大多数非对等活动,包括复制 MOSDPGOp 操作。
OSD::require_same_or_newer map 检查当前 OSDMap 是否至少与消息上指示的 map epoch 一样新。如果不是,消息会通过 OSD::wait_for_new_map 排队到 OSD::waiting_for_osdmap 中。注意,这不会违反上述条件,因为任何两条消息都将按接收顺序排队,并且如果接收到的消息 epoch 为 e0,则来自同一源的后续消息的 epoch 必须至少为 e0。请注意,来自同一 OSD 的两个 PG 对于这些目的而言被视为单 PG 消息的不同来源。也就是说,来自不同 PG 的消息可能会被重新排序。
MOSDPGOp 遵循以下过程:
OSD::handle_op:验证权限和 crush 映射。如果它们未连接且客户端无法获取回复,则丢弃请求(参见 OSD::op_is_discardable)参见 OSDService::handle_misdirected_op 参见 PG::op_has_sufficient_caps 参见 OSD::require_same_or_newer_map
OSD::enqueue_op
MOSDSubOp 遵循以下过程:
OSD::handle_sub_op 检查发送方是否为 OSD
OSD::enqueue_op
OSD::enqueue_op 调用 PG::queue_op,后者在调用 OpWQ::queue 之前检查 waiting_for_map,OpWQ::queue 将操作添加到负责处理它的 PG 的队列中。
然后最终调用 OSD::dequeue_op,并对 PG 加锁。此时,操作被传递给 PG::do_request,它会检查:
PG map 是否足够新 (PG::must_delay_op)
请求操作的客户端是否具有足够的权限 (PG::op_has_sufficient_caps)
操作是否不应被丢弃 (PG::can_discard_{request,op,subop,scan,backfill})
PG 是否处于 active 状态 (PG::flushed boolean)
操作是否为 CEPH_MSG_OSD_OP 且 PG 处于 PG_STATE_ACTIVE 状态而非 PG_STATE_REPLAY
如果未满足这些条件,操作要么被丢弃,要么排队等待稍后处理。如果所有条件都满足,则根据其类型处理操作:
CEPH_MSG_OSD_OP 由 PG::do_op 处理
MSG_OSD_SUBOP 由 PG::do_sub_op 处理
MSG_OSD_SUBOPREPLY 由 PG::do_sub_op_reply 处理
MSG_OSD_PG_SCAN 由 PG::do_scan 处理
MSG_OSD_PG_BACKFILL 由 PG::do_backfill 处理
CEPH_MSG_OSD_OP 处理
PrimaryLogPG::do_op 处理 CEPH_MSG_OSD_OP op 并将其排队:
如果它是针对指定 snapid 的 CEPH_OSD_OP_PGLS 且某些对象更新仍然缺失,则排队到 wait_for_all_missing 中
如果操作可能写入但 scrubbers 正在工作,则排队到 waiting_for_active 中
如果操作需要一个对象或 snapdir 或仍然缺失的特定 snap,则排队到 waiting_for_missing_object 中
如果操作可能写入 degraded 的对象或 snapdir,或者另一个对象阻止了它(“blocked_by”),则排队到 waiting_for_degraded_object 中
如果操作需要一个将在 backfill 完成后可用的对象,则排队到 waiting_for_backfill_pos 中
如果正在等待来自另一个 OSD 的 ack,则排队到 waiting_for_ack 中
如果操作正在等待写入完成,则排队到 waiting_for_ondisk 中
对等消息 (Peering Messages)
参见 OSD::handle_pg_(notify|info|log|query)
对等消息用两个 epoch 标记:
epoch_sent:发送消息时的 map epoch
query_epoch:触发消息发送时的 map epoch
在没有触发消息的情况下,这两个 epoch 相同。如果相关 PG 已进入新的 epoch(参见 PG::old_peering_evt, PG::queue_peering_event),我们将丢弃消息的 query_epoch。通知 (notifies)、信息 (infos)、日志 (logs) 和查询 (queries) 都作为 PG::PeeringMachine 事件处理,并由 PG::CephPeeringEvts 的 PG::queue_* 封装,其中包含创建的状态机事件以及 epoch_sent 和 query_epoch,以便在插入和从队列中移除时通用地检查 PG::old_peering_message。
注意,通知、日志和信息可以触发 PG 的创建。参见 OSD::get_or_create_pg。