美文网首页CephCeph学习之路
Ceph Luminous librbd & libra

Ceph Luminous librbd & libra

作者: KidneyBro | 来源:发表于2018-08-08 18:43 被阅读34次

    0 本文概述

    本文将对通过终端cli在Ceph集群中创建image的流程进行解析

    1 流程时序图

    image.png

    2 代码走读

    2.1 命令行处理:/src/tools/

    2.1.1 rbd.cc

    rbd.cc提供main函数入口,作为主程序的入口,调用shell.cc中的execute()函数,对指令进行解析。

    main()

    2.1.2 shell.cc

    shell.cc解析命令行,并通过封装的Action类调用对应的文件,对应当前目录下的Action文件。对于create而言,这里调用create.cc文件。

    2.1.3 Action/create.cc

    do_create()

    在execute()函数中调用librados和IoContext并初始化,之后调用do_create().

    do_create()

    2.2 librbd层:src/librbd/

    2.2.1 librbd.cc

    librbd提供相应的接口,具体实现在interval.cc中,本文中create image操作使用create4()实现对create()接口的封装。

    create4()
    creae()
    create()

    通过create()接口,调用interval.cc中create()函数,interval.cc提供这些接口的实现(line 820 to line 877).

    在create()函数中,librbd获取image id和相应的参数,并根据format的新旧使用调用不同的接口。v1现在已被废弃。使用v2来完成image create。
    对于新format信息,调用当前目录中image目录中的CreateRequest.cc中send()函数进行调用。

    2.2.2 /src/librbd/image/CreateRequest.cc

    librbd中,将每个操作的具体实现都封装成了<operation>Request.cc/h文件,operation对应每个具体的操作,如当前的create操作的具体实现就是createRequest.cc/h中。

    CreateRequest

    如上,头文件给出了类的定义,send实现在.cc文件中。头文件还给出了CreateRequest.cc实现image create的函数调用流程图。

    流程图

    函数声明方面,函数和回调函数成对声明,回调函数以handle_开头区分。

    函数和回调函数
    send()
    validate pool()

    上面的函数实现中可以看出,send()函数调用validate_pool()函数,在validate_pool()函数中,封装并调用回调函数handle_validate_pool()函数,校验rbd_directory对象是否存在,下一步的操作在回调函数中调用。其中aio_operate()实际执行回调函数。

    handle_validate_pool()

    validate_overwrite()作用是校验rbd_info的内容。

    validate_overwrite
    handle_validate_overwrite()

    在handle_validate_overwrite()函数中,如果rbd_info存在并且内容为“overwrite validated”, 直接进入下一状态,调用create_id_object(),创建rbd_id.<image_name>对象。

    create_id_object

    create_id_object()函数中,先调用了cls_client::set_id()创建rbd_id,之后又使用回调函数,这里个人观点为cls的函数需要回调函数触发。在回调函数中,调用add_image_to_directory()函数进入下一状态。

    add_image_to_directory()

    add_image_to_directory()作用为在rbd_directory对象中加入该image的id和name。

    negotiate_features()

    negotiate_features()中,会首先获取所有的feature,之后触发回调函数,将返回的feature decode到all_features中,之后调用create_image(),进入下一状态。

    create_image()
    get_all_fetures_start()

    在create_image()中,通过cls注册的函数创建rbd_header对象,并设置omap中的值,调用回调函数完成创建。

    handle_create_image()
    set_stripe_unit_count()

    之后代码遵循类似的流程,都是通过cls_client注册的函数 + 回调函数完成该状态功能,并调用函数,进入下一状态。调用的函数顺序为:

    set_strip_unit_count() -> handle_strip_unit_count() -> object_map_resize() -> handle_object_map_resize() -> fetch_mirror_mode() -> handle_fetch_mirror_mode() -> journal_create() -> handle_journal_create() -> mirror_image_enable() -> handle_mirror_image_enable()

    在一系列的调用完成后,调用complete()函数,传入的参数为0。

    complete()

    在complete()函数中,释放数据对象上下文,调用CreateRequest回调函数,完成步骤。

    2.2.3 cls/rbd/cls_rbd_client.cc

    在前文的Request调用中,使用回调函数进入下一状态之前,会先调用cls模块进行注册,cls模块针对rbd的实现在cls_rbd_client.cc文件中。

    set_id()
    dir_add_image()
    create_image()
    set_stripe_unit_count()

    cls_client模块负责注册部分元数据操作。从调用的代码可以看出,cls_client下函数不会直接执行,而通过librados::ObjectOperation的exec()执行。在下一节可以看到,cls_client调用的操作在最终的OSDC层完成函数注册,但并不会实际调用。

    需要注意的是,具体到image的创建,实际上只会记录一些image的基本信息。比如创建元数据对象rbd_id.foo和rbd_header.foo,对于image的真正数据对象rbd_data*,根本不会创建,这是因为ceph选择thin-provisioning这种凡事,可以做到秒级创建快设备,后段也可以超额分配容量。

    2.3 librados层:src/librados/

    librbd中cls_client的注册和回调函数的触发都在librados中实现。

    2.3.1 librados.cc / librados.h

    librados组件提供了cls_client注册函数需要的ObjectOperation的定义和接口实现,和IoctxImpl相关函数接口的封装。

    cls_client调用的exec()函数的实现如下,函数中初始化ObjectOperationImpl实例,并调用其成员变量o的call()函数。

    exec()
    ObjectOperationImpl

    代码中成员变量o的类型ObjectOperation来自雨OSDC层的Objecter组件,具体实现将在OSDC层中进行进一步讨论。

    librbd中,真正触发回调函数是通过aio_operate()完成的,librados中提供了该接口,具体实现是封装了IoctxImpl的aio_operate()接口,最终实现是在IoctxImpl中完成。

    aio_operate()

    2.3.2 IoctxImpl.cc

    aio_operate()

    IoctxImpl中,::ObjectOperation op实际上是引用的src/osdc/Objecter.cc里面定义的类,初始化之后,通过op将消息发送给osd。真正使用osdc中的Objecter.cc中的组件的地方是operator()和aio_operate()函数。

    2.4 OSDC 层:src/osdc

    osdc层直接与osd进行通信,调用objecter.cc/objecter.h组件来实现消息的发送。

    2.4.1 objecter.cc

    objecter.cc提供对上层消息的封装,并将这些消息发送给osd,完成各项操作。

    在librados层,cls_client调用的ObjectOperation的定义在objector.h中。

    ObjectOperation

    代码中各项成员变量的含义为

      out_bl: 用于存放ops每个操作的输出内容
      out_handler: 存放ops每个操作完成后执行的回调函数
      out_rval: 存放ops每个操作的返回值
    

    librados层中注册函数时调用的call函数的定义如下

    call()
    add_call()

    add_op()为其核心操作,作用是将ops数组中增加一个op,但不执行操作。

    add_op()

    最终的执行操作是通过aio_operate()函数在osdc层调用的op_submit()函数完成的。

    op_submit()
    _op_submit()
    _op_submit()
    _send_op()
    _send_op()

    从上述代码可以看出,在Objecter类中,遵循op_submit() -> _op_submit() -> _send_op()的调用顺序。

    3 备注

    [注] 参考链接ceph-librbd-create-image.html
    [注] 从相关资料描述来看,RadosClient是其核心管理类,处理Rados层和Pool层管理,但是在当前的解析中并未体现RadosClient的作用,需要进一步的研究和分析。

    相关文章

      网友评论

      • blackpiglet:很棒,建议以后用代码用代码块,个人感觉比图片效果要好一些。
        KidneyBro:@blackpiglet 当时看的时候用的是sourceInsight,换肾本之后资料都丢了,就先凑活着用了,见谅见谅,新的文章争取上代码块233333
      • KidneyBro:第一次用markdown写 马克一下

      本文标题:Ceph Luminous librbd & libra

      本文链接:https://www.haomeiwen.com/subject/devxbftx.html