glusterfs通信rpc怎么用

这篇文章主要介绍“glusterfs通信rpc怎么用”,在日常操作中,相信很多人在glusterfs通信rpc怎么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”glusterfs通信rpc怎么用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

站在用户的角度思考问题,与客户深入沟通,找到磁县网站设计与磁县网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都做网站、成都网站制作、成都外贸网站建设、企业官网、英文网站、手机端网站、网站推广、空间域名、雅安服务器托管、企业邮箱。业务覆盖磁县地区。

在glusterfs中,gluster与glusterd通信请求对卷的操作、集群的操作、状态的查看等;glusterd与glusterfsd通信完成对卷的操作,集群的操作,状态的查看;glusterfs与glusterfsd通信完成文件的存储。所有这些通信都是通过内部的RPC模块来完成的。

=========================================

从代码的组织来看,RPC的服务端逻辑上可分为四层,server-app、rpc-server、rpc-transport、protocol,每一层都提供相应的接口供上一层调用,同时,上一层会提供回调函数供下一层来调用;同样,RPC的客户端逻辑上也可分为四层,cli-app、rpc-cli、rpc-transport、protocol。目前,protocol提供了tcp(socket)和rdma两种方式,且都以动态库的方式提供,rpc-transport会根据配置加载不同的动态库。我们以gluster与glusterd的通信并选用tcp的方式为例来看看RPC相关流程。

1. 服务端的初始化

需要注意的是:rpc_transport_load时会根据协议的类型加载(使用dlopen)不同的动态库,调用socket_listen时将fd与回调函数添加事件驱动器中。当有读写事件时,事件驱动器回调socket_server_event_handler函数(用于服务端的accept)或者socket_event_handler函数(用于一般的请求),然后依次回调rpc_transport_notify、rpcsvc_notify处理RPC请求。

2. 客户端的初始化

socket_connect函数会将fd以及回调处理函数注册到事件驱动器中。

3. 一次完整的RPC流程

(1) 客户端发送RPC请求

客户端通过调用rpc_clnt_submit函数发送RPC请求,该函数又会一层层调用,最终在socket_submit_request中通过writev将请求发送出去。在调用rpc_clnt_submit时会准备好RPC所需要的相关数据,例如程序号,程序版本号,过程号,参数信息等等,然后逐层按照接口组织好相关的数据。

例如: 执行 gluster volume info命令,其内部关键代码:

int32_t gf_clie_1_get_volume(call_frame_t * frame, xlator_t * this)
{
    ...
    ret = cli_cmd_submit(&req,
                         frame,
                         cli_rpc_prog, //包含程序名,程序号,程序版本号等信息
                         GLUSTER_CLI_GET_VOLUME, //过程号
                         NULL,
                         this,
                         gf_cli3_1_get_volume_cbk, //结果处理回调函数
                         (xdrproc_t)xdr_gf_cli_req);
    ..
}

int cli_cmd_submit(void *req, call_frame_t * frame,
                   rpc_clnt_prog_t * prog, int procnum,
                   struct iobref * iobref,
                   xlator_t * this, fop_cbk_fn_t cbkfn,
                   xdrproc_t xdrproc)
{
    ...
    ret = cli_submit_request(req, frame, prog, procnum, NULL, this,
                             cbkfn, xdrproc);
    ...
}

int cli_submit_request(void * req, call_frame_t * frame,
                       rpc_clnt_prog_t * prog, int procnum,
                       struct iobref * iobref,
                       xlator_t * this, fop_cbk_fn_t cbkfn,
                       xdrproc_t xdrproc)
{
    ...
    ret = rpc_clnt_submit(global_rpc, prog, procnum, cbkfn,
                          &iov, count, NULL, 0, iobref, frame,
                          NULL, 0, NULL, 0, NULL)
}

int rpc_clnt_submit(struct rpc_clnt * rpc,
                    rpc_clnt_prog_t * prog, int procnum,
                    fop_cbk_fn_t cbkfn,
                    struct iovec * proghdr, int proghdrcount,
                    struct iovec * progpayload, int progpayloadcount,
                    struct iobref * iobref, void * frame,
                    struct iovec * rsphdr, int rsphdr_count,
                    struct iovec * rsp_payload,int rsp_payload_count,
                    struct iobref * rsp_iobref)
{
    struct iobuf * request_iob = NULL;
    rpc_transport_req_t req;
    ...
    request_iob = rpc_clnt_record(rpc, frame, prog, procnum, proglen,
                                  &rpchdr, callid);
    req.msg.rpchdr = &rpchdr;
    req.msg.rpchdrcount = 1;
    req.msg.proghdr = proghdr;
    req.msg.proghdrcount = proghdrcount;
    req.msg.progpayload = progpayload;
    req.msg.progpayloadcount = progpayloadcount;
    req.msg.iobref = iobref;
    ...
    ret = rpc_transport_submit_request(rpc->conn.trans, &req);
    ...
}

int32_t rpc_transport_submit_request(rpc_transport_t * this,
                                     rpc_transport_req_t * req)
{
    ret = this->ops->submit_request(this, req);
}

int32_t socket_submit_request(rpc_transport_t * this,
                              rpc_transport_req_t * req)
{
    struct ioq * entry = NULL;
    entry = __socket_ioq_new(this, &req->msg);

    ret = __socket_ioq_churn_entry(this, entry);
    ...
}

int __socket_ioq_churn_entry(rpc_transport_t *this,
                             struct ioq * entry)
{
    ret = __socket_writev(this, entry->pending_vector,
                          entry->pending_count,
                          &entry->pending_vector,
                          &entry->pending_count);
    ...
}

int __socket_writev(rpc_transport_t * this,
                    struct iovec * vector, int count,
                    struct iovec **pending_vector, int *pendint_count)
{
    ret = __socket_rwv(this, vector, count, pending_vector,
                       pending_count, NULL, 1);
    ...
}

int __socket_rwv(rpc_transport_t *this, struct iovec *vector,
                 int count, struct iovec **pending_vector,
                 int * pending_count, size_t * bytes, int write)
{
    int opcount = 0;
    struct iovec * opvector = NULL;

    opvector = vector;
    opcount = count;
    while(opcount)
    {
        if(write)
        {
            ret = wrtiev(sock, opvector, opcount);
        }
        ...
    }
    ...
}

(2) 服务端处理RPC请求

服务端收到请求后,从socket_event_handler回调到rpc_transport_notify,再回调到rpcsvc_notify,最终调用rpcsvc_handle_rpc_call函数。在这个函数中,解析客户端RPC请求中包含的程序号,过程号以及相关参数等,然后根据这些程序号,过程号找到对应的处理函数。而这些处理函数就是先前通过rpcsvc_program_register函数注册的。对应的处理函数处理完成后调用相关函数答复客户端。

注: actor并不是一个真正的函数,仅标识不同RPC请求的处理函数.

(3) 客户端处理RPC的回复

客户端在发送请求时,会将请求的相关信息缓存下来,当收到服务器的回应后,再根据程序号、过程号找到对应的请求信息,然后调用相应的回调函数对请求结果进行处理。

到此,关于“glusterfs通信rpc怎么用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!


分享文章:glusterfs通信rpc怎么用
链接分享:http://azwzsj.com/article/ghhcsd.html