土法炼钢 · 系统与基础设施

【Ceph RADOS】RADOS 内核全景:五轴坐标系与 18 篇路线

文章导航

分类入口
storagedistributed
标签入口
#ceph#rados#osdmap#pg#bluestore#crush#squid#v19.2.5

目录

站内 Ceph 与 CRUSH 已讲清去中心化放置与 RADOS 工程概览;存储工程SPDK 分别闭合纠删码/对象选型与本机用户态 NVMe。中间仍缺一层:一次写经 Messenger → PG → BlueStore 的停顿点、peering/recovery 各自保证什么、以及相对 MinIO / 云块 / SPDK 何时不该上 Ceph。

本文只做三件事:钉缺口、定义后续 17 篇共用的五条坐标系(含不变量),并给出阅读路线。难点不在单组件名词,而在交互边界上的可核对字段——OSDMap.epochpg_info_t.last_epoch_startedreadable_untilShardedOpWQ shard、BlueStore deferred/WAL。

本文是「Ceph RADOS 存储内核」系列第 1 篇(共 18 篇)。→ 系列目录

篇目 核心内容
第 1 篇 · RADOS 全景 缺口、五轴坐标系、18 篇路线
第 2 篇 · MON/MGR 与 Map quorum、OSDMap/PGMap、epoch 传播
第 3 篇 · OSD 与 Messenger daemon、msgr2、Op 进入 OSD
第 4 篇 · CRUSH 加深 rule/bucket/weight 机制钉
第 5 篇 · PG 与 Peering PrimaryLogPG、PG log、状态机
第 6 篇 · 客户端写路径 librados → 副本应答、stale read 边界
第 7–11 篇 · BlueStore 与恢复 写/读路径、recovery/backfill/scrub、EC
第 12–14 篇 · 接入层 RBD / CephFS / RGW
第 15–18 篇 · 观测收束 排障、选型、Crimson 开放问题

版本锚定:Ceph Squid v19.2.5docs.ceph.com/en/squid/;源码 tag v19.2.5)。Tentacle(20.x)特性须显式标注「Tentacle+」。无真实多节点 / vstart 集群则不粘贴伪造 ceph -s 或 fio 输出。


一、相对站内已有内容,缺口在哪

下表列出各已有系列的视角,以及本系列补的格子。规则是:不重写已有内容,只填真正空着的格子。

已有内容 视角 本系列补什么
distributed/38 CRUSH 算法直觉、RADOS 工程概览、BlueStore 简介、三接口速览 源码路径级机制、失败模式、状态机;不替代概览
storage/48–49–70 MinIO、纠删码理论、云块选型 不重写纠删码全书;EC 路径(第 11 篇)外链 storage/49
spdk/ 用户态 NVMe 轮询栈 OSD 数据面与 SPDK/Crimson 边界在第 17–18 篇收束
db/rocksdb/ 嵌入式 LSM BlueStore 内 RocksDB/BlueFS 边界;不重写 RocksDB 全书

结论:读者知道 CRUSH 算位置、会读 ceph -s,但不知道一次写卡在 Messenger 还是 BlueStore deferred、info.last_epoch_startedhistory.last_epoch_started 差在哪、RBD 对象如何命名、恢复限速如何拖死前台。本系列补这一格。

与通识教材的差别也在这里:GFS/HDFS 把元数据中心化;Dynamo 家族用 gossip 换最终一致;RADOS 用中心化有序 map + 本地放置计算 + PG 日志式复制同时成立。后面五轴就是把这套组合拆成可排障的坐标系。

本系列刻意不写安装手册与 Dashboard 点击路径。若读者的目标只是「把集群装起来」,distributed/38 与官方安装文档已够;若目标是「一次写卡在哪一层、为何 peering 选错权威历史、为何 Active 后读仍阻塞」,则必须沿五轴下钻到字段与状态机。深度来自可证伪的机制,而不是更长的背景介绍。


二、五条坐标系(后续章节回指)

后面每一篇都落到下面某一条轴上。本篇钉名字、关键字段与失败表象;具体状态机与源码在对应篇展开。排障口诀:先点名轴,再下钻模块——不要一上来改 osd_op_num_threads 或 BlueStore 参数。

Map 传播轴

定义:OSDMap epoch 如何从 MON quorum 扩散到 OSD 与 librados,以及客户端在 map 滞后时如何被强制追赶。

可核对锚点 含义
OSDMap.epoch MON 权威版本;变更触发见 src/mon/OSDMonitor.cc @ v19.2.5
OSDMap::Incremental 增量 diff,避免全量广播
Objecter 本地缓存 客户端路由输入;Architecture 文档
PastIntervals peering 回溯历史 acting;与 epoch 速率耦合(第 2、5 篇)

MON quorum 丢失时,一切依赖 epoch 递增的路径(OSD down/up、Pool 变更、CRUSH 编辑)阻塞——表现为「全集群不可写」,却不是磁盘坏了。客户端反复重试且日志里刷 map,优先落本轴。

后续篇第 2 篇第 6 篇

通信轴

定义:msgr2 Frame / 握手,以及 Op 从 TCP 进入 ShardedOpWQ 的路径。

可核对锚点 含义
ProtocolV2 HELLO / AUTH / SESSION;docs.ceph.com/en/squid/dev/msgr2/
client_messenger / cluster_messenger 客户端路径与心跳/副本路径隔离
osd_op_num_shards 同一 PG 的 Op 落同一 shard,保证 PG 内顺序
mClock(Gulati et al., OSDI 2010 前台 vs recovery/scrub 的 QoS 份额

「连接已建立但延迟高」与「连不上」是两类问题:前者看 shard 队列与 mClock,后者看网络/进程。心跳走 cluster messenger,避免业务积压被误判为 OSD down。

后续篇第 3 篇

一致性轴

定义:PG log、LES 字段、peering interval,以及 Preventing Stale Reads 中的 readable_until 如何共同界定可读性。

可核对锚点 含义
eversion_t / pg_log_entry_t Primary 序列化写的全序;log_based_pg/
info.last_epoch_started 本 OSD 某次激活 interval 的边界
history.last_epoch_started 全集群「已接受写」的下界;见 last_epoch_started/
readable_until 读租约;stale_read/(LAGGY / WAIT)

默认路径不会在 Primary 切换后主动返回旧副本数据。真正危险的是「被隔开的旧 Primary + 同样落后的客户端」——靠读租约与 WAIT 堵住。把「读到旧数据」当成 RADOS 默认语义,会把排障带向错误的 eventual-consistency 叙事。

后续篇第 5 篇第 6 篇

本地存储轴

定义:BlueStore 的 BlockDevice / BlueFS / RocksDB / Allocator,以及 min_alloc_size、deferred 与 WAL 切换。

可核对锚点 含义
ObjectStore::Transaction PG 写与 log 追加的落盘单元
deferred / WAL 小写路径;细节在第 7–8 篇
checksum 读路径校验失败模式;第 9 篇

通信与 PG 都「健康」时仍出现周期性尾延迟,优先怀疑本轴(RocksDB compaction、deferred 刷盘),而不是再调 msgr 线程数。

后续篇第 7–9 篇

接入代价轴

定义:RBD / CephFS / RGW 把上层语义切成 RADOS 对象时多付的元数据与访问模式税。

路径 切分直觉(细节后文)
RBD 固定对象大小(默认 4 MiB)覆盖写
CephFS MDS 目录树 + 小文件元数据路径
RGW 索引池 / 数据池 + manifest

同一套 RADOS 上,「块设备 IOPS 不够」与「S3 LIST 慢」往往不是同一个税种——前者看对象切分与队列,后者看索引池热点。

后续篇第 12–14 篇


三、坐标系背后的三个不变量

相对 GFS/HDFS 的中心元数据、Dynamo(DeCandia et al., SOSP 2007)的 gossip 最终一致,RADOS 同时钉住三条不变量(Weil et al., PDSW 2007;对照 Architecture):

  1. 放置计算本地完成object → hash → pg → CRUSH(OSDMap) → Primary,数据路径不查 NameNode;代价是必须持有足够新的 OSDMap.epoch
  2. 一致性单元是 PG:协商规模 \(O(\mathrm{pg\_num})\) 而非对象数;一次 OSD down 只牵动该 OSD 上的 PG 集合,恢复时间上界与 pg 分布相关。
  3. Primary 单点序列化写eversion_t 由 Primary 分配,副本只接受;并发写无需跨节点事务,代价是 interval 变更后必须 peering,并用 up_thru / LES 挡住幽灵提交。

排障时先问「哪条不变量被触碰」,再落到对应轴。例如:写超时且 epoch 狂跳 → 不变量 1;大量 PG peering/incomplete → 不变量 2/3;Active 后读卡住 → 先查租约(一致性轴),不要先怪 CRUSH。

这三条不变量也解释了系列边界:本系列不重写纠删码编码理论(那是不变量之外的编码层),也不写 SPDK 轮询完成模型(那是本地盘另一条用户态路径)。我们只在 RADOS 内核里追问:给定这三条约束,Squid 如何实现、何处失败、与论文假设差在哪。


四、设计谱系:奠基 → Squid → 仍开放的分叉

Weil et al. OSDI 2006(CephFS + RADOS 后端)
  → Weil et al. SC 2006(CRUSH)
  → Weil et al. PDSW 2007(RADOS 服务层)
  → 生产分叉:FileStore→BlueStore;msgr1→msgr2;Classic→Crimson(TP)
  → 仍争:副本 vs EC;中心化 map vs 超大规模吞吐;Classic vs Crimson
  1. Weil et al.(OSDI 2006) Ceph: A Scalable, High-Performance Distributed File System——去中心化 MDS(动态子树)+ RADOS 对象后端,论证无 NameNode 瓶颈的 POSIX 可行性。
  2. Weil et al.(SC 2006) CRUSH——确定性放置,客户端本地算位置;失败域进入 rule 语言。
  3. Weil et al.(PDSW 2007) RADOS——OSD 自治、PG、peering 目标;与同期 Dynamo gossip 形成对照:用全局有序 epoch 换可推理的复制协议。

Sage Weil 博士论文(UCSC, 2007)把上述三篇收束为完整系统叙事;本系列以 Squid v19.2.5 为工程锚,引用写清 docs.ceph.com/en/squid/ 路径或源码路径 @ v19.2.5

维度 论文/早期生产 Squid 默认 开放分叉
本地后端 论文 EBOFS → FileStore BlueStore RocksDB 压实 vs 前台尾延迟
消息 msgr1 msgr2(dev/msgr2/ 多路复用落地、io_uring
OSD 运行时 Classic 线程池 Classic Crimson(Seastar)Technology Preview
读围栏 早期主要靠 map 正确性 readable_until 读租约 租约时长 vs 跨 AZ 误判

五、开放争论(先立靶,后各章拆)

争论 A 侧 B 侧 本系列落点
副本 vs 纠删码 稳定 IOPS、恢复简单 EC 容量效率;RMW 税 第 11、17–18 篇
Classic vs Crimson 生产成熟 核隔离、NVMe 亲和 第 18 篇
自建 vs 云托管块/对象 可控 CRUSH/PG 运维与归因成本 第 17 篇
中心化 map vs gossip 全局有序 epoch,peering 可推理 超大集群 MON/map 吞吐 第 2 篇

不在第 1 篇宣布胜负;每组争论要求后续篇给出可核对机制或选型边界,而不是「看业务场景」空话。

对「自建 vs 云托管」额外钉一句:本系列不比较报价,只比较失败模式是否可归因到五轴中的某一层。若托管块设备把恢复与租约藏在黑盒里,工程师就失去了 last_epoch_started / readable_until 这类字段级抓手——这是架构选择,不是性能排名。


六、18 篇路线与阅读建议

flowchart TD
  01["01 Overview"] --> 02["02 MON/MGR Maps"]
  02 --> 03["03 OSD Messenger"]
  03 --> 04["04 CRUSH Deep"]
  04 --> 05["05 PG Peering"]
  05 --> 06["06 Client Op Path"]
  06 --> 07["07 BlueStore Arch"]
  07 --> 08["08 BlueStore Write"]
  08 --> 09["09 BlueStore Read"]
  05 --> 10["10 Recovery Backfill"]
  10 --> 11["11 EC Path"]
  06 --> 12["12 RBD"]
  06 --> 13["13 CephFS MDS"]
  06 --> 14["14 RGW"]
  09 --> 15["15 Observability"]
  10 --> 15
  15 --> 16["16 Troubleshoot"]
  16 --> 17["17 vs Alternatives"]
  17 --> 18["18 Selection"]
  01 --> 18
路径 篇目 适合
必读核心 1 → 2 → 5 → 6 → 8 → 10 → 16 快速建立坐标系
本地落盘 7 → 8 → 9 BlueStore
接入层 12 → 13 → 14 接入税
对照选型 1 → 17 → 18 路径选型

先修建议:可选读完 distributed/38;本系列默认读者已接受「CRUSH 去中心化放置」的直觉,不再复述 straw2 科普。

阅读时建议随身带一张「轴 → 字段」卡片:写超时先问 epoch;队列不消先问 shard;incomplete 先问 LES 与 past intervals;Active 后读挂起先问 readable_until;尖刺抖动先问 BlueStore。把现象翻译成字段,比翻译成「调参玄学」更接近本系列目标。


七、一次写在五轴上的停顿点(预览)

停顿表象 先落哪条轴 后续篇
客户端反复刷新 map / 写进不去 Map 传播:epoch、quorum 2
请求已达 OSD 但队列不消 通信:msgr2、ShardedOpWQ 3
卡在 peering / incomplete 一致性:interval、LES 5
Active 后读被堵住(LAGGY/WAIT) 一致性:readable_until 6
单 OSD 延迟尖刺、写放大 本地存储:deferred / RocksDB 7–9
上层 IOPS 低于 RADOS 预期 接入代价:切分与 MDS/索引 12–14

无真实集群时只保留机制与失败模式,不写延迟数字,也不粘贴伪造的 ceph -s

同一停顿表象可能对应多轴:例如「写不进去」既可能是 quorum 丢了(Map),也可能是大量 PG 卡在 peering(一致性),还可能是 shard 被恢复打满(通信 + mClock)。本表给的是优先假设,不是唯一诊断。后续篇会把每条优先假设落成字段、状态字与可检验问题。


八、小结

  1. 定位:补 distributed/38 之上的内核路径与失败模式,不重写 CRUSH 科普或 SPDK 栈。
  2. 五轴:Map / 通信 / 一致性 / 本地存储 / 接入代价;每轴有字段级锚点,排障先点名轴。
  3. 三不变量:本地放置、PG 协商粒度、Primary 序列化——任一项被破坏对应不同故障类。
  4. 谱系:OSDI/SC/PDSW 2006–2007 → Squid BlueStore+msgr2+读租约 → Crimson 仍为开放分叉。
  5. 路线:核心「1→2→5→6→8→10→16」;选型「1→17→18」。

下一篇起进入 Map 轴:没有 epoch 语义,后面的 peering 与写路径都无处锚定。


九、参考资料

规范 / 官方文档(A)

源码(A)

论文(A)

站内对照

实验台账


系列目录 · 下一篇:MON/MGR 与 Map

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。

2026-08-14 · storage / distributed

Ceph / RADOS 存储内核:从 Map 到 BlueStore

补齐站内 Ceph 单篇概览之上的 RADOS 内核层:MON/MGR map、OSD Messenger、PG peering、BlueStore、recovery 与 RBD/CephFS/RGW 接入,并以排障与选型收束。


By .