Ceph学习——Librados与Osdc实现源码解析

来源:互联网 发布:空间绑定域名教程 编辑:程序博客网 时间:2024/05/16 16:20

  • Librados
    • RadosClient类
    • IoctxImpl
    • AioCompletionImpl
  • OSDC
    • ObjectOperation 封装操作
    • op_target 封装PG信息
    • Op 封装操作信息
    • 分片 Striper

本文介绍Ceph客户端方面的某些模块的实现。客户端主要是实现了接口,对外提供访问的功能。上层可以通过接口来访问Ceph存储。Librados 与 Osdc 位于Ceph客户端中比较底层的位置,Librados 提供了Pool的创建、删除、对象的创建、删除等基本接口;Osdc则用于封装操作,计算对象的地址,发送请求和处理超时。如图:


这里写图片描述

根据LIBRADOS架构图,叙述大概的事件流程。在 Ceph分布式存储实战中 这本书中有如下一段话:
先根据配置文件调用LIBRADOS创建一个RADOS,接下来为这个RADOS创建一个radosclient,radosclient包含3个主要模块(finisher、Message、Objector)。再根据pool创建对应的ioctx,在ioctx中能够找到radosclient。在调用OSDC生成对应的OSD请求,与OSD进行通信响应请求。这从大体上叙述了librados与osdc在整个Ceph中的作用。

Librados

该模块包含两个部分,分别是RadosClient 模块和IoctxImpl。RadosClient处于最上层,是librados的核心管理类,管理着整个RADOS系统层面以及pool层面的管理。而IoctxImpl则对于其中的某一个pool进行管理,如对 对象的读写等操作的控制。

Created with Raphaël 2.1.0RadosClient(Librados模块)IoctxImpl(Librados模块)Objecter(Osdc 模块)

RadosClient类

先看头文件 radosclient.h

class librados::RadosClient : public Dispatcher//继承自Dispatcher(消息分发类){  std::unique_ptr<CephContext,          std::function<void(CephContext*)> > cct_deleter;//unique_ptr智能指针public:  using Dispatcher::cct;  md_config_t *conf;//配置文件private:  enum {    DISCONNECTED,    CONNECTING,    CONNECTED,  } state;//网络连接状态  MonClient monclient;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         MgrClient mgrclient;  Messenger *messenger;//!!!!!!!!!!!!!!!!!!网络消息接口 !!!!!!!!!!!!!!!!!!!!!!!  uint64_t instance_id;  //相关消息分发 Dispatcher类的函数重写  bool _dispatch(Message *m);  ...  ...  bool ms_handle_refused(Connection *con) override;  Objecter *objecter;//!!!!!!!!!!!!!!!!!!!!!!Osdc模块中的 用于发送封装好的OP消息!!!!!!!!!!!!!  Mutex lock;//互斥锁  Cond cond;  SafeTimer timer;//定时器  int refcnt;  ...  ...public:  Finisher finisher;//!!!!!!!!!!!!!!!!!!!执行回调函数的类!!!!!!!!!!!!!!!!!!  ...  ...  //创建一个pool相关的上下文信息  int create_ioctx(const char *name, IoCtxImpl **io);  int create_ioctx(int64_t, IoCtxImpl **io);  int get_fsid(std::string *s);  ...///pool相关操作  ...  bool get_pool_is_selfmanaged_snaps_mode(const std::string& pool);  //同步创建pool 和 异步创建pool  int pool_create(string& name, unsigned long long auid=0, int16_t crush_rule=-1);  int pool_create_async(string& name, PoolAsyncCompletionImpl *c, unsigned long long auid=0,            int16_t crush_rule=-1);  int pool_get_base_tier(int64_t pool_id, int64_t* base_tier);  //同步删除和异步删除  int pool_delete(const char *name);  int pool_delete_async(const char *name, PoolAsyncCompletionImpl *c);  int blacklist_add(const string& client_address, uint32_t expire_seconds);  //Monitor相关命令处理,调用monclient.start_mon_command 把命令发送给Monitor处理  int mon_command(const vector<string>& cmd, const bufferlist &inbl,              bufferlist *outbl, string *outs);  void mon_command_async(const vector<string>& cmd, const bufferlist &inbl,                         bufferlist *outbl, string *outs, Context *on_finish);  int mon_command(int rank,          const vector<string>& cmd, const bufferlist &inbl,              bufferlist *outbl, string *outs);  int mon_command(string name,          const vector<string>& cmd, const bufferlist &inbl,              bufferlist *outbl, string *outs);  int mgr_command(const vector<string>& cmd, const bufferlist &inbl,              bufferlist *outbl, string *outs);  //osd相关命令处理,调用objecrot->osd_command 把命令发送给OSD处理               int osd_command(int osd, vector<string>& cmd, const bufferlist& inbl,                  bufferlist *poutbl, string *prs);  //pg相关命令处理,调用objecrot->pg_command 把命令发送给OSD处理   int pg_command(pg_t pgid, vector<string>& cmd, const bufferlist& inbl,             bufferlist *poutbl, string *prs);             ...             ...             ...};

再来看看其中一些的函数

connect () 是RadosClient的初始化函数。

int librados::RadosClient::connect(){  common_init_finish(cct);  int err;  ...  ...  // get monmap  err = monclient.build_initial_monmap();//检查配置文件里面的初始Monitor信息  if (err < 0)    goto out;  err = -ENOMEM;  messenger = Messenger::create_client_messenger(cct, "radosclient");//创建通信模块  if (!messenger)    goto out;  //设置Policy相关信息        messenger->set_default_policy(Messenger::Policy::lossy_client(CEPH_FEATURE_OSDREPLYMUX));  ldout(cct, 1) << "starting msgr at " << messenger->get_myaddr() << dendl;  ldout(cct, 1) << "starting objecter" << dendl;  //创建objecter并初始化  objecter = new (std::nothrow) Objecter(cct, messenger, &monclient,              &finisher,              cct->_conf->rados_mon_op_timeout,              cct->_conf->rados_osd_op_timeout);  if (!objecter)    goto out;  objecter->set_balanced_budget();  monclient.set_messenger(messenger);  mgrclient.set_messenger(messenger);  objecter->init();  messenger->add_dispatcher_head(&mgrclient);  messenger->add_dispatcher_tail(objecter);  messenger->add_dispatcher_tail(this);  messenger->start();  ldout(cct, 1) << "setting wanted keys" << dendl;  monclient.set_want_keys(      CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD | CEPH_ENTITY_TYPE_MGR);  ldout(cct, 1) << "calling monclient init" << dendl;  //初始化monclient  err = monclient.init();  ...  err = monclient.authenticate(conf->client_mount_timeout);  ...  objecter->set_client_incarnation(0);  objecter->start();  lock.Lock();  //定时器初始化  timer.init();  //finisher对象初始化  finisher.start();  state = CONNECTED;  instance_id = monclient.get_global_id();  lock.Unlock();  ldout(cct, 1) << "init done" << dendl;  err = 0; out: ... ...  return err;}

create_ioctx()用于创建一个pool相关的上下文信息 IoCtxImpl对象。

int librados::RadosClient::create_ioctx(const char *name, IoCtxImpl **io){  int64_t poolid = lookup_pool(name);  if (poolid < 0) {    return (int)poolid;  }  *io = new librados::IoCtxImpl(this, objecter, poolid, CEPH_NOSNAP);  return 0;}

mon_command()用于处理Monitor相关命令

void librados::RadosClient::mon_command_async(const vector<string>& cmd,                                              const bufferlist &inbl,                                              bufferlist *outbl, string *outs,                                              Context *on_finish){  lock.Lock();  monclient.start_mon_command(cmd, inbl, outbl, outs, on_finish);//把命令发送给Monitor处理  lock.Unlock();}

osd_command()处理OSD相关命令

int librados::RadosClient::osd_command(int osd, vector<string>& cmd,                       const bufferlist& inbl,                       bufferlist *poutbl, string *prs){  Mutex mylock("RadosClient::osd_command::mylock");  Cond cond;  bool done;  int ret;  ceph_tid_t tid;  if (osd < 0)    return -EINVAL;  lock.Lock();  //调用objecter->osd_commandf 发送命令给OSD处理  objecter->osd_command(osd, cmd, inbl, &tid, poutbl, prs,            new C_SafeCond(&mylock, &cond, &done, &ret));  lock.Unlock();  mylock.Lock();  while (!done)    cond.Wait(mylock);  mylock.Unlock();  return ret;}

IoctxImpl

该类是pool的上下文信息,一个pool对应一个IoctxImpl对象。librados中所有关于IO操作的API都设计在librados::IoCtx中,接口的真正实现在IoCtxImpl中。它的处理过程如下:
1)把请求封装成ObjectOperation 类(osdc 中的)
2)把相关的pool信息添加到里面,封装成Objecter::Op对像
3)调用相应的函数 objecter- >op_submit 发送给相应的OSD
4)操作完成后,调用相应的回调函数。

AioCompletionImpl

Aio即Async IO,AioCompletion即Async Io Completion,也就是Async IO完成时的回调处理制作,librados设计AioCompletion就是为了提供一种机制对Aio完成时结果码的处理。而处理函数则由使用者来实现。AioCompletion是librados设计开放的库API,真正的设计逻辑在AioCompletionImpl中。

对于AIoCompletion实例的使用都是引用的pc,即AioCompletionImpl,因此具体来说应该是如何包装AioCompletionImpl。这里提一下,librados中所有关于IO操作的API都设计在librados::IoCtx中,接口的真正实现在IoCtxImpl中。而AioCompletionImpl是IO操作的回调,因为对于AioCompletionImpl的包装设计在IoCtxImpl模块中

详细的关于回调机制的分析见:ceph源代码分析之librados:1. AioCompletion回调机制分析

OSDC

该模块是客户端模块比较底层的,模块,用于封装操作数据,计算对象的地址、发送请求和处理超时。

ObjectOperation 封装操作

该类用于将操作相关的参数统一封装在该类中,并且一次可以封装多个操作。代码太长了。。。。OMG,这一块就看书总结把。。。。

struct ObjectOperation {  vector<OSDOp> ops;//操作集合  int flags;  int priority;  vector<bufferlist*> out_bl;//输出缓存队列  vector<Context*> out_handler;//回调函数队列  vector<int*> out_rval;//操作结果队列  ObjectOperation() : flags(0), priority(0) {}  ~ObjectOperation() {    while (!out_handler.empty()) {      delete out_handler.back();      out_handler.pop_back();    }  }  ...  ...  ...}

类OSDop封装对象的一个操作。结构Ceph_osd_op 封装一个操作码和相关的输入输出参数:

struct OSDop{    ceph_osd_op op;//操作码和操作参数    sobject_t soid;    bufferlist indata,outdata    int32_t rval;//操作结果}

op_target 封装PG信息

该结构封装了对象所在的而PG,以及PG对应的OSD列表等信息。

struct op_target_t {    int flags = 0;    epoch_t epoch = 0;  ///< latest epoch we calculated the mapping    object_t base_oid;//读取的对象    object_locator_t base_oloc;//对象的pool信息    object_t target_oid;//最终读取的目标对象    object_locator_t target_oloc;//最终该目标对象的pool信息。    ///< true if we are directed at base_pgid, not base_oid    bool precalc_pgid = false;    ///< true if we have ever mapped to a valid pool    bool pool_ever_existed = false;    ///< explcit pg target, if any    pg_t base_pgid;    pg_t pgid; ///< last (raw) pg we mapped to    spg_t actual_pgid; ///< last (actual) spg_t we mapped to    unsigned pg_num = 0; ///< last pg_num we mapped to    unsigned pg_num_mask = 0; ///< last pg_num_mask we mapped to    vector<int> up; ///< set of up osds for last pg we mapped to    vector<int> acting; ///< set of acting osds for last pg we mapped to    int up_primary = -1; ///< last up_primary we mapped to    int acting_primary = -1;  ///< last acting_primary we mapped to    int size = -1; ///< the size of the pool when were were last mapped    int min_size = -1; ///< the min size of the pool when were were last mapped    bool sort_bitwise = false; ///< whether the hobject_t sort order is bitwise    bool recovery_deletes = false; ///< whether the deletes are performed during recovery instead of peering    ...    ...    ...  };

Op 封装操作信息

该结构体封装了完成一个操作的相关上下文信息,包括target地址信息、连接信息等。

 struct Op : public RefCountedObject {    OSDSession *session;//OSD的相关Session 信息,session是关于connect的信息    int incarnation;    op_target_t target;//地址信息    ConnectionRef con;  // for rx buffer only    uint64_t features;  // explicitly specified op features    vector<OSDOp> ops;//多个操作    snapid_t snapid;快照ID    SnapContext snapc;    ceph::real_time mtime;    bufferlist *outbl;    vector<bufferlist*> out_bl;    vector<Context*> out_handler;    vector<int*> out_rval;

分片 Striper

当一个文件到对象的映射时,对象有分片,则使用这个类来分片,并保存分片信息。

 class Striper {  public:    /*     * map (ino, layout, offset, len) to a (list of) ObjectExtents (byte     * ranges in objects on (primary) osds)该函数完成file到对象stripe后的映射。     */    static void file_to_extents(CephContext *cct, const char *object_format,                const file_layout_t *layout,                uint64_t offset, uint64_t len,                uint64_t trunc_size,                map<object_t, vector<ObjectExtent> >& extents,                uint64_t buffer_offset=0  };

其中 ObjectExtent保存的是对象内的分片信息。

class ObjectExtent { public:  object_t    oid;       // object id  uint64_t    objectno;//分片序号  uint64_t    offset;    // 对象内的偏移  uint64_t    length;    // 长度  uint64_t    truncate_size;    // in object  object_locator_t oloc;   // object locator (pool etc)位置信息 如在哪个pool};
原创粉丝点击