文档章节

源码解读RGW中request的处理流程

秦牧羊
 秦牧羊
发布于 2017/06/21 14:18
字数 1017
阅读 201
收藏 1
点赞 0
评论 0

源码解读RGW中request的处理流程

请求处理流程图

以civetweb为例

输入图片说明

  1. rgw_main.cc为整个radosgw服务的入口,main()函数中根据在ceph.conf的rgw frontends参数设置来选择不同的前端类型,之后执行相应的run()方法实现整个frontend服务的启动。注意这里会根据ceph.conf中rgw_enable_apis的设置,实现s3、swift、admin等多种类型的接口生成不同的handler,具体代码如下

    #src/rgw/rgw_main.cc
    get_str_list(g_conf->rgw_enable_apis, apis); #获取接口类型列表
    
      map<string, bool> apis_map;
      for (list<string>::iterator li = apis.begin(); li != apis.end(); ++li) {
        apis_map[*li] = true;
      }
    ...
      if (apis_map.count("s3") > 0 || s3website_enabled) {
        if (! swift_at_root) {
          rest.register_default_mgr(set_logging(new RGWRESTMgr_S3(s3website_enabled))); #设置S3接口默认handler为RGWRESTMgr_S3
    ...
      if (apis_map.count("swift") > 0) {
        do_swift = true;
        swift_init(g_ceph_context);
    
        RGWRESTMgr_SWIFT* const swift_resource = new RGWRESTMgr_SWIFT;#设置swift接口默认handler为RGWRESTMgr_SWIFT
        ...
    
  2. 之后在对应的rgw_civetweb_fronted.cc中,根据之前介绍的civetweb启动流程,设置相应启动参数,之后使用mg_start()完成civetweb的启动。(注意参数中callback设置的是civetweb_callback)

    #src/rgw/rgw_civetweb_frontend.cc
    int RGWMongooseFrontend::run() {
      char thread_pool_buf[32];
      snprintf(thread_pool_buf, sizeof(thread_pool_buf), "%d",
    	   (int)g_conf->rgw_thread_pool_size);
      string port_str;
      map<string, string> conf_map = conf->get_config_map();
      conf->get_val("port", "80", &port_str);
      conf_map.erase("port");
      std::replace(port_str.begin(), port_str.end(), '+', ',');
      conf_map["listening_ports"] = port_str; #civetweb默认启动监听端口
      set_conf_default(conf_map, "enable_keep_alive", "yes"); #keep_alive参数设置
    
      set_conf_default(conf_map, "num_threads", thread_pool_buf); #默认threads设置
      set_conf_default(conf_map, "decode_url", "no");
      ...
      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, &env, (const char **)&options); #启动服务
    
      if (!ctx) {
        return -EIO;
      }
    
      return 0;
    } /* RGWMongooseFrontend::run */
    
    
  3. 经过上一步的设置,在civetweb_callback中每一个request请求都需要经过process_request()进行处理,注意每个request请求都会绑定一组RGWRados(负责底层Librados的数据读写)/RGWREST(对应request和Response的处理)/OpsLogSocket(日志消息记录)

    #src/rgw/rgw_civetweb_frontend.cc
    

static int civetweb_callback(struct mg_connection* conn) { struct mg_request_info* req_info = mg_get_request_info(conn); RGWMongooseEnv* pe = static_cast<RGWMongooseEnv *>(req_info->user_data);

{ // hold a read lock over access to pe->store for reconfiguration RWLock::RLocker lock(pe->mutex);

RGWRados* store = pe->store; RGWREST* rest = pe->rest; OpsLogSocket* olog = pe->olog;

RGWRequest req(store->get_new_req_id()); RGWMongoose client_io(conn);

int ret = process_request(pe->store, rest, &req, &client_io, olog); #每个request请求绑定一组前面的RGWRados、RGWREST、OpsLogSocket ... ```

  1. 之后调用rgw_process.cc中的process_request(),其中rest->get_handler根据请求的URL是否包含bucket、object信息,获取到对应的handler类型,之后调用handler->get_op(store)根据前面取得的handler对应request_method获取到最终的handler,之后触发handler对应的pre_exec()、execute()、complete()完整整个request请求的处理,代码如下:

    #src/rgw/rgw_process.cc
    int process_request(RGWRados* store, RGWREST* rest, RGWRequest* req,GWStreamIO* client_io, OpsLogSocket* olog)
    {int ret = 0;
    client_io->init(g_ceph_context);
    ...
    RGWHandler_REST *handler = rest->get_handler(store, s, client_io, &mgr,&init_error); #这里根据URL里面是否包含bucket、Object字段会进一步获取到对应的handler类型
    if (init_error != 0) {
    abort_early(s, NULL, init_error, NULL);
    goto done;
    }
    dout(10) << "handler=" << typeid(*handler).name() << dendl;
    should_log = mgr->get_logging();
    req->log_format(s, "getting op %d", s->op);
    op = handler->get_op(store); #这里根据request_method获取到最终处理request请求的handler类型
    ...
    req->log(s, "pre-executing");
    op->pre_exec(); #请求预处理
    req->log(s, "executing");
    op->execute(); #具体请求的具体实现
    req->log(s, "completing");
    op->complete(); #完成请求处理
    
    #src/rgw/rgw_process.cc
    RGWHandler_REST* RGWRESTMgr_S3::get_handler(struct req_state *s)
    {
      bool is_s3website = enable_s3website && (s->prot_flags & RGW_REST_WEBSITE);
      int ret =
        RGWHandler_REST_S3::init_from_header(s,
    					is_s3website ? RGW_FORMAT_HTML :
    					RGW_FORMAT_XML, true);
      if (ret < 0)
        return NULL;
    
      RGWHandler_REST* handler;
      // TODO: Make this more readable
      if (is_s3website) {
        if (s->init_state.url_bucket.empty()) {
          handler = new RGWHandler_REST_Service_S3Website;
        } else if (s->object.empty()) {
          handler = new RGWHandler_REST_Bucket_S3Website;
        } else {
          handler = new RGWHandler_REST_Obj_S3Website;
        }
      } else {
        if (s->init_state.url_bucket.empty()) {
    		handler = new RGWHandler_REST_Service_S3; #bucket为空则切换到RGWHandler_REST_Service_S3
        } else if (s->object.empty()) {
    		handler = new RGWHandler_REST_Bucket_S3; #obj为空则切换RGWHandler_REST_Bucket_S3
        } else {
    		handler = new RGWHandler_REST_Obj_S3; #bucket和Object都不为空,则切换到RGWHandler_REST_Obj_S3
        }
      }
    
      ldout(s->cct, 20) << __func__ << " handler=" << typeid(*handler).name()
    		    << dendl;
      return handler;
    }
    
    
    #src/rgw/rgw_rest.cc
    RGWOp* RGWHandler_REST::get_op(RGWRados* store)
    {
      RGWOp *op;
      switch (s->op)  #这里s对应一个req_state的结构体
      { rest->op
       case OP_GET:
         op = op_get();
         break;
       case OP_PUT:
         op = op_put();
         break;
       case OP_DELETE:
         op = op_delete();
         break;
       case OP_HEAD:
         op = op_head();
         break;
       case OP_POST:
         op = op_post();
         break;
       case OP_COPY:
         op = op_copy();
         break;
       case OP_OPTIONS:
         op = op_options();
         break;
       default:
         return NULL;
      }
    
      if (op) {
        op->init(store, s, this);
      }
      return op;
    } /* get_op */
    
    结构体定义
    struct req_state {
      CephContext *cct;
      RGWClientIO *cio;
      RGWRequest *req; /// XXX: re-remove??
      http_op op; #对应一个枚举类型,具体如下
      RGWOpType op_type;
      ...
    
      enum http_op {
      OP_GET,
      OP_PUT,
      OP_DELETE,
      OP_HEAD,
      OP_POST,
      OP_COPY,
      OP_OPTIONS,
      OP_UNKNOWN,
    };
    

URL->handler过程

理解整个URL转换handler的过程,能够感觉request信息快速定位具体的op操作,方便debug,整个过程用下面一张图总结。

输入图片说明

© 著作权归作者所有

共有 人打赏支持
秦牧羊
粉丝 68
博文 57
码字总数 28980
作品 0
广州
架构师
RGW S3 Authorize解析

截止到目前为止,RGW S3的认证部分支持AWS v4认证、AWS v2认证以及匿名用户认证。这三种认证的总入口位于rgwprocess.cc::processrequest()函数,该函数中处理认证部分的代码如下: rgwproce...

linuxhunter ⋅ 2016/04/18 ⋅ 0

RadosGW框架分析

RadosGW分析。 一、RadosGW的main()函数解析。 RadosGW的main()函数位于rgwmain.cc中,该函数是RadosGW的入口函数。这里主要解析和RadosGW相关的内容,尽量省略WebServer的内容。 main()函数...

linuxhunter ⋅ 2016/04/07 ⋅ 1

RGW S3 Multipart解析

S3分段上传技术主要应用在大文件的数据上传上,通常在S3客户端会对上传的大文件做一次分片操作。在RGW内部还会对S3客户端发送过来的数据再进行一次分片处理,RGW默认分片大小是4MB。下面就M...

linuxhunter ⋅ 2016/04/13 ⋅ 1

ceph RGW接口源码解析--Rados数据操作

RGW业务处理流程: http reqest --> apache 转 FastCgi module FastCgi module --> radosgw 通过socket请求实现(未确定是否有其它方式) radosgw --> ceph集群 通过socket实现,调用rados接口......

惊浪 ⋅ 2014/12/11 ⋅ 0

rgw bucket相关操作解析

一、list bucket。 1、读取bucket信息处理流程。 RGWListBucket::execute() |RGWRados::Bucket::List::listobjects() |RGWRados::clsbucketlist() |RGWRados::openbucketindex() |CLSRGWIss......

linuxhunter ⋅ 2016/04/11 ⋅ 0

RGW S3 CORS解析

一、RGW S3 CORS核心类关系图。 二、RGW S3 CORS处理类关系图。 三、RGW S3 CORS操作解析。 1、PUT CORS操作。 RGWPutCORS::execute() |RGWPutCORSObjStoreS3::getparams() |从HTTP请求数据流...

linuxhunter ⋅ 2016/04/14 ⋅ 0

RGW S3 ACL解析

RGW ACL主要类关系图如下图所示: RGW ACL处理类关系图如下图所示: RGW ACL主要处理流程详细说明如下。 一、PUT ACL。 RGWPutACL::execute() |从HTTP请求数据流中解析出RGWAccessControlPol...

linuxhunter ⋅ 2016/04/14 ⋅ 0

RGW Usage类解析

一、概述。 RGW Usage类实现了RGW的流量统计功能,其中包括发送/接收的字节数、执行操作的个数以及成功之行操作的个数。Usage类统计的这些内容对于一般的流量统计来说已经够用了。 二、核心...

linuxhunter ⋅ 2016/04/19 ⋅ 0

rgw object read and write

一、Get Object。 1、读取Object的主要处理流程。 RGWGetObj::execute() |创建RGWGetObjCB类实例,其中handledata()函数为回调函数,该函数会调用RGWGetObj::getdatacb()函数,而该函数最终会...

linuxhunter ⋅ 2016/04/12 ⋅ 4

Dubbo-多线程通信原理

本文代码摘录的时候,将一些与本流程无关的内容去掉了,如有需要请看源码。 如果大家对Dubbo RPC原理原理感兴趣,可以看我之前写过的另外一篇博客《Dubbo RPC源码解读》。 一、 思考与目标 ...

小飞哥1112 ⋅ 2017/11/26 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

NFS介绍 NFS服务端安装配置 NFS配置选项

NFS介绍 NFS是Network File System的缩写;这个文件系统是基于网路层面,通过网络层面实现数据同步 NFS最早由Sun公司开发,分2,3,4三个版本,2和3由Sun起草开发,4.0开始Netapp公司参与并主导...

lyy549745 ⋅ 30分钟前 ⋅ 0

Spring AOP 源码分析 - 筛选合适的通知器

1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析。本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出合适的通知器(Advisor...

java高级架构牛人 ⋅ 53分钟前 ⋅ 0

HTML-标签手册

标签 描述 <!--...--> 定义注释。 <!DOCTYPE> 定义文档类型。 <a> 定义锚。超链接 <abbr> 定义缩写。 <acronym> 定义只取首字母的缩写。 <address> 定义文档作者或拥有者的联系信息。 <apple......

ZHAO_JH ⋅ 54分钟前 ⋅ 0

SylixOS在t_main中使用硬浮点方法

问题描述 在某些使用场景中,应用程序不使用动态加载的方式执行,而是跟随BSP在 t_main 线程中启动,此时应用代码是跟随 BSP 进行编译的。由于 BSP 默认使用软浮点,所以会导致应用代码中的浮...

zhywxyy ⋅ 今天 ⋅ 0

JsBridge原理分析

看了这个Github代码 https://github.com/lzyzsd/JsBridge,想起N年前比较火的Hybrid方案,想看看现在跨平台调用实现有什么新的实现方式。代码看下来之后发现确实有点独特之处,这里先把核心的...

Kingguary ⋅ 今天 ⋅ 0

Intellij IDEA神器常用技巧五-真正常用快捷键(收藏级)

如果你觉得前面几篇博文太啰嗦,下面是博主多年使用Intellij IDEA真正常用快捷键,建议收藏!!! sout,System.out.println()快捷键 fori,for循环快捷键 psvm,main方法快捷键 Alt+Home,导...

Mkeeper ⋅ 今天 ⋅ 0

Java 静态代码分析工具简要分析与使用

本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能、特性等方面对它们进行分析和比较,...

Oo若离oO ⋅ 今天 ⋅ 0

SpringBoot自动配置小记

spring-boot项目的特色就在于它的自动配置,自动配置就是开箱即用的本源。 不过支持一个子项目的自动配置,往往比较复杂,无论是sping自己的项目,还是第三方的,都是如此。刚接触会有点乱乱...

大_于 ⋅ 今天 ⋅ 0

React jsx 中写更优雅、直观的条件运算符

在这篇文字中我学到了很多知识,同时结合工作中的一些经验也在思考一些东西。比如条件运算符 Conditional Operator condition ? expr_if_true : expr_if_false 在jsx中书写条件语句我们经常都...

开源中国最帅没有之一 ⋅ 今天 ⋅ 0

vim编辑模式与命令模式

5.5 进入编辑模式 从编辑模式返回一般模式“Esc” 5.6 vim命令模式 命令 :“nohl”=no high light 无高亮,取消内容中高亮标记 "x":保存退出,和wq的区别是,当进入一个文件未进行编辑时,使...

弓正 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部