注意

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

Rados 存储桶索引

RGW 中的存储桶将其对象列表存储在存储桶索引中。每个索引条目只存储足够的元数据(大小、etag、mtime 等)以用于处理列出对象的 API 请求。这些 API 包括 S3 中的 ListObjectsV2ListObjectVersions,以及 Swift 中的 GET Container

注意

存储桶可以创建为“无索引”模式。此类存储桶没有索引,并且无法被列出。

一致性保证

RGW 保证对象操作的读写一致性。这意味着一旦客户端收到成功的写入请求响应,该写入的效果必须对后续的读取请求可见。

例如:如果 S3 客户端发送一个 PutObject 请求来覆盖一个现有对象,然后发送一个 GetObject 请求来读取它,RGW 决不能返回前一个对象的内容。它必须要么返回新对象的内容,要么返回一个后续对象写入或删除的结果。

此一致性保证适用于所有对象写入请求(PutObject、DeleteObject、PutObjectAcl 等)和所有对象读取请求(HeadObject、GetObject、ListObjectsV2 等)。

Rados 对象模型

S3/Swift 对象或“API 对象”作为 Rados 对象存储在 rgw.buckets.data 池中。每个 API 对象由一个 head 对象和零个或多个 tail 对象组成。存储桶索引对象存储在 rgw.buckets.index 池中。

写入对象时,其 head 对象最后写入。这充当了一个原子“提交”操作,使其对读取请求可见。

分片和重新分片

对于给定的存储桶,索引可以被分割成几个 Rados 对象,称为存储桶索引分片。在 RADOS 中,对同一对象的多次写入不能并行运行。通过将索引分散到更多的 Rados 对象上,我们提高了其写入并行性。对于给定的对象上传,相应的存储桶索引分片是根据对象名称的哈希值选择的。

新存储桶的默认分片数为 11,但可以在 zonegroup 的 bucket_index_max_shards 或 ceph.conf 的 rgw_override_bucket_index_max_shards 中覆盖。随着存储桶中对象数量的增长,其索引分片数也会因动态重新分片而增加。

有关存储桶索引对象布局的信息存储在 RGWBucketInfo 中,具体为 src/rgw/rgw_bucket_layout.h 中的 struct rgw::BucketLayout。重新分片逻辑在 src/rgw/driver/rados/rgw_reshard.cc 中。

索引事务

为了保持存储桶索引一致性,所有对象写入或删除都必须相应地更新索引。由于 head 对象存储在与存储桶索引不同的 Rados 对象中,我们无法通过单个 Rados 操作原子地更新两者。为了满足列出操作的 一致性保证,我们必须使用三步存储桶索引事务来协调这两个对象写入

  1. 在存储桶索引对象上准备一个事务。

  2. 写入或删除 head 对象。

  3. 在存储桶索引对象上提交事务(如果第 2 步失败则取消事务)。

对象写入和删除可能会相互竞争,因此一个给定对象可能同时有多个已准备好的事务。如果存在任何未完成的事务,RGW 会将对象条目视为“待定”状态;否则视为“已完成”状态。

此事务在 src/rgw/driver/rados/rgw_rados.cc 中实现,对象写入对应 RGWRados::Object::Write::write_meta(),对象删除对应 RGWRados::Object::Delete::delete_obj()。存储桶索引操作在 src/cls/rgw/cls_rgw.cc 中实现,对应 rgw_bucket_prepare_op()rgw_bucket_complete_op()

列表显示

列出对象时,RGW 将从存储桶索引中读取所有条目(待定和已完成)。对于任何待定条目,它必须在将该条目包含在最终列表中之前检查 head 对象是否存在。

如果 RGW 在 索引事务 中途崩溃,索引条目可能会停留在这种“待定”状态。当存储桶列表遇到这些待定条目时,它还会将 head 对象的信息发送回存储桶索引,以便它可以更新条目并解决其过时的事务。此消息称为“dir suggest”(目录建议),因为存储桶索引将其视为提示或建议。

存储桶列表在 src/rgw/driver/rados/rgw_rados.cc 中实现,对应 RGWRados::Bucket::List::list_objects_ordered()RGWRados::Bucket::List::list_objects_unordered()RGWRados::check_disk_state() 是读取 head 对象并编码建议更改的部分。相应的存储桶索引操作在 src/cls/rgw/cls_rgw.cc 中实现,对应 rgw_bucket_list()rgw_dir_suggest_changes()

S3 对象版本控制

对于已启用版本控制的存储桶,存储桶索引包含每个对象版本和删除标记的条目。除了按对象名称对索引条目排序外,它还必须按从新到旧的顺序对同一名称的对象版本排序。

RGW 为每个对象版本在 rgw.buckets.data 池中存储一个 head 对象。此 Rados 对象的 oid 是对象名称及其版本 ID 的组合。

在 S3 中,对对象名称的 GET/HEAD 请求将为您提供该对象的“当前”版本。为了支持这一点,RGW 存储了一个额外的“对象逻辑头”(olh)对象,其 oid 仅包含对象名称,充当其当前版本 head 对象的间接引用。此间接引用逻辑在 src/rgw/driver/rados/rgw_rados.cc 中实现,对应 RGWRados::follow_olh()

为了保持此 olh 对象与存储桶索引之间的一致性,索引为每个对象名称保留一个单独的“olh”条目。此条目存储对其版本的所有写入/删除的日志。在 src/rgw/driver/rados/rgw_rados.cc 中,RGWRados::apply_olh_log() 重放此日志,以保证此 olh 对象与存储桶索引收敛到相同的“当前”版本。

由 Ceph 基金会为您呈现

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