标签:
本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成:
(1)安装和部署
(3)Ceph 与 OpenStack 集成的实现
(4)TBD
Ceph 作为一个统一的分布式存储,其一大特色是提供了丰富的编程接口。我们来看看下面这张经典的图:
其中,librados 是 Ceph 的基础接口,其它的接口比如 RADOSGW, RBD 和 CephFS 都是基于 librados 实现的。本文试着分析下 Ceph 的各种接口库和常用的工具。
Ceph 提供一个消息层协议(messaging layer protocol)使得 ceph 客户端可以和 Ceph Monitor 以及 Ceph OSD Daemon 交互。librados 就是一个该协议的编码库形式的实现。所有的 Ceph clients 要么使用 librados 要么使用其封装的更高层 API 与对象存储进行交互。比如,librbd 使用 librados 提供 Ceph 客户端与 RBD 交互 API。
librados 是使用 C++ 实现的,同时也提供 C, python,Java 和 PHD 语言的绑定。使用它之前,你需要安装它:
一个 Ceph client 通过 librados 存放或者读取数据块到 Ceph 中,需要经过以下步骤:
可见,第一步中,ceph client 需要知道 Ceph Minotor 的访问方法,以及用户的身份信息,而这些信息往往是放在 ceph 配置文件中,比如:
[global] mon host = 192.168.1.1 keyring = /etc/ceph/ceph.client.admin.keyring
Python rados 模块是 librados 的 Python 的很薄的封装,它在 github 上的源文件在 /src/pybind/rados.py, 安装到 Ubunt 后的源文件在 /usr/lib/python2.7/dist-packages/rados.py。
(1)要使用 rados.py 模块,在你的代码中 import rados
(2)创建一个 cluster handler,你需要提供 ceph.conf 文件和 keystring
import rados, sys #Create Handle Examples. 你有多种方式来指定 ceph.conf (1)cluster = rados.Rados(conffile=‘ceph.conf‘) #默认路径的 ceph.conf (2)cluster = rados.Rados(conffile=sys.argv[1]) #指定路径的 ceph.conf (3)cluster = rados.Rados(conffile = ‘ceph.conf‘, conf = dict (keyring = ‘/path/to/keyring‘)) #默认路径的 ceph.conf 和指定的 keystring
(3)连接到 ceph cluster
cluster.connect()
(4)获取 ceph cluster 的信息,以及操作 pool
cluster_stats = cluster.get_cluster_stats()
pools = cluster.list_pools()
cluster.create_pool(‘test‘)
cluster.delete_pool(‘test‘)
(5)向 ceph 集群读写数据,需要有一个 I/O Context (ioctx)
ioctx = cluster.open_ioctx(‘data‘)
(6)然后就可以读写数据了
ioctx.write_full("hw", "Hello World!") #向 “hw” object 写入 "Hello World!" print ioctx.read("hw") #读取 ”hw“ object 的数据 ioctx.remove_object("hw") #删除 “hw” object
更多的信息,可以参考 LIBRADOS (PYTHON)。
RBD shi Rados Block Device 的缩写,而 librbd 是访问 RBD 的库。它调用 librados C 语言绑定,以及与Linux 内核中的 rbd 模块通信,来提供 RMD image 的创建、删除、映射和删除映射等操作。其中,创建和删除等操作是调用 librados,而将 RDB Image 映射到主机上则是调用 Linux rbd 内核模块:
// MapDevice maps an image to a device on the host. Returns the device path and // any errors. On error, the device path will be blank. func (img *Image) MapDevice() (string, error)
librbd 的源代码在 https://github.com/contiv/librbd,是使用 Go 语言实现的,调用 librados 的 C 库以及linux 内核模块,在 Ubuntu 14 上它的文件在 /usr/lib/x86_64-linux-gnu/librbd.so.1。它支持:
rbd python 模块 rbd.py 的源代码在 https://github.com/ceph/ceph/blob/master/src/pybind/rbd.py,它是 librbd 的一个 python 封装。
def load_librbd(): """ Load the librbd shared library. """ librbd_path = find_library(‘rbd‘) if librbd_path: return CDLL(librbd_path) # try harder, find_library() doesn‘t search LD_LIBRARY_PATH # in addition, it doesn‘t seem work on centos 6.4 (see e46d2ca067b5) try: return CDLL(‘librbd.so.1‘) except OSError as e: raise EnvironmentError("Unable to load librbd: %s" % e)
它只封装了 librbd 中的同步操作。它主要提供了 RBD、Image 和 SnapIterator 三个类。在 Ubuntu 上,安装 python-rbd 包就可以在你的机器上找到该文件:/usr/lib/python2.7/dist-packages/rbd.py。 提供类似文件访问的方式去访问 ceph RBD image (连接-打开-使用-关闭)。该模块除了提供主要三个类 Rados, Ioctx, 和Image (Rados 对应于 ceph 集群;Ioctx 对应于 pool;Image 对应于 RBD Image)以外,还封装了 librdb 的返回值作为 Error 类。rbd 模块还提供 Error 类的具体的子类,比如 PermissionError 和 IOError。
#使用 rbd 之前,连接到 RADOS,并打开一个 IO context (和特定 pool 相关) cluster = rados.Rados(conffile=‘my_ceph.conf‘) cluster.connect() ioctx = cluster.open_ioctx(‘mypool‘) #初始化一个 RBD 对象 rbd_inst = rbd.RBD() size = 4 * 1024**3 # 4 GiB #创建 image rbd_inst.create(ioctx, ‘myimage‘, size) #初始化 image 对象 image = rbd.Image(ioctx, ‘myimage‘) #准备 600 个字符的数据 data = ‘foo‘ * 200 #写入数据 image.write(data, 0) #关闭 image 对象 image.close() #关闭 IO Context ioctx.close() #关闭连接 cluster.shutdown()
更优化的编码方式:
with rados.Rados(conffile=‘my_ceph.conf‘) as cluster: with cluster.open_ioctx(‘mypool‘) as ioctx: rbd_inst = rbd.RBD() size = 4 * 1024**3 # 4 GiB rbd_inst.create(ioctx, ‘myimage‘, size) with rbd.Image(ioctx, ‘myimage‘) as image: data = ‘foo‘ * 200 image.write(data, 0)
使用 Ceph 的块存储有两种路径:
两种途径的接口实现不完全相同。就目前来说,前者是目前更稳定的途径,也是Ceph所有应用场景中最广泛使用的。网上多篇文章认为目前内核模块尚不稳定,建议尽量不要使用。
QEMU 通过 librbd 库访问 RBD,而 librbd 是调用 librados。
QEMU 对 librbd 的调用关系可以使用 ldd 命令查看:
root@compute1:~# ldd /usr/bin/qemu-system-x86_64 | grep rbd librbd.so.1 => /usr/lib/x86_64-linux-gnu/librbd.so.1 (0x00007f76ef9e8000)
qemu-img 命令支持直接创建 rbd 镜像,比如:
qemu-img create -f rbd rbd:vmimages/ubuntu-newdrive 2G
然后可以使用 virsh 将它定义为一个 device,下面是 device.xml 文件:
<disk type=‘network‘ device=‘disk‘> <driver name=‘qemu‘ type=‘raw‘/> <auth username=‘vmimages‘> <secret type=‘ceph‘ uuid=‘76e3a541-b997-58ac-f7bd-77dd7d4347cb‘/> </auth> <source protocol=‘rbd‘ name=‘vmimages/ubuntu-newdrive‘> <host name=‘192.168.0.100‘ port=‘6789‘/> </source> <target dev=‘vdc‘ bus=‘virtio‘/> </disk>
然后该 device 添加到虚机中即可。虚机访问 RBD 设备是通过:
我们知道,Linux Kernel 中的块设备驱动是 virtio_blk,它会对虚机的块设备各种请求封装成一个消息通过 virtio 框架提供的队列发送到 QEMU 的 IO 线程,QEMU 收到请求后会转给相应的 QEMU Block Driver 来完成请求,当使用 RDB 时 QEMU block driver 会调用 librbd 来访问 Ceph RDB 设备。
rbd 工具也可以调用 Linux RBD 内核模块来将 RBD Image 挂载到Linux 主机上作为一个新的设备。一开始,该内核模块并没有被加载,但是在执行了 rbd map 操作后,libceph 模块自动被加载:
root@compute2:~# lsmod | grep rbd #此时,rbd 内核模块还没有被加载
root@compute2:~# rbd -n client.cinder map vms/smb01_d1 #做 rbd map 操作
/dev/rbd1
root@compute2:~# lsmod | grep rbd #此时, rbd 内核模块已经被自动加载
rbd 63787 1
libceph 225461 1 rbd
root@compute2:~# rmmod rbd #这时候,rbd 内核模块也无法被卸载
rmmod: ERROR: Module rbd is in use
在看 rbd 的帮助,我们要可以看到 map,unmap,showmapped 命令确实调用的是 rbd 内核模块:
map <image-name> map image to a block device using the kernel unmap <device> unmap a rbd device that was mapped by the kernel showmapped show the rbd images mapped by the kernel
过程:
#创建一个 RDB Image root@compute1:~# rbd -n client.cinder create vms/smb01_d2 --size 1000 --image-format 2
#将 Image map 给主机
root@compute1:~# rbd -n client.cinder map vms/smb01_d2 /dev/rbd2
#列表已经被映射的 RDB Image
root@compute1:~# rbd showmapped
id pool image snap device
1 vms smb01_d1 - /dev/rbd1
2 vms smb01_d2 - /dev/rbd2
3 vms smb01_d3 - /dev/rbd3
#unmap
root@compute1:~# rbd unmap /dev/rbd1
root@compute1:~# rbd unmap /dev/rbd2
root@compute1:~# rbd unmap /dev/rbd3
其实,rbd 是和 /sys/bus/rbd 交互来完成map:
access("/sys/bus/rbd", F_OK) = 0 socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, 15) = 3 setsockopt(3, SOL_SOCKET, SO_ATTACH_FILTER, "\r\0\0\0\0\0\0\0\3000b\261\375\177\0\0", 16) = 0 bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000002}, 12) = 0 getsockname(3, {sa_family=AF_NETLINK, pid=6958, groups=00000002}, [12]) = 0 setsockopt(3, SOL_SOCKET, SO_PASSCRED, [1], 4) = 0 open("/sys/bus/rbd/add_single_major", O_WRONLY) = -1 ENOENT (No such file or directory) open("/sys/bus/rbd/add", O_WRONLY) = 4 write(4, "9.115.251.194:6789,9.115.251.195:6789,9.115.251.218:6789 nam"..., 101) = 101 close(4)
你甚至可以直接对 /sys/bus/rbd 操作来 map,showmapped 和 unmap RBD Image:
root@compute1:~#echo "10.20.30.40 name=admin rbd foo" | sudo tee /sys/bus/rbd/add #map root@compute1:~# ls /sys/bus/rbd/devices #showmapped 1 root@compute1:~# echo 1 | sudo tee /sys/bus/rbd/remove #unmap 1 root@compute1:~# ls /sys/bus/rbd/devices
相信可以参考 RBD KERNEL OBJECT OPERATIONS 和 这篇文章。
Ceph 提供 rbd 作为一个操作 ceph rados 块设备(RBD)image 的 工具,根据调用的底层模块,其功能可分为两部分:
root@compute1:~# which rbd /usr/bin/rbd root@compute1:~# ldd /usr/bin/rbd | grep rbd librbd.so.1 => /usr/lib/x86_64-linux-gnu/librbd.so.1 (0x00007fcf7ae62000) root@compute1:~# ldd /usr/lib/x86_64-linux-gnu/librbd.so.1 | grep rados librados.so.2 => /usr/lib/x86_64-linux-gnu/librados.so.2 (0x00007f29b543f000)
在 Ubuntu 上,你安装了 ceph-common 就可以得到该工具,其命令行格式为:
理解 OpenStack + Ceph (3):Ceph RBD 接口和工具 [Ceph RBD API and Tools]
标签:
原文地址:http://www.cnblogs.com/sammyliu/p/4838139.html