2. Ceph核心架构与数据分布

Ceph 之所以能在无中心节点的前提下提供统一的对象、块与文件存储,关键在于它把“数据放在哪里”这件事从查表变成了可计算。理解 Ceph,本质上要理解三层:底层负责可靠存储的 RADOS,中间负责把对象映射到具体设备的 CRUSH 与 PG,上层负责对外提供接口的 RBD、RGW、CephFS。本节围绕这条主线,把 MON、OSD、MDS、MGR 的职责和 Pool、PG、CRUSH 的协作关系讲清楚。

一、RADOS:一切存储能力的底座

RADOS(Reliable Autonomic Distributed Object Store,可靠自治分布式对象存储)是 Ceph 的存储内核。它对外暴露的并不是文件或块,而是“对象”:每个对象由对象名(oid)、命名空间(namespace)和所属 Pool 唯一确定,数据以对象为单位被复制、校验和恢复。RBD 的块设备、RGW 的 S3/Swift 对象、CephFS 的文件数据,最终都会被拆解成 RADOS 对象落到 OSD 上。

RADOS 由两类核心守护进程支撑:OSD 负责实际的数据存取,MON 负责维护集群的权威状态。RADOS 的“自治”体现在:客户端不需要向中心节点询问数据位置,而是自己用 CRUSH 算出位置;OSD 之间通过心跳和 PG 日志互相监督,发现故障后自动触发数据恢复。

二、MON、OSD、MDS、MGR 的分工

MON(Monitor)维护集群的 Cluster Map,包括 Monitor Map、OSD Map、PG Map、CRUSH Map 和 MDS Map。它使用 Paxos 在多个 MON 之间达成一致,通常部署 3 或 5 个,保证多数派可用。MON 不存用户数据,但它是集群的“宪法”:客户端必须先拿到 Map,才能计算数据位置。

OSD(Object Storage Daemon)是真正存放数据的进程,通常一块盘对应一个 OSD。它负责对象的读写、副本复制、数据校验、故障恢复和向 MON 上报状态。OSD 的数量和权重直接决定集群容量与数据分布。

MDS(Metadata Server)只服务于 CephFS,负责文件系统的目录树、inode、权限等元数据。对象存储和块存储不需要 MDS。MDS 可以多活,元数据被切分成子树由不同 MDS 承担。

MGR(Manager)负责监控指标、Dashboard、Prometheus 导出、编排模块等管理面功能。它不参与数据路径,但为运维提供可观测性。

客户端接口层 RBD 块设备 RGW 对象网关 CephFS 文件系统 librados / 原生对象接口 RADOS 可靠自治分布式对象存储 MON × 3/5 Cluster Map / Paxos 权威集群状态 CRUSH 算法 哈希 + 权重计算 无需查表定位 PG 归置组 对象 → PG 映射 复制/纠删码单元 MGR Dashboard / 指标 管理面模块 OSD 集群(每块盘一个 OSD) OSD.0 权重 1.0 SSD 480G PG 副本 OSD.1 权重 1.0 SSD 480G PG 副本 OSD.2 权重 1.0 HDD 4T PG 副本 OSD.3 权重 1.0 HDD 4T PG 副本 OSD.4 权重 1.0 HDD 4T PG 副本 MDS 仅 CephFS 元数据 数据路径:客户端 → CRUSH 计算 → PG → OSD 副本;MON 提供 Map,MGR 提供可观测性,MDS 仅服务 CephFS

三、Pool 与 PG:数据分布的中间层

Pool 是管理员划分的逻辑存储池,它规定了副本数(size)、最小可用副本数(min_size)、PG 数量、CRUSH 规则等策略。客户端写入对象时,先确定它属于哪个 Pool,再在 Pool 内计算它属于哪个 PG。PG(Placement Group,归置组)是对象到 OSD 之间的“中间聚合层”:一个 PG 包含若干对象,一个 PG 整体被映射到一组 OSD 上。

为什么需要 PG?如果每个对象都单独计算 OSD 位置,元数据量和迁移粒度都会爆炸。把对象先聚合成 PG,再以 PG 为单位做复制、迁移和恢复,可以大幅降低管理开销。PG 数量需要提前规划,经验公式是:PG总数 ≈ (OSD总数 × 100) / 副本数,再向上取到 2 的幂。例如 5 个 OSD、副本数 3,则约需 167 个 PG,取 256。PG 太少会导致数据分布不均,太多则增加 MON 和 OSD 的元数据负担。

四、CRUSH:把位置变成计算

CRUSH(Controlled Replication Under Scalable Hashing)是 Ceph 数据分布的核心算法。它接收三个输入:对象所属 PG 的 ID、CRUSH Map、以及一个随机种子(通常是 rjenkins 哈希)。输出是一组 OSD 编号,即该 PG 的主副本和从副本位置。

CRUSH Map 是一棵层次树,典型结构为:root → rack → host → osd。每个节点有类型和权重,OSD 权重通常与磁盘容量成正比。CRUSH 通过“选择桶”算法在树中逐层挑选,并遵循故障域隔离规则:同一个 PG 的多个副本不能落在同一 host 或同一 rack 下。这样即使整机架断电,数据仍然可用。

CRUSH 的最大价值在于“确定性”:只要 Map 不变,任何客户端对同一 PG 计算出的 OSD 集合完全一致,因此不需要中心索引。当 OSD 增减时,只有受影响的 PG 需要迁移,迁移量约为总数据的 1/N,而不是全量重分布。

五、一次写入的完整路径

假设客户端向 Pool rbd 写入对象 rbd_data.abc123,副本数为 3,集群有 5 个 OSD。过程如下:

  1. 客户端从 MON 获取最新的 OSD Map 和 CRUSH Map。
  2. 用对象名哈希得到 PG ID,例如 2.1f。
  3. 用 CRUSH 计算 PG 2.1f 对应的 OSD 集合,例如 [OSD.2, OSD.0, OSD.4],其中 OSD.2 为主副本。
  4. 客户端直接向主 OSD.2 发送写请求。
  5. 主 OSD 写入本地后,并行转发给 OSD.0 和 OSD.4。
  6. 两个从副本确认后,主 OSD 向客户端返回写入成功。

整个过程客户端只与主 OSD 通信,MON 不参与数据路径。如果某个从 OSD 超时未确认,主 OSD 会将其标记为 degraded,并在后台启动恢复,把缺失的副本补齐到其他 OSD 上。

判断集群健康时,ceph -s 中的 HEALTH_OK 表示所有 PG 处于 active+clean;若出现 active+degraded,说明有副本缺失但数据仍可读写;若出现 undersized,说明可用副本数低于 min_size,写入可能被阻塞。

六、关键参数与观察点

对象关键参数作用
Poolsize / min_size副本数与最小可用副本数
Poolpg_num / pgp_numPG 数量与用于放置的 PG 数量
CRUSHweightOSD 权重,影响数据分配比例
CRUSHrule故障域隔离规则,如 rack 级隔离
OSDup / in进程是否运行、是否参与数据分配

理解这组关系后,再看 Ceph 的扩容、故障恢复和性能调优,就能落到具体对象上:扩容改的是 CRUSH Map 和 OSD 权重,恢复看的是 PG 状态,性能瓶颈则要区分是客户端到主 OSD 的网络、主 OSD 的磁盘 IO,还是副本同步的带宽。RADOS 提供可靠存储,CRUSH 和 PG 决定数据落在哪里,MON、MDS、MGR 分别守住状态、元数据和管理面,这就是 Ceph 核心架构的完整图景。