站内 Ceph 与 CRUSH 已讲清去中心化放置与 RADOS 工程概览;存储工程 与 SPDK 分别闭合纠删码/对象选型与本机用户态 NVMe。中间仍缺一层:一次写经 Messenger → PG → BlueStore 的停顿点、peering/recovery 各自保证什么、以及相对 MinIO / 云块 / SPDK 何时不该上 Ceph。
本文只做三件事:钉缺口、定义后续 17
篇共用的五条坐标系(含不变量),并给出阅读路线。难点不在单组件名词,而在交互边界上的可核对字段——OSDMap.epoch、pg_info_t.last_epoch_started、readable_until、ShardedOpWQ
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.5(
docs.ceph.com/en/squid/;源码 tagv19.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_started 与
history.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,优先落本轴。
通信轴
定义: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 叙事。
本地存储轴
定义: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):
- 放置计算本地完成:
object → hash → pg → CRUSH(OSDMap) → Primary,数据路径不查 NameNode;代价是必须持有足够新的OSDMap.epoch。 - 一致性单元是 PG:协商规模 \(O(\mathrm{pg\_num})\) 而非对象数;一次 OSD down 只牵动该 OSD 上的 PG 集合,恢复时间上界与 pg 分布相关。
- 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
- Weil et al.(OSDI 2006) Ceph: A Scalable, High-Performance Distributed File System——去中心化 MDS(动态子树)+ RADOS 对象后端,论证无 NameNode 瓶颈的 POSIX 可行性。
- Weil et al.(SC 2006) CRUSH——确定性放置,客户端本地算位置;失败域进入 rule 语言。
- 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)。本表给的是优先假设,不是唯一诊断。后续篇会把每条优先假设落成字段、状态字与可检验问题。
八、小结
- 定位:补 distributed/38 之上的内核路径与失败模式,不重写 CRUSH 科普或 SPDK 栈。
- 五轴:Map / 通信 / 一致性 / 本地存储 / 接入代价;每轴有字段级锚点,排障先点名轴。
- 三不变量:本地放置、PG 协商粒度、Primary 序列化——任一项被破坏对应不同故障类。
- 谱系:OSDI/SC/PDSW 2006–2007 → Squid BlueStore+msgr2+读租约 → Crimson 仍为开放分叉。
- 路线:核心「1→2→5→6→8→10→16」;选型「1→17→18」。
下一篇起进入 Map 轴:没有 epoch 语义,后面的 peering 与写路径都无处锚定。
九、参考资料
规范 / 官方文档(A)
- Ceph Squid Architecture —
docs.ceph.com/en/squid/architecture/。 - Ceph Squid OSD Internals —
docs.ceph.com/en/squid/dev/osd_internals/。 - Ceph Squid Preventing Stale Reads —
docs.ceph.com/en/squid/dev/osd_internals/stale_read/。 - Ceph Squid CRUSH Map —
docs.ceph.com/en/squid/rados/operations/crush-map/。
源码(A)
ceph/cephtag v19.2.5:src/osd/、src/mon/、src/msg/、src/osdc/、src/os/bluestore/(后续篇钉具体符号)。
论文(A)
- Sage A. Weil, Scott A. Brandt, Ethan L. Miller, Darrell D. E. Long, Carlos Maltzahn. “Ceph: A Scalable, High-Performance Distributed File System.” OSDI 2006.
- Sage A. Weil, Scott A. Brandt, Ethan L. Miller, Carlos Maltzahn. “CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data.” SC 2006.
- Sage A. Weil, Andrew W. Leung, Scott A. Brandt, Carlos Maltzahn. “RADOS: A Scalable, Reliable Storage Service for Petabyte-scale Storage Clusters.” PDSW 2007.
- Giuseppe DeCandia et al. “Dynamo: Amazon’s Highly Available Key-value Store.” SOSP 2007(对照:gossip 去中心化)。
站内对照
实验台账
- 本篇无命令输出;不写 IOPS / 延迟数字。
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
Ceph / RADOS 存储内核:从 Map 到 BlueStore
补齐站内 Ceph 单篇概览之上的 RADOS 内核层:MON/MGR map、OSD Messenger、PG peering、BlueStore、recovery 与 RBD/CephFS/RGW 接入,并以排障与选型收束。
【Ceph RADOS】MON/MGR 与 Map:quorum、epoch 传播与客户端可见性
拆解 Ceph MON Paxos quorum、OSDMap/PGMap 结构与 epoch 传播机制;说明 MGR 主备模型与模块框架;分析客户端 epoch 缓存与可见性窗口的边界条件。
【Ceph RADOS】CRUSH 加深:rule/bucket/weight 机制与失败域语义
相对 distributed/38 的 CRUSH 算法概览,深入 bucket 类型的算法复杂度差异、rule step 语义、weight 体系与 primary_affinity,分析 chooseleaf 与失败域的精确定义及 CRUSH 与一致性哈希的本质区别。
【Ceph RADOS】PG 与 Peering:PrimaryLogPG、PG log 与状态机
拆解 PG 命名与生命周期、PrimaryLogPG 的日志式复制设计、pg_log_entry_t 格式、last_epoch_started 与 last_epoch_clean 的语义差异,以及 peering 状态机从 Reset 到 Active 的完整路径。