CephCeph学习之路

Ceph Luminous librbd & libra

2018-08-08  本文已影响34人  KidneyBro

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的作用,需要进一步的研究和分析。

上一篇下一篇

猜你喜欢

热点阅读