Ceph in a Word

口头说明 Ceph 的整个过程:假设客户端需要向 Ceph 写入一段数据,从应用层一直讲到磁盘。

1. 上层数据先转换成 RADOS 对象

用户看到的接口可能是:

  • RBD 块设备
  • CephFS 文件系统
  • RGW 提供的 S3 对象接口
  • 直接调用 librados

无论入口是什么,最终都要转换为底层的 RADOS 对象。

例如,一个较大的 RBD image 不会作为单个对象保存,而会被切分成多个固定大小的 RADOS 对象。每个对象至少可以用下面的信息定位:

1
Pool + Namespace + Object ID

为了简化,后面只使用:

1
Pool + Object ID

2. 客户端先联系 MON

客户端启动后,首先需要知道:

  • 集群中有哪些 OSD
  • 哪些 OSD 是 up、哪些是 down
  • Pool 使用什么副本策略
  • 集群的 CRUSH 拓扑和规则
  • 当前的数据映射状态

这些信息来自 MON 维护的 Cluster Map,包括:

  • Monitor Map
  • OSD Map
  • CRUSH Map
  • MDS Map 等

因此客户端先联系一个 MON,完成 CephX 身份认证,并获取最新的 Cluster Map。

这里最重要的一点是:MON 告诉客户端集群当前是什么样子,但不会代理客户端的数据读写。

客户端获得 Map 后,就可以自己计算数据位置,不需要每次都询问 MON。

3. Object 映射到 PG

现在客户端知道:

1
2
Pool = rbd
Object ID = rbd_data.1234

客户端先对 Object ID 做哈希计算,再结合这个 Pool 的 PG 数量,计算对象属于哪个 PG。可以简化理解成:

1
hash(Object ID) → PG 编号

假设计算结果是 PG 17,而这个 Pool 的 ID 是 4,那么最终 PG ID 可能表示为:

1
4.11

这里的 11 通常是十六进制显示,概念上相当于我们假设的 PG 17。因此得到:

1
对象 rbd_data.1234 → PG 4.11
为什么需要 PG,而不直接把对象映射到 OSD?

因为对象可能有数十亿个。如果 Ceph 为每个对象单独维护完整的位置和迁移历史,元数据成本会非常高。
PG 把一批对象组合起来,让 Ceph 以 PG 为单位进行:

  • 数据放置
  • 副本管理
  • Peering
  • Recovery
  • Backfill
  • Scrub

PG 是对象和 OSD 之间的一层间接映射。

4. PG 通过 CRUSH 映射到 OSD

客户端已经知道对象属于 PG 4.11,接下来需要确定这个 PG 应该由哪些 OSD 保存。

客户端结合:

1
2
3
4
PG ID
+ 当前 OSD Map
+ CRUSH Map
+ Pool 的 CRUSH Rule

在本地运行 CRUSH 算法。假设 Pool 配置为:

1
2
3
size = 3
failure domain = host
device class = hdd

这表示:

  • 每个对象正常保存三份
  • 三份副本应尽量位于不同主机
  • 只选择 HDD 类型的 OSD

CRUSH 可能计算出:

1
PG 4.11 → [osd.2, osd.7, osd.12]

这组 OSD 称为这个 PG 的集合。第一个 OSD 通常是 Primary:

1
2
3
Primary   = osd.2
Secondary = osd.7
Secondary = osd.12

CRUSH 不是从中央数据库查询“对象在哪块盘”,而是根据确定性的算法计算期望位置。客户端和 OSD 使用相同的 Map 和算法,会得到相同结果。

5. Up Set 与 Acting Set

Up Set

CRUSH 根据当前 OSD Map 计算出来的、理论上应该负责这个 PG 的 OSD:

1
Up Set = [osd.2, osd.7, osd.12]

Acting Set

当前实际负责处理这个 PG 请求的 OSD:

1
Acting Set = [osd.2, osd.7, osd.12]

集群正常时,两者通常相同。如果 OSD 故障、PG 正在迁移或者发生临时映射,两者可能不同。例如:

1
2
Up Set     = [osd.2, osd.7, osd.15]
Acting Set = [osd.2, osd.7, osd.12]

这可能表示 CRUSH 认为以后应该由 osd.15 负责,但迁移还没完成,当前实际数据仍由 osd.12 提供。客户端真正发送请求时,要依据当前生效的映射联系 Acting Set 的 Primary。

6. 客户端联系 Primary OSD

假设 Acting Set 是:

1
[osd.2, osd.7, osd.12]

那么 osd.2 是 Primary OSD。

客户端不会分别向三个 OSD 写三次,而是把写请求发送给 Primary:

1
客户端 → osd.2

Primary 负责协调这个 PG 的操作顺序和副本写入。这样可以避免多个副本分别接收客户端请求,产生并发顺序不一致的问题。

7. Primary 将数据复制给其他 OSD

osd.2 收到写请求后:

  1. 检查客户端的 CephX 权限。
  2. 确认请求属于自己负责的 PG。
  3. 在本地执行写入。
  4. 向 osd.7 和 osd.12 发送副本写请求。
  5. 等待所需副本完成。
  6. 向客户端返回成功。

数据流可以表示为:

1
2
3
                ┌→ osd.7
客户端 → osd.2 ──┤
└→ osd.12

客户端只直接联系 Primary,但 Primary 会协调其他副本。

如果这是纠删码池,Primary 的工作不是简单复制完整对象,而是将数据编码成 K 个数据分片和 M 个校验分片,再分发到 Acting Set 中的多个 OSD。

8. OSD 通过 BlueStore 写入磁盘

每个 OSD 收到数据后,交给自己的 BlueStore 后端。BlueStore 主要涉及:

1
2
3
4
block
├── 对象主体数据
├── BlueFS
└── RocksDB 元数据

如果单独配置了高速设备,还可能有:

1
2
3
block     → 主要对象数据,通常在 HDD
block.db → RocksDB/BlueFS,通常放在 SSD 或 NVMe
block.wal → 数据库 WAL,可单独部署,但很多场景不需要

BlueStore 不需要在 OSD 数据盘上再创建 XFS 或 ext4,而是直接管理块设备。它还负责:

  • 磁盘空间分配
  • 对象元数据
  • 校验和
  • 压缩
  • RocksDB/BlueFS 管理

当需要的副本完成持久化后,Primary 才按照相应写入规则向客户端确认。

9. 读取过程

读取过程的前半段与写入基本一致:

1
2
3
4
客户端获取 Cluster Map
→ Object ID 计算 PG
→ PG 通过 CRUSH 映射到 Acting Set
→ 联系 Primary OSD

正常情况下,客户端向 Primary 读取:

1
客户端 ← osd.2

Primary 从本地 BlueStore 读取对象并返回。如果 Primary 已经故障,MON 和 OSD 会更新集群状态,并为 PG 形成新的 Acting Set。例如:

1
2
原 Acting Set = [osd.2, osd.7, osd.12]
新 Acting Set = [osd.7, osd.12]

此时 osd.7 可以成为新的 Primary。客户端收到更新的 OSD Map 后,重新计算并向 osd.7 请求。客户端发现 Map 过期时,OSD也可以提示它刷新 Map 并重试。

10. OSD 故障后的恢复

假设 osd.12 故障:

1
2
[osd.2, osd.7, osd.12]
×

大致会发生:

  1. 其他 OSD 通过 heartbeat 发现 osd.12 无响应。
  2. OSD 向 MON 报告。
  3. MON 根据报告更新 OSD Map,将其标记为 down。
  4. 相关 PG 可能变成 active+undersized+degraded。
  5. 等待相应策略或管理员操作后,故障 OSD可能被标记为 out。
  6. CRUSH 为 PG 选择新的 OSD,例如 osd.15。
  7. 剩余副本与新 OSD进行 peering 和 recovery/backfill。
  8. 恢复完成后,PG 回到 active+clean。

新的副本集合可能变为:

1
[osd.2, osd.7, osd.15]

需要注意:

  • Peering:相关 OSD 确认 PG 状态、日志和权威历史。
  • Recovery:恢复缺失或过期的对象。
  • Backfill:向新 OSD 批量迁移该 PG 所需的数据。
  • active:PG 可以处理客户端 I/O。
  • clean:PG 的目标副本全部完整并处于正确位置。

Peering 完成不等于数据已经恢复完成,因此可能出现:

1
active+degraded

表示 PG 已经能够提供服务,但副本还不完整。

各组件在数据路径中的位置

组件 作用 是否持续经过用户数据
MON 认证、维护 Cluster Map、形成 quorum 否
MGR 监控、指标、Dashboard、管理模块 否
OSD 存储对象、复制、恢复、Scrub 是
BlueStore OSD 的本地存储后端 是
MDS 管理 CephFS 元数据 文件元数据经过,文件内容通常不经过
RGW 将 S3/Swift 请求转换为 RADOS 操作 RGW 请求经过
RBD 将块 I/O 转换为 RADOS 对象操作 是
CRUSH 计算 PG/OSD 数据位置 它是算法,不是守护进程

一句话总结整个过程:

上层接口把数据转换为 RADOS 对象;客户端从 MON 获取 Cluster Map,利用对象 ID 计算 PG,再通过 CRUSH 计算 Acting Set,联系其中的 Primary OSD;Primary 协调副本或纠删码分片写入,最后由各 OSD 的 BlueStore 将数据持久化到磁盘。

本文作者:jujimeizuo
本文地址: https://blog.jujimeizuo.cn/2026/08/06/ceph-in-a-word/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!