简介
块设备是i/o设备中的一类,是将信息存储在固定大小的块中,每个块都有自己的地址,还可以在设备的任意位置读取一定长度的数据,例如硬盘,U盘,SD卡等。狭义的块设备专指硬盘。
块设备(Block device)是Ceph最重要的用途之一。早期Ceph开发的时候,是作为纯粹的文件系统向外提供的;随着云计算的兴起,基于Ceph的后端存储组件RBD的产生逐渐使ceph作为弹性计算最重要的后端之一,逐步得到了开发者的重视。
在当前,Iaas和弹性计算流行的今天,部分厂商将Ceph选为块存储的存储系统。在LinuxIO协议栈中,块设备位于VFS层之下,提供了基于块的读写能力。
Ceph RADOS语义:
Ceph的底层是RADOS集群,RADOS包含了Monitor集群,OSD集群以及客户端,对外提供一致和统一的服务。
Ceph支持块存储、对象存储和文件存储的场景,不同的存储场景对于存储的性能要求不同:大数据场景更加注重吞吐量和集群规模,块存储注重延迟和稳定性,对象存储更加关注成本和数据可靠性,数据库和实时计算关注低延迟以及一致性。
为了满足不同的存储场景的需要,作为存储底座的RADOS的对外提供的接口需要足够简单,尽量满足不同存储场景的需求。Ceph的RADOS客户端提供了以下几种语义:
- 向一个存储池内创建一个对象,并可以对对象随机读写以及追加读写;对象使用对象id标志,比如“object1”,对象内容是无意义的二进制流;
- 向一个存储池内创建一个omap或者attr,omap类似于字典,并可以向omap中新增或者删除key value。如果存储池是基于纠删码的存储,则不支持omap。
Ceph提供了以对象为基础的接口,上层业务需要在额外封装块存储或者对象存储的接口。RADOS内部实现了高可用、数据高可靠性、统一化存储。
RBD接口
RBD(RADOS Block Device)是Ceph对外的三大组件之一,也是Ceph最稳定的接口。应用访问rados应用有两种途径(如下图):
- librbd 用户态接口,librados.so动态链接库充当客户端接入RADOS集群;可以在用户态访问RBD接口;
- krbd 内核态,通过rbd命令,可以将rbd设备映射为本地的块设备,可以在/mnt下挂载。
用户可以使用rbd命令通过存储池的名字和image名字设置挂载的image。
sudo rbd map {pool-name}/{image-name} --id {user-name}
RDB提供的接口定义在中,RBD提供的接口不同于块设备的bio接口,在RBD使用名字或者id唯一标志一个RBD。rbd.ko作用在块设备驱动层。提供了以下接口:
- 打开、关闭、clone、快照一个块设备;
- 同步io接口,以及异步io接口,参数 偏移+长度;
- 获取image元数据信息的能力。
image存储组织(基于RADOS)
RBD块设备在Ceph中被称为image(本文仅仅讨论image V2)。类似于其他存储,image由元数据和数据组成,元数据和数据都以对象的方式在RADOS维护:
- 对于块设备的各种IO请求,RBD驱动会转化为对于RADOS集群中相应对象的操作。
- image元数据中需要维护信息,支持快照、克隆等操作,也需要记录文件大小、条带等信息;
- image数据被分为一个个大小相等的数据片(默认为4MB,比如1GB的image分为256个),每个数据片都以RADOS对象的形式存储在RADOS集群中。
对于一个块存储设备,RBD在RADOS上维护了四种对象:
rbd_id.<:name>
RBD向上提供了通过name接口访问image的能力,同时也提供了为image重命名的接口。image内部使用id标志,这样即使名字改变id也不会变化。
比如RADOS对象, rbd_id.foo1 值为 “1234567890”,表示名字为foo1的image的id为1234567890。
rbd_header.<:id>
rbd_header.<:id>表示image的元数据信息,比如rbd_header.1234567890表示id为1234567890的image元数据信息。superblock中的大部分信息都维护在rbd_header.<:id>中,
rbd_header.<:id>的类型为omap,可以容纳很多键值对。
rbd_object_map.<:id>
早期的RBD设备没有这个对象,对于数据快照的场景,RBD会逐次拷贝每一个数据片对象,会占用集群大量的性能。对于数据快照的场景,理想的方式应该是采用写时复制技术,类似于Linux fork,只有修改了才会复制。为了支持写时复制,rbd_object_map对象被加入新版的image元数据中。
每一个数据片在rbd_object_map都有2bits的标识,可以表示四种状态:
- b00 表示数据片不存在,即内容全部为0;
- b10 表示数据片存在,可以被随意修改;
- b10 数据片存在等待删除,即内容全部为0;
- b11 数据片从上一次快照没有被修改过。
在RADOS中,这个对象的值为二进制流。对于1TB的磁盘,4MB的分片,RBD共维护了262144个数据片对象,相应的每个数据片对象占有2bits,那么总共占有64KB,所以rbd_object_map对象的大小为64KB。第i个字节,表示第4i ~4i+3 个分片的状态。
rbd_data.<:obj_prefix>.<:obj_no>
这一类对象表示块存储的数据分片,obj_no为16位长度的16进制数表示一个64位整形。obj_prefix存在Header里面。比如某个image的prefix为1017238e1f29,那么rbd_data.1017238e1f29.0000000000000000 表示第一个分片,依次类推。由于image的特性,创建的块设备的时候只在头尾创建了部分数据,大部分数据片为空,即标志位为00。
为了节省存储空间,如果一个数据片全部为0则不会实际在RADOS集群中存储;如果一个数据片的后半部分全部为0,则只会存储到非0部分,比如在4MB的全0数据片中,3084KB-3085KB写入了1KB的数据,则RBD会创建一个对象长度为3085KB,前面3084KB全部为空。
数据条带化:
启动条带化会使用RAID0的方式存储。