Librbd是Ceph提供块存储的库,它实现了RBD接口,基于LIbrados实现了对RBD的基本操作。Librbd对于元数据的相关操作是通过cls_rbd实现的。cls_rbd是Cls的一个扩展模块,Cls允许用户自定义对象的操作接口和实现方法,为用户提供了一种比较直接的接口扩展方式。Librbd的数据读写相关操作则是通过直接Librados来直接访问。
Librbd 包含了rbd的相关操作,并发送给ImageRequestWQ类处理(队列),而后该类将其中的的请求发送给ImageRequest处理,ImageRequest将Image进行分片(将一个 块 分解成 对象 进行处理,Ceph的底层本质还是对象存储) 等操作后,将各个对象调用ObjectRequest类进行处理 ,每个ObjectRequest请求分别处理。ImageRequest和ObjectRequest下面都包含很多相关操作的子类,用子类实现了具体的接口。关于RBD的读写流程用了函数调用的流程图表示,思路更加清晰,并且最新版本函数、类的名字都改变了。
结构如图:
Cls——Ceph的扩展模块
cls_rbd是Cls的一个扩展模块,Cls允许用户自定义对象的操作接口和实现方法,为用户提供了一种比较直接的接口扩展方式。
该模块下包含几个文件:
1)cls_rbd_types 主要是注册了rbd模块,以及自定义的一些方法
...
...
...
//对应的方法
int create(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
{
string object_prefix;
uint64_t features, size;
uint8_t order;
int64_t data_pool_id = -1;
try {
bufferlist::iterator iter = in->begin();
::decode(size, iter);
::decode(order, iter);
::decode(features, iter);
::decode(object_prefix, iter);
if (!iter.end()) {
::decode(data_pool_id, iter);
}
} catch (const buffer::error &err) {
return -EINVAL;
}
...
...
...
//注册模块以及方法
cls_register("rbd", &h_class);
cls_register_cxx_method(h_class, "create",
CLS_METHOD_RD | CLS_METHOD_WR,
create, &h_create);
...
...
...
2)cls_rbd_client 定义了客户端访问rbd函数。调用模块和客户端的读写操作流程类似,都是通过ioctx->ecex 函数,封装操作并发送给对应的OSD处理。见( 超链接留空 )
Librbd 库
RBD是ceph中提供块存储的客户端服务,之所以说是客户端服务是相对于RADOS而言,RBD是基于librados API开发的一个块存储服务。Ceph底层的实现是对象存储,通过librbd实现了块存储的接口,对外提供块存储的服务。
所以,块存储在客户端也会被拆成n个对象来存储处理。
下面摘取
麦子迈:解析Ceph: Librbd–块存储库 中的基础名词介绍。
Image: 对应于LVM的Logical Volume,是能被attach/detach到VM的载体。在RBD中,Image的数据有多个Object组成。(image 镜像 可以作是块存储的呈现形式)
Snapshot: Image的某一个特定时刻的状态,只能读不能写但是可以将Image回滚到某一个Snapshot状态。Snapshot必定属于某一个Image。
- Clone: 为Image的某一个Snapshot的状态复制变成一个Image。如ImageA有一个Snapshot-1,clone是根据ImageA的Snapshot-1克隆得到ImageB。ImageB此时的状态与Snapshot-1完全一致,区别在于ImageB此时可写,并且拥有Image的相应能力。
关于 块存储 原理的一些东西,可以操作集群 实际看看:Ceph介绍之RBD实现原理
RBD元数据
当在一个pool里面创建一个RBD对象的时候,会对应的生成其它的对象以及相关的元数据用于管理rbd。
- rbd _dircetory对象:该对象在每一个Pool都存储在,用来保存该pool下的所有的RBD的目录信息。当创建RBD设备的时候,会首先检查该对象的存在,如无则创建。该对象中包含了 Ceph中专门用于存储元数据 的结构omap。该omap属性里保存了所有RBD设备的名字和ID信息。在omap属性中 保存这key-value键值对,key为 “name”+设备名字,value为”_id“+RBD的ID 。
- 另外还会创建id_obj对象:对象名字为 rbd_id. ,内容为RBD的ID信息。
- head_obj对象:其中的omap保存了RBD相关的元数据。
- rbd_object_map. :保存其对象和父image对象的映射信息。
另外还会创建数据对象 ,用于存储数据,因为Ceph存储的本质就对象存储,所以即使提供的块存储也要拆分成对象来管理。
源码目录简单介绍
librbd 模块下的源代码现在文件比较多。根据网上别人的总结。。。。
http://blog.youkuaiyun.com/scaleqiao/article/details/51165598
1)operation, 这个目录里实现了关于image的主要操作,包括flatten、resize、trim、snapshot create、snapshot remove、snapshot protect、snapshot unprotect、snapshot rename、snapshot rollback
2)librbd.cc,这个文件里并没有具体实现所有的接口,而其实大部分接口的具体实现是在internal.cc,除了I/O相关的接口,read/write。
3) ImageCtx.h和ImageCtx.cc,定义了image的上下文,包括image layout的初始化、卷/snap相关元数据的获取接口以及后来引入的rbd mirror的相关元数据结构(object map、journal 等)的创建。
4)AioImageRequestWQ.h/AioImageRequestWQ.cc、AioImageRequest.h/AioImageRequest.cc,实现了aio相关的I/O接口,进入rbd的read请求会转变成一个AioImageRead的实例,而write请求会变成一个AioImageWrite的对象。而这些对象最终会分别调到AioImageRead.send_request()和AbstractAioImageWrite::send_request()这两个函数,来处理IO请求(其中主路径中关于journal的部分可以先略过去)。
5) AioObjectRequest.h/AioObjectRequest.cc,I/O请求会通过Striper::file_to_extents()被影射成针对某个/某些对象的操作,这些操作都被定义/实现在这两个文件中
6) AioCompletion.h/AioCompletion.cc,这两个文件实现了Aio的回调处理逻辑。上层应用可以通过rbd_aio_create_completion()创建一个AioCompletion的对象,并传入自己的回调函数。这样当具体操作结束之后,AioCompletion对象会调用上层应用的回调函数
7) LibrbdWriteback.h/LibrbdWriteback.cc,这两个文件主要是通过现有的ObjectCacher机制,在librbd中支持Writeback这种I/O方式
8) ImageWatcher.h/ImageWatcher.cc,这是后来引入的watch/notify机制,用于增加了管理image exlusive lock的支持
9) 日志 Journal*,这些文件主要实现rbd mirror的功能
10)CopyupRequest.h/CopyupRequest.cc,这个主要用于处理clone卷的逻辑
看完思路清晰不少。但是目前最新的版本而言,改动了一些,主要是名字的AIo都没了。 但是跳转的处理逻辑依然还是差不多 集中在 ImageRequestWQ、ImageRequest、ObjectRequest之中。
RBD的创建
rbd有很多个创建函数。根据传入的参数不同来调用不同的函数。其过程比较简单,都是调用librbd::create来设置相应的参数。RBD的创建过程,其本质是调用Cls的RBD模块设置相关的元数据信息。相关的元数据的操作函数也一样。
int RBD::create(IoCtx& io_ctx, const char *name, uint64_t size, int *order)
{
TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
tracepoint(librbd, create_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, *order);
int r = librbd::create(io_ctx, name, size, order);//设置参数
tracepoint(librbd, create_exit, r, *order);
return r;
}
...
...
...
int RBD::create4(IoCtx& io_ctx, const char *name, uint64_t size,
ImageOptions& opt