ceph rbd:nbd原理

前言

rbd是ceph提供的块存储服务。主要有几种使用场景:

  • map成块设备直接使用
  • 结合iSCSI使用
  • 结合OpenStack使用

map成块设备,主要有两种方式:

  • 通过RBD Kernel Module
  • 通过RBD-NBD

经过考察,发现RBD Kernel Module项目更新缓慢,其功能已经远远落后于librbd提供的功能。像striping、object map、exclusive lock等功能均不支持。

RBD-NBD方式,基于Network Block Device(nbd)实现,并且nbd已经经过了很长时间的实践,稳定性有所保证。对块设备的请求,由nbd间接调用librbd完成,可以支持最新的特性,是比较理想的方式。

下文将对rbd通过nbd进行读写和map的实现进行介绍。

nbd

nbd是一种起源于linux的轻量级块访问协议,可以让你将任何存储方式作为操作系统的块设备来使用。它主要分成两部分,server端和client端。client端位于linux内核。server端需要由你实现。

当我们对/dev/nbdx设备发起io操作时,会由内核中的nbd client封装成nbd请求通过tcp网络发送给对应的nbd server,server端解析请求,做出处理后,返回结果到nbd client端。

image.png

有关协议的内容和操作方式,见官方文档。
注意,这里文档里称内核中的部分为server,我们实现的部分为client。

rbd-nbd

ceph社区为nbd实现了一个server,这个server会接收来自内核中nbd的请求,然后转调librdb完成请求,返回结果。

rbd对nbd的支持全部位于rbd-nbd.cc文件,大概1000行代码。

命令基本实现

  • 使用rbd-nbd map image-spec|snap-spec 命令将一个rbd镜像map到块设备,是fork出一个server进程,并为该server进程和内核client指定通信所用的socket fd。当然,还要为client设置timeout、block size、device size等等一些参数,以及一些flags。之后,server进程会运行两个线程,然后调用ioctl(nbd, NBD_DO_IT)进入阻塞状态,直到unmap过程中调用ioctl(nbd, NBD_DISCONNECT)。一个为读线程,接收来自client的请求,解析后放入一个pending队列,然后调用image.aio_write``image.aio_read``image.aio_flush等命令异步执行操作,在其完成后会调用提前注册的回调函数,将请求从pending队列转移到finish队列。另一个为写线程,finish队列为空时,写线程阻塞,当finish队列不为空时,写线程负责从finish队列中取出完成的请求,将结果返回给nbd client端。
  • 使用rbd-nbd unmap devpath命令进行unmap操作,其实只有两行代码: int nbd = open_device(devpath.c_str())ioctl(nbd, NBD_DISCONNECT)(NBD_DISCONNECT是nbd的协议原语之一)。
  • 使用rbd-nbd list-mapped命令查看所有map的nbd设备和rbd镜像的对应关系,其步骤是:从x=0开始遍历,通过/sys/block/nbd/pid获取该nbd设备对应的server进程pid,然后通过/proc//cmdline获取该进程启动时的命令(肯定是rbd-nbd map image-spec|snap-spec),通过解析cmdline来获得image、pool等信息。

一些要点

  • rbd-nbd server与client的通信是使用socketpair(AF_UNIX, SOCK_STREAM, 0, fd)产生fd进行的。client端通过fd[0]向server发送请求与接收结果。server端通过fd[1]接收client端发送的请求,并返回结果。
  • 通过nbd map的块设备只可能有两个cache,一个是内核中的块设备缓存,一个是librbd的缓存。nbd本身没有做缓存。
  • rbd-nbd会监控rbd image size的变化,发生变化时,会依次清空blk设备缓存ioctl(fd, BLKFLSBUF, NULL),设置新size到nbd clientioctl(fd, NBD_SET_SIZE, new_size),重新扫描分区表ioctl(fd, BLKRRPART, NULL),清空image缓存image.invalidate_cache()

写的不是很详细,有问题私戳我吧。。

参考

https://sourceforge.net/p/nbd/code/ci/master/tree/doc/proto.md
https://nbd.sourceforge.io/
https://github.com/ceph/ceph/blob/master/src/tools/rbd_nbd/rbd-nbd.cc

你可能感兴趣的:(ceph rbd:nbd原理)