Rados 网关的数据布局¶
虽说源代码才是终极手册,但本文档能让新开发者更快地了解实现细节。
简介¶
Swift 提供了名为容器( container )的东西,在这里它等价于桶( bucket )概念。也可以说 RGW 用桶实现了 Swift 的容器功能。
本文档没有考虑 RGW 如何操作这些数据结构,比如说,为了序列化怎样使用 encode() 和 decode() 方法、等等。
概念预览¶
虽然 RADOS 只知道 pool 、对象(及其 xattr )和 omap[1] ,但是从概念上 RGW 把它的数据组织成了三种不同的类型:元数据、桶索引和数据。
元数据¶
我们有三“部分”元数据: user 、 bucket 、和 bucket.instance 。你可以用下面的命令调查这几种元数据:
$ radosgw-admin metadata list
$ radosgw-admin metadata list bucket
$ radosgw-admin metadata list bucket.instance
$ radosgw-admin metadata list user
$ radosgw-admin metadata get bucket:<bucket>
$ radosgw-admin metadata get bucket.instance:<bucket>:<bucket_id>
$ radosgw-admin metadata get user:<user> # get or set
前述命令中的变量含义如下:
user: 保存着用户信息
bucket: 保存着桶名与其例程 ID 的映射关系
bucket.instance: 保存着桶例程信息 [2]
每个元数据条目都存储于独立的 rados 对象。 实现细节见下文。
要注意,元数据没被索引过。所以,罗列元数据部分的时候,其实是在包含它们的存储池里做 rados pgls 操作。
桶索引¶
它是另一种元数据,也是独立保存的。桶索引是在 rados 对象里保存的键值映射,默认情况下,每个桶占用一个 rados 对象,但是从 Hammer 起,这些映射可以分片存入多个 rados 对象。这个映射本身是保存在 omap 里的,并与各 rados 对象关联。各 omap 的键名是对象名、值是此对象的基本元数据——罗列此桶时显示的就是元数据。另外,各 omap 都有一个头,保存着桶的一些统计元数据(如对象数量、总尺寸等等)。
另外,桶索引里还有其它信息,是保存在其它键名空间里的。比如,我们可以在这里存桶索引日志、而且对于版本化的对象,有更多信息要保存。
数据¶
各个 rgw 对象的数据保存在一或多个 rados 对象里。
对象定位路径¶
访问对象时, ReST 风格的 API 要提供给 RGW 三个参数:帐户信息( S3 的访问密钥或者 Swift 的帐户名)、桶或容器名、和对象名(或键名)。当前, RGW 只用帐户信息查找用户 ID 并用于访问控制,只用桶名和对象键名就能定位存储池内的对象。
在 RGW 里,用户 ID 是个字符串,通常是用户凭据里的真实用户名,而不是其哈希值或者映射过的标识符。
访问某个用户的数据时,此用户的记录要从 default.rgw.meta 存储池内、命名空间为 users.uid 的 <user_id> 对象载入。
桶名即 default.rgw.meta 存储池内、命名空间为 root 的对象名。要载入桶记录,以便获取所谓的记号( marker ),它作为桶的唯一标识符。
对象数据位于 default.rgw.buckets.data 存储池内。对象名是 “<marker>_<key>” ,如 default.7593.4_image.png ,其中 marker 是 default.7593.4 、键名是 image.png 。正因为这些组合起来的名字没被解析过,只是传递给了 RADOS ,所以分隔符的选择就没那么重要、不会引起歧义;正因为如此,斜杠也允许作为对象名(键名)。
也可以创建并使用多个数据存储池,这样不同的用户、桶就可以默认放到不同的 rados 存储池里了,以此提供了必要的伸缩性。这样的布局和这些存储池的命名是由 policy 选项 [3] 配置的。
一个 RGW 对象可由多个 RADOS 对象组成,其中的第一个对象是头儿,它包含着元数据,像载荷清单、 ACL 、内容类型、 ETag 、和用户自定义的元数据,这些元数据是存储在 xattr 里的。为保证高效性、原子性,这个头还可以存储最多 512 KB 的对象数据。载荷清单描述了各对象是如何存储在 RADOS 对象里的。
桶和对象列表¶
某一用户的桶列表保存在 default.rgw.meta 存储池里、命名空间为 users.uid 、名为 <user_id>.buckets 的对象(如 foo.buckets )的 omap 里。在罗列桶、更新桶内容、以及更新和检索桶的统计信息(例如配额信息)时要访问这些对象。
这些 omap 条目的值位于用户可见、编码过的 cls_user_bucket_entry 类和它的嵌套类 cls_user_bucket 里面。
这些列表以桶名持久化、存储在 .rgw 存储池里面。
某一桶内所包含的对象罗列在桶索引里,这已经在前面的“桶索引”小段里说过了。在 default.rgw.buckets.index 存储池里、索引对象的默认命名规则是 .dir.<marker> 。
附注¶
[1] Omap 是个与对象相关联的键值存储,类似扩展属性与 POSIX 文件的关联一样。对象的 omap 与对象数据在物理上是分离的,但是对 RADOS 网关来说是不可见、无形的。在 Hammer 版里,每个 OSD 都有一个用于存储 omap 的 LevelDB 数据库。
[2] 在 Dumpling 版之前还没有 bucket.instance 元数据,这些信息存储在 bucket 元数据里。所以,在较老的集群里有可能碰到这样的桶。
[3] 从 Infernalis 版起,存储池的命名有所变化。与早先安装的系统相比,有些细节不太一样,具体而言,原来为每个命名空间配置了单独的存储池,现在都并入了 default.root.meta 存储池。
附录:提纲¶
已知存储池:
- .rgw.root
不确定的 region 、 zone 以及全局信息,每条使用一个对象。
- <zone>.rgw.control
notify.<N>
- <zone>.rgw.meta
多种元数据组成的多个命名空间:
- namespace: root
<bucket> .bucket.meta.<bucket>:<marker> # 参见 put_bucket_instance_info()
租户是用来区分桶的,而不是桶例程。例如:
.bucket.meta.prodtx:test%25star:default.84099.6 .bucket.meta.testcont:default.4126.1 .bucket.meta.prodtx:testcont:default.84099.4 prodtx/testcont prodtx/test%25star testcont
- namespace: users.uid
包含两种信息,存储于 <user> 对象里的单个用户信息( RGWUserInfo )、及各个用户的桶列表,储存在 <user>.buckets 对象的 omap 内。如果配置了租户,也会包含在 <user> 内,如:
prodtx$prodt test2.buckets prodtx$prodt.buckets test2
- namespace: users.email
不重要
- namespace: users.keys
47UA98JSTJZ9YAN3OS3O
这样,在认证时 radosgw 就可以通过访问密钥查寻用户。
- namespace: users.swift
test:tester
- <zone>.rgw.buckets.index
对象命名规则为 .dir.<marker> ,它们都有各自的桶索引。如果索引分片了, marker 之后的各个分片后面还要追加分片索引。
- <zone>.rgw.buckets.data
default.7593.4__shadow_.488urDFerTYXavx4yAd-Op8mxehnvTI_1 <marker>_<key>
marker 长得像 “default.16004.1” 或者 “default.7593.4” 。当前,其格式为 “<zone>.<instance_id>.<bucket_id>” ,可是一旦生成, marker 就不会再被解析,所以未来它的格式可以自由更改。