1. 简介
Ceph 能够同时提供对象存储、块存储和文件存储。
(1)对象存储
- 提供 RESTful 接口;
- 提供与 S3 和 Swift 兼容的 API;
- 对象条带化;
- 多站点部署和复制;
(2)块存储
- 精简配置,即能够按需分配;
- 镜像最大可达16EB;
- 可配置条带化;
- 内存缓存;
- 快照;
- 写时复制的克隆;
- 支持 KVM 和 libvirt;
- 内核驱动程序支持;
- 灾难恢复;
(3)文件存储
- 提供与 POSIX 兼容的语义;
- 数据与元数据分离;
- 可配置条带化;
- 内核驱动程序支持;
- 子目录快照;
- 可以和 Hadoop 配合使用(替换 HDFS);
2. 存储集群
一个 Ceph 存储集群至少需要包含一个 Monitor、一个 Manager 和一个 OSD(Object Storage Daemon)。当运行 Ceph 文件系统客户端时,则还需要一个 MDS(Metadata Sderver)。
- Monitor(
ceph-mon
):维护着集群的运行状态图(map),包括 monitor map、manager map、OSD map、MDS map 和 CRUSH map。此外,还负责管理守护进程和客户端之间的身份认证。出于冗余和高可用性考虑,通常至少需要有 3 个 monitor。 - Manager(
ceph-mgr
):负责跟踪运行时指标和集群的当前状态,包括存储利用率、系统负载等。为了实现高可用性,通常至少需要有 2 个 manager。 - OSD(
ceph-osd
):负责存储数据、处理数据复制、恢复、重平衡;并通过检查其他 OSD 守护进程的心跳信号,向 monitor 和 manager 提供一些监控信息。为了实现冗余和高可用性,通常至少需要有 3 个 OSD。 - MDS(
ceph-mds
):代表 Ceph 文件系统存储元数据,其允许用户执行诸如ls
等命令而不会给存储集群带来巨大的负担。
Ceph 将数据作为对象存储在逻辑存储池中,并通过 CRUSH 算法来计算哪个归置组(PG)应该包含该对象,然后进一步计算哪个 OSD 守护进程应该存储该归置组。
3. 寻址流程
- 如果上传的文件过大,则会首先将文件划分为多个大小相同的对象(最后一个对象的大小可以不一致);
- 一个对象会被映射到一个 PG 中,而一个 PG 可以承载多个不同的对象(PG 与对象之间的关系是“一对多”的关系);
- 一个 PG 会被映射到多个 OSD 上(数据冗余),且每个 OSD 可以承载大量的 PG(PG 与 OSD 之间的关系是“多对多”的关系);
(1)文件 -> 对象
ino
为文件的 ID(如,file);ono
为对象的序号(如,0, 1, …);oid
为对象的 ID,其等于 ino
拼接上 ono
(如,file0, file1, …)。
Ceph 将对象存储在扁平的命名空间中(没有目录层级)。对象具有 ID、二进制数据和一组键值对组成的元数据,元数据的语义完全取决于客户端。对象 ID 在整个集群中是唯一的。
(2)对象 -> PG
设集群中 PG 的总数为 m
(应为 2 的整数次幂),则 mask
等于 m-1
;所以对象 ID 为 oid
的对象将被映射到 PGID 为 hash(oid) & mask
的 PG 上。
(3)PG -> OSD
在得到 PGID 之后,Ceph 使用 CRUSH 算法为该 PG 找到一系列的 OSD 以承载该 PG;当集群运行图或存储策略配置发生变化时,PG 到 OSD 的映射关系将会发生变化。
为什么要在对象和 OSD 之间插入一层 PG 抽象?
如果没有 PG 这一层映射,在这种情况下,一定需要采用某种算法,将对象直接映射到一组 OSD 上。
- 如果这种算法是某种固定映射的哈希算法,则意味着一个对象将被固定映射在一组 OSD 上,当其中一个或多个 OSD 损坏时,对象将无法被自动迁移至其他 OSD 上(因为映射函数不允许),当系统为了扩容新增了 OSD 时,对象也无法被再平衡到新的 OSD上(因为映射函数不允许)。
- 如果采用一个动态算法(如仍然采用 CRUSH 算法)来完成这一映射,似乎是可以避免由静态映射而导致的问题的。但是,其结果将是各个 OSD 所处理的本地元数据量暴增,由此带来的计算复杂度和维护工作量也是难以承受的。例如,在 Ceph 的现有机制中,一个 OSD 平时需要和与其共同承载同一个 PG 的其他 OSD 交换信息,以确定各自是否工作正常,是否需要进行维护操作。由于一个 OSD 上大约承载数百个 PG,每个 PG 内通常被映射到 3 个 OSD 上,因此在一段时间内,一个 OSD 大约需要进行数百次至数千次 OSD 信息交换。然而,如果没有 PG 的存在,则一个 OSD 需要和与其共同承载同一个对象的其他 OSD 交换信息。由于每个 OSD 上承载的对象可能高达数百万个,因此同样长度的一段时间内,一个 OSD 大约需要进行的 OSD 间信息交换将暴涨至数百万次乃至数千万次。而这种状态维护成本显然过高。
4. 集群运行图
Ceph 集群的拓扑结构由以下 5 张运行图表示:
- Monitor Map:主要包含了每个 monitor 的 IP 地址和端口等信息;可以通过
ceph mon dump
来查看。 - OSD Map:主要包含了每个存储池、OSD 等的有关信息;可以通过
ceph osd dump
来查看。 - PG Map:主要包含了每个 PG 的详细信息、每个 OSD 的统计信息等;可以通过
ceph pg dump
来查看。 - CRUSH Map:包含了一个存储设备列表、故障域层次结构、存储数据时遍历该层次结构的规则;可以通过如下命令来查看,
ceph osd getcrushmap -o {comp-crushmap-filename} crushtool -d {comp-crushmap-filename} -o {decomp-crushmap-filename}
- MDS Map:主要包含了存储元数据的存储池、元数据服务器等信息;可以通过
ceph fs dump
来查看。
5. 智能的后台进程
在 Ceph 集群中,OSD 后台进程可以和其他的 OSD 后台进程、monitor 直接交互;且 Ceph 客户端也能够直接与 OSD 后台进程直接进行数据传输。这意味着 OSD 后台进程可以利用本机的 CPU 和内存执行那些会拖垮集中式服务器的任务。
具体而言,充分利用 OSD 节点的算力和内存具有如下优点:
-
OSD 直接服务于客户端:任何网络设备对其所能支持的并发连接数都是有限制的,让 Ceph 客户端直接与 OSD 后台进程交互,不仅能够提高总的系统容量,同时消除单点故障。
-
OSD 成员关系和状态:OSD 后台进程加入一个集群,并汇报其自身的状态。OSD 后台进程的状态为
up
或down
,分别对应其是否能够服务于客户端的请求。OSD 后台进程会周期性地向 monitor 发送心跳信息;如果 monitor 在一段时间内没有接收到 OSD 的心跳信息,则将该 OSD 标记为down
状态。此外,OSD 后台进程也会确定相邻 OSD 是否处于down
状态,并将其报告给 monitor。 -
数据清理:数据清理是以 PG 为单位的。
- 浅度清理(每天):OSD 后台进程可以将它们的本地对象的元数据与其他 OSD 上的副本进行比较。
- 深度清理(每周):逐比特位比较对象中的数据及其校验和。
-
数据复制:Ceph 客户端使用 CRUSH 算法来计算对象的存储位置,然后查看 CRUSH 运行图来识别 PG 的 primary OSD。客户端会将对象写入 PG 的 primary OSD,然后 primary OSD 通过查看 CRUSH 运行图来寻找 secondary OSD 和 tertiary OSD,并将对象复制到后两者。
6. OSD Sets
(1)Acting Set:Acting Set 指的是负责某个 PG 的一系列 OSD。 Acting Set 中的第一个 OSD 即为 primary OSD。
(2)Up Set:Acting Set 中的部分 OSD 后台进程并不总是处于 up
状态的。当 Acting Set 中的 OSD 处于 up
状态时,它就是 Up Set 的成员。当一个 OSD 失败时,Ceph 可以将其上的 PGs 映射到其他的 OSD。
7. 客户端
Ceph 客户端包含如下服务接口:
- 块设备:支持内核模块和 QEMU 直接使用 librbd。
- 对象存储:提供了与 S3 和 Swift 兼容的 RESTful API。
- 文件系统:支持将其挂载为内核对象或用户空间中的文件系统(FUSE)。