Ceph学习——Librbd块存储库与RBD读写流程源码分析

本文深入探讨Ceph的Librbd库,解析RBD块存储的元数据管理和读写流程。通过Librbd,Ceph实现了基于librados的块存储接口。RBD的创建涉及元数据设置,数据读写通过ImageRequestWQ、ImageRequest和ObjectRequest处理,将块拆分为对象进行操作。文中还介绍了Cls扩展模块和RBD的元数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值