前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Ceph RGW整体结构,最全干货在这!

Ceph RGW整体结构,最全干货在这!

作者头像
腾讯云TStack
发布2020-05-20 10:40:32
8.4K0
发布2020-05-20 10:40:32
举报

小新 职场新人,存储小白 立志成为职场老鸟,存储专家;

影视迷,东野迷。

  友情提醒:以下内容有点干,请自备快乐水~

一、前言

Ceph中的对象存储网关RadosGW和Ceph RBD以及CephFS一样,构建在librados之上,主要提供的命令工具有如下:

  • radosgw : 用来启动radosgw服务,并且提供restful的访问方式,也是下文讨论的对象
  • radosgw-admin : 用来提供admin的管理服务,如创建user等

另还有radosgw-es、radosgw-token和radosgw-object-expirer

目前RadosGW(下称RGW)主要提供两种接口:Amazon S3 RESTful接口和OpenStack的Swift接口。其中S3接口是由Amazon提出的标准化的对象存储接口,可以使用该接口标准对接其他支持S3标准的对象存储系统,OpenStack Swift本身就可以提供分布式对象存储,使用的是Swift接口,RGW为了可以对接OpenStack,也支持Swift接口。

由Ceph的存储架构可知,RGW、RBD和CephFS可以使用同一套Rados集群,所以可以同时提供上述的三种服务。对于RGW而言,S3和Swift两个接口类型可以使用同一个存储空间(如.rgw.data),因此,可以使用两种接口对Object数据进行读写。

目前使用的Ceph版本为14.2.8(Nautilus),RGW相比L版本新增的特性有如下:

1、默认frontend从civetweb换成beast,整体性能有所提升

2、支持在placement中设置storage class,并支持lifecycle跨placement进行数据处理

3、支持对象锁,新增6个对象锁的API

4、新的发布/订阅基础设施以支持serverless框架(如knative)或数据管道(如kafka)

5、支持List Object V2等。。。

二、整体架构

RGW的总体启动流程和作用如下:

1、启动frontend(即一个响应http请求的web服务器)

2、然后接受http请求,将http请求进行封装为RGWRequest

3、然后根据请求的uri和method等rest请求信息(包含在RGWProcessEnv)

4、获取到相应的RGWOp和RGWHandler_Rest

5、然后由Scheduler调度某个Thread来执行相应Handler的op操作

6、并根据结果封装返回体进行返回

下面主要从代码的角度,分别从启动过程和启动之后处理请求两个阶段来进行讨论。

1、RGW启动时架构

下面是针对N版本的RGW的启动整体架构图:

架构说明  

RGW主要由上述的三部分组成,首先是Frontend,简单理解就是HTTP服务器,响应前端http请求;然后是REST APis,主要就是采用的REST Api的格式,以及对应API处理的MGR;以及RGWProcess,将RGWRados等信息封装到一起交由RGWProcess进行处理。

Frontend  

用来提供HTTP服务请求的监听,并根据请求的相关信息,封装参数、转换请求(http request -> RGWRequest)、调度任务、转发给Handler进行处理。Frontend目前支持的类型包括Civetweb(也是N版之前默认的Frontend)、Beast(当前N版的默认Frontend)、Loadgen和FastCGI。在配置文件中可以同时配置多个Frontend,每个Frontend对应有自己的配置,存储在RGWFrontendConfig中,使用multimap来存储每个Frontend以及对应的RGWFrontendConfig。

Civetweb来自于Mongoose,是一款强大的嵌入式Web网络服务器,简单和性能之间的均衡,在RGW中的实现类是RGWCivetWebFrontend。Beast是新加入进来的Frontend,主要是采用异步IO的方式来实现请求的处理,相比Civetweb而言,性能上有所提升(有待详细对比),在RGW中的实现类是RGWAsioFrontend。另外的Loadgen和FastCGI(FCGI)相对而言在RGW中使用的较少,在RGW中的实现类分别是RGWLoadGenFrontend和RGWFCGXFrontend,具体可以参考详细的使用说明。

总结:

  • Frontend Config ( multimap<string, RGWFrontendConfig *> )
  • Civetweb ( RGWCivetWebFrontend )
  • Beast ( RGWAsioFrontend )
  • Loadgen ( RGWLoadGenFrontend )
  • FastCGI/FCGI ( RGWFCGXFrontend )

Rest Apis 

主要体现在具体可以接收和处理的API的类型,通过RGWREST来进行API资源的注册,同样可以同时支持多个API类型,目前版本所支持的API类型有:

  • S3 (Amazon的S3标准API,重点讨论)
  • Swift (对接Openstack的API)
  • Swift Auth (Swift的授权认证API)
  • Admin (提供Admin的API访问,例如创建user等操作)

每个API类型对应一个主MGR(可以理解为该API类型的处理方法集),主MGR还可以注册多个子MGR(此处的‘主’和‘子’只是我在理解上的逻辑分类,实际代码中没有明确的主次之分),因此每个API可以对应有多个MGR;每个MGR中维护该MRG所支持的Resource(可以理解为所支持的具体的handler列表),可以将每个MGR看作是一种Resource;每个Resource同时还可以包含有多个Handler(即处理相应资源请求的类,例如处理Bucket的Handler),每个Handler中还有多个OP(即具体的操作,例如GetOp等),关系图如下所示:

下面以S3协议类型的API作为例子详细进行解析,其他的API类型基本上跟如下的流程和关系一致,部分区别在有的API的主MGR下面还注册有多个子MGR,如Swift,另外有的API的Handler中通过重写的方式实现部分OP。

下图中的S3的API类型的整体关系图和上面的基本一致,S3的API的MGR只有一个,并且设置为default mgr,下面的详细示例图中选择Obj的相关Handler进行介绍,其中包含的OP基本上就是HTTP请求中常见的几个请求Method,如GET,PUT,DELETE等。每个OP中还包含有一个或多个具体的操作实现类,例如op_get中会有GetObj,GetObjAcl,GetObjTag等,如下图中列举的是op_delete的具体操作。

RGWProcess 

此过程就是封装请求,在RGW启动之后,创建好了Frontend,并运行了起来,用来监听来自前端的HTTP的请求,刚刚上一步完成了API的注册,接下来就是等待请求的到来。此处的RGWProcess主要是体现出在请求来了之后,需要准备的资源和参数,进行封装好之后传递给真正的RGWProcess进行处理,也就是rgw_process.cc/process_request()方法进行处理,之后的处理过程在下面有介绍。

从上述的整体架构图来看,处理一个请求需要的几个重要参数资源,如下:

  • RGWProcessEnv
  • RGWRequest
  • RGWRestfulIO
  • RGWRados
  • Scheduler
RGWProcessEnv  

用来存储在RGWProcess过程中的非常重要的环境变量,例如:RGWRados等,其结构体的定义如下:

代码语言:javascript
复制
struct RGWProcessEnv {  RGWRados *store;  RGWREST *rest;  OpsLogSocket *olog;  int port;  std::string uri_prefix;  std::shared_ptr<rgw::auth::StrategyRegistry> auth_registry;};在创建Frontend的时候通过RGWProcessEnv将RGWRados等参数传递给Frontend。
RGWRequest  

来自前端的HTTP请求,需要转换成对应的RGWRequst,这个过程也是RGW处理流程的重要一个流程,主要用来存储维护请求的id、请求的状态信息以及HTTP请求转化为RGWRequest之后的OP句柄等。其中req_state(即请求状态信息)存储整个请求过程中的状态信息,包括有:错误码和错误信息、op和op_type、trans_id和host_id等信息。

RGWRestfulIO 

用来与Rest Client进行交流的接口,除了提供常规的Client的功能之外,还有类似Accounter计数器、AWS Auth V4等功能,通过过滤器的模式来提供不同的功能,屏蔽了复杂的pipeline结构,如下示例。

代码语言:javascript
复制
auto real_client_io = rgw::io::add_reordering(    rgw::io::add_buffering(cct,        rgw::io::add_chunking(          rgw::io::add_conlen_controlling(&real_client))));
RGWRados 

RGWRados作为RGW与Rados进行沟通的接口适配器,里面封装了所有RGW需要去操作底层Rados的操作接口,上层的RGW操作最终都是通过该适配器与底层的Rados进行沟通。

Scheduler 

Scheduler主要是用来进行任务的调度,当请求需要处理的时候,会由相应的Scheduler来进行调度,调度的流程大概是:

1、获取调度器所需参数(client,cost等)

2、然后获取Executor

3、接着根据获取的Executor创建Completion(看做是待处理的请求)

4、然后将创建的Completion转换为Request的unique_ptr

5、最后将创建的Request的unique_ptr添加到任务执行的工作队列中

当前版本中的Schedule采用的dmClock(distribute mClock)算法来进行实现的,可以实现QoS功能,dmClock主要包含有Reservation(下限)、Limit(上限)和Weight(权重)三个控制参数,采用基于时间便签的队列模式,将请求映射到时间轴来确定请求应该被处理的时刻。

支撑性组件 

在进行RGW初始化的过程中,需要将系统的一些支撑性的组件完成初始化,例如日志、配置、认证等,为其他的组件在运行的过程中提供资源。

Config 

Config组件,里面存储了所有的参数值,如果没有指定配置,则会给一个默认的参数值,在代码层面可以在src/common/options.cc中查找到是所有配置的默认值和说明,例如,可以获取frontend的配置、apis的配置、log配置等信息。在RGW的启动过程中,可以使用g_conf来获取相应的参数,该方法通过ConfigProxy的方式来进行配置的获取和修改,其中ConfigProxy中采用Seastar来进行实现。

TracePoint 

实现代码的Trace功能,可以追踪程序的执行过程,进行程序的流程分析,通过ceph的上下文进行初始化,在RGW这一层主要提供两种Trace的时间对象,分别用来Trace RGWOp的操作过程,以及Trace RGWRados的操作流程,如下所示:

代码语言:javascript
复制
TracepointProvider::Traits rgw_rados_tracepoint_traits("librgw_rados_tp.so", "rgw_rados_tracing");TracepointProvider::Traits rgw_op_tracepoint_traits("librgw_op_tp.so", "rgw_op_tracing");
TracepointProvider::initialize<rgw_rados_tracepoint_traits>(g_ceph_context);TracepointProvider::initialize<rgw_op_tracepoint_traits>(g_ceph_context);
Timer 

主要作用是执行定时任务,Timer在RGW中的使用主要体现初始化超时、日志打印以及Realm重新加载中,主要的功能如下:

1、使用SafeTimer创建相应的定时器

2、将任务(事件event)添加到事件队列中

3、定期轮询事件队列中的事件是否到了处理的时间,如果没有则继续轮询,如果到了则执行

4、也可以取消指定事件或者所有事件等。

SafeTimer中的事件存储采用的multimap的方式,其中key是时间,由multimap的特性可知默认采用升序排序,即multimap中的第一个元素的时间应该是最小的,如下所示。

代码语言:javascript
复制
std::multimap<utime_t, Context*> schedule;std::map<Context*, std::multimap<utime_t, Context*>::iterator> events;

说明:

1、schedule这个map存储将要执行的事件信息,时间作为key,实际调度执行的map

2、events是用来检查事件是否正确添加或者取消,例如:是否有重复添加的,或者是否要取消一个不存在的事件等;

因此对于事件处理来说,schedule中存储的事件是按照时间小到大排序,也就是时间越小的越排在前面,因此,在检查事件是否到时间的时候,首先检查第一个事件执行时间是否到了,如果没到,那后面的事件都不用检查了,如果到了,则取出来进行执行。

Log 

在RGW中的日志体现在两个方面,一个是使用dout以及各种日志函数等进行日志的输出,另一个是采用OpsLogSocket实现的操作日志,会记录RGW中的每个操作记录,可以通过参数设置是否将操作的日志输出到Rados中,或者输出到Scoket中进行读取,如下所示:

代码语言:javascript
复制
# 启动ops的日志记录rgw enable ops log# 配置是否将ops log记录到raods中rgw ops log rados
# 配置ops log记录的socket地址rgw ops log socket path
# 最少累积多少条ops log才写入socket中rgw ops log data backlog

note: 有些参数不知道其作用的时候,可以在src/common/options.cc中查找到相关说明

Auth 

在RGW初始化的时候进行Auth Registry的创建,在后面创建Frontend的时候会将Auth Registry信息添加到FrontendEnv中,对请求进行验证和授权。

Auth的简要的认证过程如下:

1、通过在不同场景下使用get_swift、get_s3_main或者get_s3_post进行Strategy的获取

2、然后根据具体实现调用相应的Strategy的authenticate方法

3、在authenticate方法中加载相应的Engine进行验证

在验证的Engine方面,根据不同的场景下的不同Strategy有如下类型:

1、S3AnonymousEngine: 响应匿名请求的验证

2、ExternalAuthStrategy:外部验证Engine的引入

▶ EC2Engine:即为Keystone的验证引擎

▶ LDAPEngineA:将S3的Signature转换成相应的LDAP的user/pass向LDAP服务进行验证

3、LocalEngine:直接使用保存在meta pool中的aksk进行验证

4、STSAuthStrategy:是AWS的Web验证服务,根据返回的临时安全Token进行后续验证,可以传入IAM策略;

Signal Hanlder 

在Frontend运行之前会进行系列信号处理Handler的注册,来响应运行过程中的各种系统信号,例如Ctrl+C,在RGW中注册的信号有如下几种:

1、SIGTERM:软终止进程,可以阻塞、处理和忽略

2、SIGINT:终止进程,终端输入Ctrl+C

3、SIGUSR1:用户自定义信号

4、SIGALRM:时钟的定时信号(如提供给Timer使用)

5、SIGHUP: 终端挂起(断开连接),如&符提交的

并且每个信号有相应的信号处理Handler,在RGW进程进行shutdown的时候,会将已经注册的信号和处理进行Unregister来释放相应的资源,同时还会释放其他的各种资源(如Frontend等)。

2、RGW启动后处理请求的架构

在上述的介绍中可以看到也有RGWProcess,与下面的RGWProcess有所不同,上面的介绍的RGWProcess是在Frontend中封装的各种参数然后传递给process_request,然后请求的处理就离开了Frontend,来到了rgw_process.cc中的process_request,即下面开始介绍的RGWProcess。

架构说明  

结合前面RGW启动时的架构和RGW启动后处理请求的架构可以看出RGWProcess的主要作用就是接收来自Frontend的请求,进行相关的参数处理和验证之后,将请求转发到后端具体Mgr的Handler进行处理,由此就到每个具体功能的处理Handler中进行任务的执行,从而完成整个RGW的请求处理的架构流程。

process_request 

作为Frontend传递请求信息过来的入口,首先,接收来自Frontend的参数信息,

主要包括:

1、RGWRados

2、RGWRestfulIO

3、RGWRequest

4、Scheduler

5、RGWProcessEnv

根据传入的参数得到相应的对象变量,如下所示:

1、RGWRestfulIO  ->  RGWEnv

2、RGWEnv, RGWRequest  ->  RGWUserInfo, req_state

3、RGWRados, req_state  ->  RGWObjectCtx

该部分主要就是进行基本参数的转换,将Frontend传递过来的参数转为接下来所需要的对象。其中RGWEnv中主要包含了请求头的基本参数,如下图所示,因此可以由该对变量生成req_state结构体的对象。

get_handler 

这个部分最主要的作用就是根据上面封装好的参数,获取相应的Mgr,以及处理对应请求的Handler,可以根据Handler获取具体操作的RGWOp对象,然后就可以通过使用RGWOp对象来进行具体的执行,因此这个过程非常重要。

传给get_handler参数除了上述架构图中的之外,还另外有frontend_prefix和Auth模块中的auth_registry,通过frontend_prefix和req_state的参数来匹配具体的Mgr和Handler,用auth_registry进行权限验证,流程如下:

1、其中,在进行preprocess之后,通过RGWREST中的RGWRESTMgr对象调用get_manage获取符合req_state和frontend_prefix匹配条件的RGWRESTMgr

2、然后通过取到的RGWRESTMgr来获取符合req_state和frontend_prefix的请求条件,且通过auth_registry认证通过的RGWHandler_REST

3、对取到的RGWHandler_REST进行init初始化工作;

scheduler_request 

对于Scheduler,其默认的调度类型是throttler,也可以配置使用dmclock,但是当前版本的dmClock还是处于实验阶段,调度的大概流程如下:

1、通过get_handler取到特定的RGWHandler_REST之后,通过handler取到当前请求的RGWOp对象

2、然后对该RGWOp对象调用scheduler_request进行请求处理的调度

3、根据传入的Scheduler进行scheduler_request调度

对于dmclock的调度器而言,其有同步和异步两种实现:AsyncScheduler和SyncScheduler

verify_requester 

此处调用RGWOp的verify_requester,根据不同的API类型来进行请求的权限验证,如下是不同的类型对应的验证方法:

1、S3 API:RGWHandler_REST_S3::authorize

2、Swift API:RGWHandler_REST_SWIFT::authorize

3、Swift Auth API: RGWHandler_SWIFT_Auth::authorize

4、IAM:RGWHandler_REST_IAM::authorize

postauth_init 

此处调用的是RGWHandler_REST的postauth_init,主要校验的对像如下:

1、BucketName: 校验bucket name是否符合Amazon的规格,例如必须字母,数字或下划线开头

2、ObjectName:

  • 主要校验长度是否小于1024字节
  • 编码格式是否是UTF-8

3、Tenants:主要校验Tenant名中是否由非法字符

4、MFA:校验请求头中的HTTP_X_AMZ_MFA

  • 检验长度是否合法
  • 检验User是否含有有关参数
  • 检验MFA值的合法性

rgw_process_authenticated 

最后来到了最终将要执行的地方的,主要涉及到的操作有如下:

 1、RGWHandler_REST::init_permissions : 初始化RGWOp的操作权限   - 如果RGWOp是Create Bucket,则rgw_build_iam_environment   - 如果不是,则do_init_permissions进行权限初始化

2、RGWHandler_REST::read_permissions :根据不同的OP来获取RGWOp的操作权限

  - 如果是只有Bucket才有的操作,则直接忽略   - 如果不是,则通过rgw_build_object_policies获取RGWAccessControlPolicy信息

3、RGWOp::init_processing:初始化RGWOp的执行

  - 获取Bucket的quota   - 获取User的quota

4、RGWOp::verify_op_mask:通过位运算的方式来判断当前操作是否在支持的操作列表中

5、RGWOp::verify_permission: 检验是否对当前操作有权限   - 例如当前用户是否可以list bucket等

6、RGWOp::verify_params: 对于有些OP而言,需要校验参数信息   - 例如Put Obj中Obj的大小是否超出最大限制等

7、RGWOp::pre_exec():根据每个具体RGWOp的pre_exec   - 例如dump一下bucket的状态信息(指的是Bucket相关OP)

8、RGWOp::execute(): 执行具体操作的地方,由每个RGWOp的execute方法完成

9、RGWOp::complete():完成请求的操作,并且根据执行结果封装response

3、总结

上面从RGW启动的过程,和启动之后处理请求的两个阶段讨论了从代码层面来看的RGW架构,至此对RGW的整体结构和大致流程有了初步认识,接下来就应该针对请求的详细处理过程进行分析。

欲知后事如何,且听下回分解。

三、参考

Ceph v14-2-0-nautilus releases

(https://docs.ceph.com/docs/master/releases/nautilus/#v14-2-0-nautilus)

CivetWeb

(http://civetweb.github.io/civetweb/) Background on http frontends(civetweb and beast

https://www.cnblogs.com/dengchj/p/11436758.html

Loadgen

https://www.loadgen.com/ Ceph dmClock介绍

https://docs.ceph.com/docs/master/rados/configuration/osd-config-ref/ Seastar介绍

https://zhuanlan.zhihu.com/p/30738569 Ceph STS Auth介绍

https://docs.ceph.com/docs/master/radosgw/STS/ Ceph LDAP Auth介绍

https://docs.ceph.com/docs/master/radosgw/ldap-auth/

还在为容器时区困扰?送你一剂良药!

玩转K8S AdmissionWebhook

· END ·

记得文末点个在看鸭~


点就完事儿了!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯云TStack 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • RGWProcessEnv  
  • RGWRequest  
  • RGWRestfulIO 
  • RGWRados 
  • Scheduler 
  • 支撑性组件 
    • Config 
      • TracePoint 
        • Timer 
          • Log 
            • Auth 
              • Signal Hanlder 
              • 架构说明  
              • process_request 
              • get_handler 
              • scheduler_request 
              • verify_requester 
              • postauth_init 
              • 3、Tenants:主要校验Tenant名中是否由非法字符
              • rgw_process_authenticated 
              相关产品与服务
              对象存储
              对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档