1.总体架构
rgw 作为对象存储网关系统, 一方面扮演RADOS集群客户端角色, 为对象存储应用提供数据存储; 另一方面扮演HTTP 服务端角色, 接受并解析互联网传送的数据。
通过 HTTP 协议与 Swift 和 S3 应用通讯, 后端与 librados 结合, 通过socket 与 RADOS 集群通讯。 RGW 支持目前主流的WEB服务器, 包括 Civetweb、 APACHE、 Nginx等, 其中Civetweb 是一个C++库, 可以内嵌到RGW框架中, 是RGW默认的WEB服务器; Apache 与 Nginx 需要以独立进程存在, 收到请求后, 通过RGW注册的监听端口将请求转发到RGW上处理。
2.相关概念及定义
2.1几个内部概念
- zone:包含多个RGW实例的一个逻辑概念。zone不能跨集群。同一个zone的数据保存在同一组pool中。
- zonegroup:一个zonegroup如果包含1个或多个zone。如果一个zonegroup包含多个zone,必须指定 一个zone作为master zone,用来处理bucket和用户的创建。一个集群可以创建多个zonegroup,一个zonegroup也可以跨多个集群。
- realm:一个realm包含1个或多个zonegroup。如果realm包含多个zonegroup,必须指定一个zonegroup为master zonegroup,用来处理系统操作。一个系统中可以包含多个realm,多个realm之间资源完全隔离。
2.2几个外部概念
- 用户: 对象应用的使用者。 一个用户拥有一个或多个存储通。
- 存储桶: 存储桶是对象的容器。 是为了方便管理和操作具有同一属性的一类对象引入的一层管理单元。
- 对象: 对象是对象存储系统数据组织和存储的基本单位,一个对象包括数据和元数据。
尽管不同的对象存储系统在设计上有所不同,但是对外呈现的基础数据实体大同小异。比如Amazon S3的基础数据实体包含user,bucket,object与以上的用户,存储桶,对象一致。而openStack Swift将用户的概念细分为account和user.
2.2.1 用户
一个用户包含的信息包括用户认证信息、 访问控制权限信息和配额信息。
用户认证
要了解用户认证信息有哪些,必须要先了解RGW的认证机制, RGW针对S3 API和Swift API采用不同的认证机制。
S3认证过程
应用在发送请求前, 使用用户私有密钥(secret_key), 请求内容, 采用与RGW网关约定好的算法计算出数字签名后, 将数字签名以及用户访问密钥(access_key) 封装在请求中发送给RGW网关。
RGW网关收到请求后, 使用用户访问密钥作为索引从RADOS集群中读取用户信息, 并从用户信息中获取用户私有密钥。
使用用户私有密钥请求内容等, 采用与应用约定好的算法计算数字签名。
判断RGW生成的数字签名与请求的签名是否匹配, 如果匹配, 则认为请求是真实的, 用户认证通过。
可以看出,在S3认证机制中,用户信息中必须包含访问密钥和私有密钥信息
Swift认证过程
- 应用在发出真正的操作请求前, 向RGW网关请求一个令牌(注: 该令牌有有效期, 过了有效期后, 需要重新请求新的令牌)。
- RGW收到令牌请求后, 使用子用户ID作为索引从RADOS集群中读取出子用户信息, 并从子用户信息中获取到Swift私有密钥(swift_key) 生成一个令牌返回给应用。
- 应用后续操作中携带该令牌, RGW收到操作请求后, 采用与步骤2相同的方式生成一个令牌, 并判断与请求中的令牌是否一致, 如果一致, 身份验证通过。
可以看出,Swift认证机制中必须包含Swift私有密钥。
RGW将用户信息保存在Rados对象的数据部分,一个用户对应RADOS对象,由于大部分情况下,我们需要使用用户ID作为所以获取用户信息,因此该对象以用户ID命名(RADOS通过‘‘pool名+对象吗’’来查询一个对象)
RGW需要将访问密钥,字用户,email跟用户信息所在的RADOS对象建立索引关系,针对这种情况,RGW采用了二级索引的方式,及分别创建以用户访问密钥,子用户,email命名的三个对象(即索引对象),并将用户ID保存在对象的数据部分,当需要某个索引查询用户信息时,所有从所有对象中读出用户ID,然后使用用户ID作为所以读取用户信息。
2.2.2存储桶
一个存储桶对应要一个RADOS对象。一个存储桶包含的信息包括两类,一类是对RGW网关透明的信息,这类信息通常指用户自定义的元数据,RGW网关直接将这些信息保存在扩展属性中,一个KV键值对对应一个扩展属性条目,另一类是RGW网关关注的信息,这类信息包括存储桶中对象的存储策略、存储桶中索引对象的数目以及应用对象和索引对象的映射关系、存储桶的配额等,此类信息由数据结构RGWBucketInfo管理。
在创建存储桶时,RGW网关会同步创建一个或多个索引(index)对象,用于保存该存储桶下的对象列表,以支持查询存储桶对象列表(List Bucket)功能,因此在存储桶中有心的对象上传或者删除的时候必须更新索引对象。
2.2.3对象
应用上传的对象包括数据和元数据两部分,数据部分保存在一个火多个RADOS对象的数据部分,元数据保存在其中一个RADOS对象的拓展属性中。RGW对单个对象提供了两种上传接口:整体上传和分段上传。
2.2.4Pool
RGW中含有多种pool,通过以下命令可以获得:
rados lspools
rbd
.rgw.root
default.rgw.control
default.rgw.data.root
default.rgw.gc
default.rgw.log
default.rgw.
users
.uid
default.rgw.
users
.keys
default.rgw.
users
.swift
default.rgw.buckets.index
default.rgw.buckets.data
各种pool的作用
- .rgw.root 包含realm,zonegroup和zone
- default.rgw.control在RGW上电时,在control pool创建若干个对象用于watch-notify,主要作用为当一个zone对应多个RGW,且cache使能时, 保证数据的一致性,其基本原理为利用librados提供的对象watch-notify功能,当有数据更新时,通知其他RGW刷新cache, 后面会有文档专门描述RGW cache
- default.rgw.data.root:包含bucket和bucket元数据,bucket创建了两个对象一个:一个是< bucket_name > 另一个是.bucket.meta.< bucket_name >.< marker > 这个marker是创建bucket中生成的。同时用户创建的buckets在.rgw.buckets.index都对应一个object对象,其命名是格式:.dir.< marker
- default.rgw.gc:RGW中大文件数据一般在后台删除,该pool用于记录那些待删除的文件对象
- default.rgw.log:各种log信息
- default.rgw.users.uid:保存用户信息,和用户下的bucket信息
- default.rgw.users.keys:包含注册用户的access_key
- default.rgw.users.swift:包含注册的子用户(用于swift)
- default.rgw.buckets.index:包含bucket信息,和default.rgw.data.root对应
- default.rgw.buckets.data:包含每个bucket目录下的object
default.rgw.data.root,default.rgw.buckets.index和default.rgw.buckets.data 之间有直接的联系
3.功能实现
这里主要是介绍RGW对外提供的功能,I/O路径以及存储桶创建,对象上传下载等几个功能的实现。
3.1功能特性
对象存储最基本的功能呢包括用户,存储桶,对象的增删改查等,RGW网关最近几年在不断地跟进和对齐AmazonS3和OpenStack Swift功能。目前RGW网关兼容的S3和Swift的API见链接:
- https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html
- https://docs.openstack.org/swift/latest/api/object_api_v1_overview.html
3.1.1I/O路径
RGW网关使用OP线程处理应用的I/O请求(OP线程在上电时创建,当前端WEB服务器为Civetweb时,通过修改配置项rgw_thread_pool_size指定OP线程数目)。OP线程内部逻辑可分为HTTP前端,REST API通用处理层、API操作执行层、RADOS接口适配层与librados接口层等几个关键流程。OP线程从HTTP前端收到I/O请求后,首先在REST API通用处理层,从HTTP语义中解析出S3或Swift数据并进行一系列的检查,检查通过后,根据不同API操作请求执行不同的处理流程,如需从RASDOS集群获取数据或这往RADOS集群写入数据,则通过RGW与RADOS接口适配层调用librados接口将请求发送到RADOS集群中获取或写入相应数据,完成整个I/O过程。
RGW实例内部I/O路径如下图:
REST API通过处理层的关键步骤如下图所示,大概分为用户认证,用户/存储桶/对象的访问控制和用户/存储桶配额检查等几项。
这里以Civetweb作为Web服务器的Request处理流程如下:
1.在main函数中若选择使用civetweb作为前端Web服务器,在设置相关配置后调用run函数启动civetweb.
run函数中在mg_start函数启动web server.该函数还会传入一个回调函数,用于处理每个request请求。
int
RGWCivetWebFrontend::run()
{
...
struct
mg_callbacks cb;
memset
((
void
*)&cb, 0,
sizeof
(cb));
/* 回调函数设置 */
cb.begin_request = civetweb_callback;
cb.log_message = rgw_civetweb_log_callback;
cb.log_access = rgw_civetweb_log_access_callback;
/* 启动服务 */
ctx = mg_start(&cb,
this
, options.data());