本文主要是介绍一文读懂CEPH RGW基本原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一文读懂CEPH RGW基本原理
一、RGW简介
二、RGW的组成结构
三、Rgw用户信息
四、BUCKET与对象索引信息
五、RGW对象与RADOS对象的关系
六、上传对象的处理流程
七、RGW的双活机制
八、RGW版本管理机制与CLS机制
九、结语
本文从RGW的基本原理出发,从整体上描述RGW的框架结构,突出关键结构之间的关联关系,从基础代码分析关键环节的实现细节,以达到清晰说明RGW模块“骨架”的效果。
一、RGW简介
RGW是CEPH系统的一种应用,用于对外提供对象存储服务。随着技术的发展,网络中的非结构化数据越来越多,而且数据量特别大,这些数据在技术上表现为大块的顺序读写,并且单次写入、多次读取,数据内容上传后几乎不会修改,这就提出了使用分布式技术存储这些对象数据的迫切需求。RGW是其中基于CEPH技术的一种需求实现。互联网中常见的云存储也是这类需求的具体应用。
RGW以S3协议和SWIFT协议对外提供对象存储服务,两个协议有较多的相似之处。S3协议全称为Amazon Simple Storage,源于亚马逊早期推出的云计算服务。SWIFT是OpenStack云平台的一个云存储子系统,两者的对象访问方式均以HTTP方式访问,上传对象为PUT,下载对象为GET,删除对象的接口为DELETE;但两者在用户管理、对象集合方面有些差异,S3协议采用Bucket组织对象,SWIFT采用Container组织对象。基于此,RGW在上层针对两个协议分别实现,屏蔽两者的差异,在中间层以后则采用一致的设计实现。为支持HTTP协议,RGW模块内部还集成了WEB服务器civetweb。本文重点以S3协议为例进行阐述。
S3协议与SWIFT协议主要接口对比表
项目 | S3协议 | SWIFT协议 |
---|---|---|
查询用户的存储桶 | List Buckets | List Containers |
查询存储桶内的对象 | List Bucket | List Container |
上传对象 | Put Object | Put Object |
下载对象 | Get Object | Get Object |
删除对象 | Delete Object | Delete Object |
对内而言,用户的对象经由RGW处理后,会最终存放在后端RADOS系统内。RGW所负责的就是用户对象到后端RADOS对象的转换。用户对象就是用户的文件,比如文本文件、图片文件、音视频文件或者打包的压缩文件,其大小可能很小,只有几个字节,也可能很大,数G或者数T,经由RGW处理后,这些文件都将以RADOS对象的方式存储。单个RADOS对象理论上也可以存放大量数据,但是综合考虑I/O效率、数据迁移和各节点均衡分布等因素,在实际使用时一般都会限制单个RADOS对象的大小。对于RGW应用场景而言,默认限制单个RADOS对象的大小最大为4M。在这种情形下,RGW就需要处理RGW对象怎么分解为多个RADOS对象、这些RADOS对象怎么组织、RGW元数据如何存放等问题,这也是本文分析的重点。
RADOS对象与RGW对象主要特性对比表
项目 | RADOS对象 | RGW对象 |
---|---|---|
服务协议 | HTTP | LIBRADOS |
对象大小 | 一般限制在4M | S3协议默认限制在5T |
覆盖写支持 | 支持 | 不支持 |
索引支持 | 不支持 | 支持 |
版本控制 | 不支持 | 支持 |
二、RGW的组成结构
RGW 是RADOS Gateway 的缩写。RGW 是运行于RADOS集群之上的一个RADOS Client 实例,是CEPH集群对外提供对象存储服务的一个网关,它允许用户通过Restful API 的方式访问CEPH集群。其提供的Restful API具体为S3 API 和Swift API,即符合S3 协议和Swift 协议。
向下RGW通过LibRADOS接口库访问RADOS集群。RGW的所有数据,包括集群内RGW服务单元zone的配置信息、用户信息等元数据和实际内容数据均存放在RADOS集群内,RGW自身不持久化存储数据。RGW与RADOS集群的通讯方式为网络通信,基于TCP协议与RADOS集群内的Monitor节点和OSD节点进行高速的数据访问与处理。
RGW的组成结构如下图。
图中Frontend WEB服务器用于监听并接收HTTP服务请求。默认情况下RGW内嵌入了WEB服务器Civetweb(N版本后换成了beast),相关请求在RGW进程内直接处理;此外,RGW支持Apache、Nginx等第三方WEB服务器。与第三方WEB服务器集成时,RGW与WEB服务器是独立的进程,WEB服务器通过RGW注册的监听端口转发请求给RGW。本文以内嵌入的Civetweb为例进行说明,在此情形下Civetweb以线程池的模式运行在RGW进程内,以便于多任务的并发处理;默认线程数为512个,并受配置参数rgw_thread_pool_size控制。
REST API处理层负责处理S3协议与SWIFT协议的协议API特性逻辑。S3X协议接口采用WEB API形式,由GET、PUT、DELETE等简单的WEB接口组成,分别对应上传、下载、删除等操作。用户的操作请求到达WEB服务器后,操作请求会先交由该层处理。该层依据具体的S3协议或SWIFT协议将操作请求进一步整理,去除协议特性,按照RGW对象标准操作格式提交给下一层处理。
Execution层按照RGW对象的标准格式处理各类操作请求,各类操作请求在该层中都有相对应的程序实现。在这一层中会根据操作请求处理RGW对象的元数据和内容数据,并操纵RGW-RADOS适配层进行I/O操作。
RGW-RADOS适配层会将对RGW对象的操作转化为对RADOS对象的操作。操作RADOS对象主要通过LIBRADOS接口实现,因此LIBRADOS接口对该层而言是完全可见的。RGW对象的所有数据均以RADOS对象作为支撑,在处理用户操作请求的过程中,需要使用RGW对象多种关联信息,因此RGW-RADOS适配层会在这一过程中被反复多次调用。
LIBRADOS是RADOS系统的对外窗口,在RGW应用环境中它运行在RGW进程内,并通过网络协议访问RADOS系统内的OSD(数据存储节点)、MONITOR(监控管理节点)。RGW、RBD(CEPH的块存储应用)等均要通过LIBRADOS接口库访问RADOS系统,它是规范使用CEPH的重要接口。该库除实现公开的标准接口外,还实现了CRUSH对象寻址算法,这意味着应用RGW可更具CRUSH算法的运算结果直接发起对最终OSD数据存储节点的访问,能做到更高的I/O效率。
GC资源回收模块属于辅助模块,是针对磁盘空间等资源的回收。RGW使用专门的线程负责此项工作。在客户端执行删除对象操作后,对象所占用的磁盘空间会由后台GC线程处理;此外在执行对象上传操作时,上传过程中会产生一些临时数据,这些临时数据也会由GC线程负责回收。可使用命令“radosgw-admin gc list --cluster clustername”查看资源回收处理情况。
QUOTA配额管理模块也属于辅助模块,其用于管理存储桶和用户的配额。存储桶配额可限制存储桶内的所有对象大小、对象数量,用户配额可限制用户所有对象的大小和对象数量。配额信息的访问和更新都比较频繁,因此RGW将配额信息缓存在缓存中,同时设置了数个配置项控制缓存配额信息与落盘配额信息的同步周期、同步时机,在RGW进程内还有相应的“rgw_buck_st_syn”“rgw_user_st_syn”线程处理这些工作。可通过“radosgw-admin”命令配置相关配置项,也可配置为不开启配额功能。
AUTH权限管理模块也是一个辅助模块,其涉及到基于S3协议的用户身份认证和基于swift协议的用户身份认证,以及用户对资源的操作权限管理。S3协议的身份认证基于密钥进行,swift协议的用户身份认证基于令牌认证。操作权限方面RGW将划分为读、写、删除等不同类别,这些功能均在AUTH权限管理模块中实现。
三、Rgw用户信息
Rgw用户信息存放在多个rados对象内。根据S3协议规定,用户访问RGW时会首先发送acess key和一段密文信息,并不会直接发送用户名。因此对RGW用户相关信息的描述是从access key开始。基于access key可检索出用户名,基于用户名可查找到该用户的id、别名以及email等关联信息;同时在知道用户名的情况下,可直接到RADOS对象“{username}.bucket”内查询出用户的所有bucket。下图以图示的方式说明各部分之间的关联关系。
图中,用户的access key作为一个RADOS对象单独存在,该对象的名字就是{access key},如“AccessKeyDemo”,内容是access key对应的用户名{username},如“UserNameDemo”。这意味着access key在RADOS内是以明文、并作为RADOS对象名存在的,也意味着不同RGW用户的access key不能相同,在创建RGW用户时也会检查access key是否冲突,冲突时会提示“user id mismatch”。
对于username,会在RADOS内的POOL“{zone}.rgw.meta”中直接创建一个以具体username命名的RADOS对象,该对象通过内容数据存放用户的基本信息,基本信息对应数据结构RGWUserInfo,其内包含user_id、display neme、access key等信息。POOL是RADOS对外提供的、用以管理并划分RADOS对象的一个逻辑结构,一个RGW的zone会有多个RADOS POOL来支撑。
针对用户与其所持有的bucket,会在RADOS内创建一个以具体username+“.bucket”为名称的RADOS对象。在该对象的OMAP属性内记录了RGW用户所持有的bucket的基本信息。OMAP属性是KV结构,OMAP属性的名为具体的bucket名称,属性值为cls_user_bucket_entry结构数据,其内记录了bucket名称、大小size、创建时间creation_time等基本信息。
对于每个bucket,系统会以具体的bucket名称创建对应的RADOS对象,其内以XATTR属性的方式存放了bucket拥有者的基本信息,这些信息与前述username对象相同。此外对于每个bucket,系统还会创建其他多个RADOS对象,用于存放bucket自身的一个基础元数据信息,包括bucket的ACL策略、bucket内的对象列表等。下一节再详细说明。
上述这些RADOS对象均存放在POOL“{zone}.rgw.meta”内。为了更好地区分这些不同类别的RADOS对象,RGW利用了RADOS的命名空间机制。比如username对象在users.uid命名空间、acess key对象在users.keys命名空间等。命名空间是RADOS对象标识的基本结构组成之一,它作为一个因素参与到CRUSH运算之中,在后端存储落盘时它也是最终数据文件的标识因素之一,因此不同命名空间的RADOS对象可以重名。在rados ls 命令中使用参数—all可以列出特定pool下所有命名空间中的对象,如下例所示:
# rados ls -p ZoneTest.rgw.meta --all
此外从图中还可看出,用户基本信息以及用户与bucket之间的关联等由单独的RADOS对象存放,RADOS对象内会以内容数据、XATTR属性数据或OMAP属性数据等形式存放数据,XATTR数据数据读取速度最快,但其数据大小具有严格的限制;OMAP数据的读写速度次之,在后台它在专门的KV数据库内存放,其数据条目可根据应用需求增加;RADOS对象的内容数据则没有太多限制,只要不超过设定的限制即可,默认限制是100G。各RADOS对象间通过RADOS对象名称进行关联,这些关联关系在RGW程序逻辑中直接确定。比如在已知用户名“UserNameDemo”的情况下,可以到RADOS对象“UserNameDemo.bucket”内直接查询到该用户所拥有的bucket;在已知bucket名称“BucketNameDemo”的情况下,可以在RADOS对象“BucketNameDemo”中直接查询到bucket拥有者的基本信息。
四、BUCKET与对象索引信息
与描述用户相类似,Bucket自身以及对象索引等元数据信息也存放在数个RADOS对象内。相关主要RADOS对象及其关联关系如下图所示。
Bucket自身最基本的元数据信息存放在{bucketname}RADOS对象内,这个RADOS对象的名字就是bucket的名字,存放在{zone}.rgw.meta POOL中,命名空间为root,在其内容数据中存放了bucket的bucket_id、bucket拥有者、创建时间等基本信息。
Bucket更为丰富的元数据信息保存在.bucket.meta.{bucketname}:{bucketid} RADOS对象内,这个RADOS对象的XATTR属性中存放了bucket的访问控制策略,XATTR属性名为user.rgw.acl,属性值对应数据结构RGWAccessControlPolicy。这个RADOS对象的内容数据部分存放了bucket的主要元数据信息,包括bucket拥有者、所属zonegroup、空间配额quota等,对应数据结构RGWBucketInfo。该RADOS对象同样存放在{zone}.rgw.meta POOL中,命名空间也为root。这个RADOS对象的名字较长,可用rados命令列出该RADOS对象以及Bucket基本元数据的RADOS对象。
# rados ls -p ZoneTest.rgw.meta --namespace=rootBuckertNameTest.bucket.meta.BuckertNameTest:ab46ccc9-4eb5-432d-8d9e-63d79720582e.2674103.1
bucket内的对象索引信息会分片存放在多个RADOS对象内。因为CEPH定位于大规模分布式对象存储,因此一个Bucket内的对象可能会非常多,将索引信息分片存放有利于提高对象检索的速度。这些RADOS对象命名规则为.dir.{bucket_id}.{shard_id},存放在{zone}.rgw.buckets.index POOL内,未设定命名空间。这些RADOS对象有多个OMAP属性,每个属性对应一个对象,属性名为对象名,属性值为对应的基本元数据信息,包括对象名字、版本、存在状态等,对应数据结构rgw_bucket_dir_entry。在生产环境中,OMAP属性数据常存放在SSD等快速存储介质上,以OMAP方式存放对象索引信息有利于提高索引信息的读写速度。
此外这些RADOS对象的OMAPHeader属性中存放了Bucket的整体统计信息,包括Bucket内对象总数和总大小,对应数据结构rgw_bucket_dir_header。OMAPHeader属性是OMAP属性的一种,与常规OMAP属性相比,它不需要指定属性名,直接存放属性值;在RADOS后端实现时,以“{对象ID}-”作为key名进行数据读写。
五、RGW对象与RADOS对象的关系
RGW对象最终是由RADOS对象承载的。根据RGW对象的大小,RGW对象与RADOS对象的对应关系分为三种情况。当RGW对象的内容数据小于默认设定值4M时,一个RGW对象对应一个RADOS对象;当RGW对象超过4M、小于S3客户端设定值(s3cmd默认设定15M)时,RGW对象由一个首部RADOS对象和多个分片RADOS对象组成;对于更大的RGW对象(s3cmd默认是超过15M),RGW对象由一个首部RADOS对象和多个分段对象组成,每个分段对象又由multipart RADOS对象和分片RADOS对象组成。当使用java等应用编程接口时,按段分割界限可由应用指定,但最大不超过5G,当RGW对象超过5G时必须分段上传。
对于小于4M的对象,其与RADOS对象的关系如下图。此处以只有12字节“Hello world!”RGW对象hw为例进行说明。此时在{zone}.rgw.buckets.data POOL下只建立一个RADOS对象,RADOS对象名字为{bucketid}{RGW对象名字}。该对象的数据内容就是RGW对象要存储的内容,该对象的user.rgw.manifest XATTR属性存放了RGW对象的数据布局信息,包括RGW对象的实际大小、首部对象的实际大小、首部对象允许的最大大小、存在其他RADOS对象时的对象命名前缀等关键信息。此外该首部对象还有user.rgw.acl、user.rgw.content_type、user.rgw.source_zone等多个XATTR属性信息。
对于大于4M、小于默认值15M的RGW对象,系统在RADOS首部对象后面增加其他RADOS对象存放数据,这种方式称为数据分片。新增加的RADOS对象只存放内容数据,没有XATTR或OMAP属性数据,并以{bucketid}shadow{prefix}{stripid1}命名,其中前缀prefix来自于首部对象的user.rgw.manifest XATTR属性值,在新建RGW对象时随机产生。
对于大于默认值15M的RGW对象,S3协议客户端s3cmd将会分段上传,每段内容数据不超过15M,在RADOS中存放数据时也以15M为分段界限进行存放。按段分割界限是由S3协议规定的,最大不超过5G,实际使用时每段不宜太大。因为S3协议使用的是HTTP传输协议,HTTP协议更适合在一个协议会话中传输短报文,在一个协议会话中传输太大的文件容易影响系统稳定性。HTTP协议服务端更喜欢能尽快地完成并结束一个协议话。此外S3协议的这个规定,也有利于按段进行断点续传。当分段存放时RGW对象的组织方式如下。
此时,首部对象不再存放内容数据,只以XATTR属性的形式user.rgw.manifest等元数据信息。在每段的首部会有一个multipart对象,其自身会存放不超过4M的内容数据,以及user.rgw.acl等XATTR属性数据。在multipart对象后面会有一些strip分片对象,专门用于存放内容数据,每个内容数据大小同样不超过4M。因为每段最多15M,每个multipart对象自身可存放4M内容数据,因此其后面的分片对象不超过3个。
从上述RGW对象的数据组织方式也可看出,RGW对象存储的数据访问特征是大块的顺序读写,并且单次写入、多次读取,数据内容上传后几乎不会修改。如果数据经常需要随机改写和追加,使用RGW存放会比较困难。
六、上传对象的处理流程
下面以上传12个字节的RGW对象hw为例说明对象的上传过程。Hw对象的内容为“Hello world!”,对象以S3接口方式上传。使用s3cmd命令“s3cmd put ./hw s3://BucketNameDemo”上传对象hw,上传操作与RGW之间的会话基于HTTP协议,它们间的第一个会话交互如下。
//操作请求提交的内容
GET /BucketNameDemo/?location HTTP/1.1
Host: 10.21.170.218:7480
Accept-Encoding: identity
Content-Length: 0
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Authorization: AWS4-HMAC-SHA256 Credential=KeyDemo/20210510/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=1c74ee51a2a83272cb0389a69160287fee5b8564bc2fc650bdee7ad14c66ee94
x-amz-date: 20210510T093939Z//RGW返回的内容
HTTP/1.1 200 OK
x-amz-request-id: tx00000000000000000001c-006098ff5b-3a5a5d-default
Content-Length: 127
Date: Mon, 10 May 2021 09:39:39 GMT
该次交互的目的是查询目标BUCKET是否存在。这通过S3接口“GET / BucketNameDemo/”实现。RGW收到请求后会进行用户身份的鉴别。身份鉴别通过后,查询目标bucket是否存在,当目标bucket存在时,RGW返回HTTP 200;当目标bucket不存在时,RGW会返回HTTP 404错误。
第一次交互对RGW而言也是一个操作请求。该次交互完成后,进行第二次交互,第二次交互过程如下。
//操作请求提交的内容
<?xml version="1.0" encoding="UTF-8"?><LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/"></LocationConstraint>
PUT /BucketNameDemo/hw HTTP/1.1
Host: 10.21.170.218:7480
Accept-Encoding: identity
Authorization: AWS4-HMAC-SHA256
Credential= KeyDemo/20210510/us-east-1/s3/aws4_request,
SignedHeaders=content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-meta-s3cmd-attrs;x-amz-storage-class,Signature=16a3b9cf0aa937353eb4a86d059f653f86f8a8ac7694393f001728bdccdcc578
content-length: 13
content-type: text/plain
x-amz-content-sha256: 03ba204e50d126e4674c005e04d82e84c21366780af1f43bd54a37816b6ab340
x-amz-date: 20210510T093939Z
x-amz-meta-s3cmd-attrs: atime:1620639558/ctime:1620639558/gid:0/gname:root/md5:8ddd8be4b179a529afa5f2ffae4b9858/mode:33188/mtime:1620639558/uid:0/uname:root
x-amz-storage-class: STANDARDHello World!
//RGW返回的内容
HTTP/1.1 200 OK
Content-Length: 0
ETag: "8ddd8be4b179a529afa5f2ffae4b9858"
Accept-Ranges: bytes
x-amz-request-id: tx00000000000000000001d-006098ff5b-3a5a5d-default
Date: Mon, 10 May 2021 09:39:39 GMT
该次交互会向RGW正式提出PUT上传对象的请求。这通过S3接口“PUT / BucketNameDemo/hw”实现。在该请求中,除内容数据“Hello World!”外,还会向RGW一并提交对象所属的存储桶、内容长度、对象类型等辅助信息。
接下来我们重点说明RGW在收到第二次交互,也就是收到PUT请求后的处理情况。
首先是处理请求的回调函数。请求处理回调函数在系统启动阶段设定。
# src\rgw\rgw_civetweb_frontend.cc
这篇关于一文读懂CEPH RGW基本原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!