机器学习平台技术栈之 Ceph:筑牢 AI 时代的统一数据底座

在构建企业级机器学习平台(Machine Learning Platform)的宏大工程中,我们谈论了计算调度(Volcano)、网络网关(Envoy)、以及 GPU 管理(Device Plugin 等)。然而,在 AI 的世界里,如果没有“数据”,再强悍的算力也只是无源之水。

无论是拥有数十亿张图片的自动驾驶视觉训练集,还是需要频繁保存重启的大语言模型(LLM)几百 GB 的 Checkpoint,亦或是算法端到端流水线(Pipeline)中不同步骤之间需要共享的临时特征文件,存储系统面临着吞吐量、并发度、持久性和云原生兼容性极其苛刻的挑战

传统的 NAS 或单机文件系统早已无法支撑。在这个背景下,开源分布式存储的无冕之王——Ceph,凭借其“一套系统,三种接口(块、文件、对象)”的高度统一架构,以及无需中心元数据节点的去中心化高可用设计,成为了当今算力中心和 Kubernetes 机器学习平台最为主流的基础数据底座。

本文将极其硬核地深入解构 Ceph。从核心底层组件,到神级路由算法 CRUSH,再到它在 Kubernetes 中如何通过 Rook 与 AI 训练任务完美结合。通过这篇“万字级”深度的深度干货,带你穿透数据的汪洋大海。

1. 痛点:AI 训练到底撞上了什么样的“存储墙”?

在理解 Ceph 为什么称霸集群之前,我们必须看看 AI 训练任务对存储系统提出了哪些“变态”的要求:

  1. **海量小文件并发读取 (I/O 梦魇)**:计算机视觉(CV)训练往往需要每个 Epoch 随机打乱并读取数千万张几十 KB 的小图片(通过 PyTorch DataLoader)。传统的集中式存储在面对这种高并发元数据(Metadata)检索时,响应极易拥塞崩溃。
  2. **大文件极速写入 (Checkpoint 风暴)**:千亿参数的大模型训练往往采用 3D 并行,需要每隔几小时将当前的权重状态同时转储。几百个 GPU 并发写入几百 GB 数据,网络吞吐压力瞬间爆表。
  3. **多节点数据强一致共享 (RWX 支持)**:分布式训练中,通常需要多台物理机(多个 Pod)同时挂载同一份数据目录进行并行读取。这需要存储系统支持 ReadWriteMany(RWX)语义。
  4. 结构化与非结构化杂糅:既需要极其快速的文件系统(如挂载训练集),又需要廉价且海量的对象存储(用来做数据集归档和 MLflow 模型无版本管理)。

为了解决同时想要“文件、块、对象”的痛点,Ceph 走上了全能王的王座。

2. 核心架构设计与三种存储形态

Ceph 的架构设计是一首优雅的冰与火之歌。它的基本哲学是:底层构建一个无限可扩展的、强一致的、去中心化的对象存储底座(RADOS),然后再并在其上套不同的马甲(接口)向外界提供服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
graph TD
subgraph K8s AI Platform / Applications
Pod1[PyTorch Training Pod \n (Data Directory)]
Pod2[MySQL / Redis DB \n (Stateful Service)]
Pod3[MLflow Model Registry \n (S3 Client)]
end

subgraph Ceph Interface Layer
CephFS[CephFS \n (Posix File System)]
RBD[RBD \n (Rados Block Device)]
RGW[RADOS Gateway \n (S3/Swift Object Storage)]
end

subgraph Client Library
Librados[Librados \n (Core Client API)]
end

subgraph Ceph Core Storage Engine
RADOS[RADOS - Reliable Autonomic Distributed Object Store]
end

%% Routing
Pod1 ==>|Mounts (RWX)| CephFS
Pod2 ==>|Mounts (RWO)| RBD
Pod3 ==>|REST API (HTTP)| RGW

CephFS --> Librados
RBD --> Librados
RGW --> Librados

Librados --> RADOS

Ceph 向上方提供的三大引擎:

  1. **RBD (块存储)**:向 K8s 暴露为一个纯底层的裸盘。速度极快,用于挂载给数据库(如 AI 平台底层的 MySQL 或 Redis),一般仅支持单节点读写(ReadWriteOnce, RWO)。
  2. **CephFS (文件存储)**:符合 POSIX 语义标准。可以像普通硬盘一样在多台机器配置中被 mount,并支持群组并发读写(ReadWriteMany, RWX)。在 AI 领域,这是挂载训练源码、日志、数据集最高频的存储方式。
  3. **RGW (对象存储 Gateway)**:兼容 AWS S3 协议。应用通过 HTTP 通信,使用 Bucket 与 Object。非常适合大模型平台用来构建统一的模型制品仓库(Model Registry),抛弃本地文件依赖。

3. Ceph 核心底层概念大解析

我们要真正掌握 Ceph,必须要将其下方的 RADOS 底座抽丝剥茧。这里有四个最重要的实体概念:OSD、MON、PG 以及 Pool

3.1 实体组件概念

  • OSD (Object Storage Daemon):真正的“搬砖工”。集群里的每一块物理硬盘(HDD 或 NVMe SSD)都会对应运行一个起管理作用的 OSD 进程(Daemon)。OSD 负责实际保存数据块,并与其它 OSD 进行心跳检测和数据副本的复制/恢复。
  • MON (Monitor):监控者 / 维系视角的首脑。MON 维护着集群状态的映射图(Cluster Map 的权威副本,包含 OSD Map 等)。值得注意的是,用户的读写数据绝对不经过 MON 节点(只取图),从而消除了中心化性能瓶颈。
  • MDS (Metadata Server)仅在 CephFS 中存在。在提供基于目录和层次结构的文件系统时,需要解析树状结构和权限。MDS 取代了 OSD 来响应各种如 ls, cd, mkdir 的元数据系统调用(并将解析完的物理地址给客户端去直接对接 OSD 下载主干数据)。
  • **MGR (Manager)**:辅助监控系统的集群健康指标并管理暴露外部接口。

3.2 抽象数据概念

  • **Pool (存储池)**:一种逻辑隔离分区。我们可以通过给机械硬盘分配一个 Pool 名叫 hdd-pool 用于冷备,给全闪 NVMe 分配一个 Pool 名叫 nvme-pool 用于 AI 高速训练。针对每个 Pool,我们可以配置不同的副本数(Replica Size = 3)或是纠删码(Erasure Coding)。
  • PG (Placement Group, 归置组):对大量 Object 的逻辑分组。这可以说是影响调度性能最重要的概念。由于系统内的 Object(如几十 KB 的小图)多达几十亿个。如果每次 OSD 变动都要去追踪哪些 Object 发生变动将是巨大的算力灾难。Ceph 将成千上万的对象哈希后放入若干个编号固定的 PG 中,后续数据恢复和监控都以 PG 为最小调度单元(比如迁移数据就是迁移一整个 PG)。

4. 极致的技术结晶:概念的化学反应与数据寻址

在一个拥有 1000 块硬盘的 PB 级别存储集群里,当 PyTorch 读取一个叫 /train/dog.png 的文件时,Ceph 怎么知道要去哪一块硬盘(甚至是机架和机房)上把这两百 KB 的数据精确捞出来?

传统的 HDFS 或是元数据服务,会记录一张无限庞大的表:[dog.png] -> [Disk A]。这会导致该查询节点极易宕机卡死。
而 Ceph 放弃了中心字典,采用了极其高超的 CRUSH 算法 进行纯数学函数的客户端本地散列(Hashing)。

4.1 数据切分与路由流程图 (Data Routing Pipeline)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
flowchart TD
File[用户文件: /train/dog.png \n (Size: 10MB)]
--> |切割分片 (4MB/chunk)| Obj1(Object 1 \n 4MB)
File --> Obj2(Object 2 \n 4MB)
File --> Obj3(Object 3 \n 2MB)

subgraph Hashing Function
Obj1 --> |Hash(Object_ID) % PG_NUM| PG_42[PG 42]
Obj2 --> |Hash(Object_ID) % PG_NUM| PG_89[PG 89]
end

subgraph CRUSH Algorithm (Magic!)
PG_42 --> |CRUSH(PG 42, ClusterMap)| OSD_List[OSD_3, OSD_9, OSD_45]
end

subgraph Physical Disk Layer
OSD_List --> OSD_3[(Primary OSD \n server-1 nvme0)]
OSD_List --> OSD_9[(Replica OSD \n server-2 nvme1)]
OSD_List --> OSD_45[(Replica OSD \n server-4 nvme0)]
end

style CRUSH Algorithm fill:#f9f,stroke:#333,stroke-width:2px;

4.2 计算步骤极其精妙的解构:

  1. **File to Object (文件切被割)**:系统将该文件切分成多个通常是 4MB 固定大小对象的序列,赋予全局唯一名称(OID,比如 obj_1)。
  2. **Object to PG (对象归属)**:对 obj_1 的名称进行哈希运算,并将结果取模 PG_NUM。这就不可变更地将其归入了一个具体的 Placement Group(例如:计算出等于 PG 42)。
  3. PG to OSDs (核心: CRUSH):这是最伟大的发明——CRUSH (Controlled Replication Under Scalable Hashing) 算法。
    • 客户端从 MON 处拿到非常小的一张 Cluster Map(包含了机房、机柜、宿主机和硬盘的拓扑树)
    • 客户端在其本地直接用公式算出:CRUSH(PG_42) -> [OSD_3, OSD_9, OSD_45]
    • 这个公式保证了:算出来的 3 个 OSD 副本(假设系统副本数为 3)一定会分散在不同的容错域(Failure Domains)。比如 OSD3 和 OSD9 绝对不会落在同一个机柜内(保证断电时数据不丢)。

这样一来,不需要任何中心查询,任意一台有计算能力的调度客户端就能在一瞬间“算”出数据位于哪里,然后直接跟对应 OSD 发起 TCP 握手通信去捞数据。这是何等惊艳的去中心化性能!

4.3 写入的数据流与强一致性机制

Ceph 遵循极其严苛的一致性设计(相比于追求高吞吐允许丢部分数据的弱一致性系统)。
当发生写入操作时(例如保存 LLM 的 model-epoch-1.ckpt):

  1. 客户端使用 CRUSH 算出该 PG 的三个 OSD 列表 [OSD_A, OSD_B, OSD_C]
  2. 列表排名第一的 OSD_A 自动成为主代理(Primary OSD)。
  3. 客户端将数据包发送给 Primary OSD_A。
  4. OSD_A 收到后,内部并行向次级副本 OSD_BOSD_C 转发写入请求。
  5. 直到 B 和 C 都落盘并向 A 回复 ACK 后,Primary OSD_A 才会统一向客户端返回 Write Success
    这保证了在任何读取时刻(就算同时并发发生宕机主从切换),AI 跑出来的权重永远不会遇到脏数据回退(Silent Data Corruption)。

5. 高性能存储引擎:BlueStore 深水区

传统的 Ceph 在 OSD 写入物理磁盘时,走的是:RADOS 对象 -> 先写入宿主机 Linux 操作系统的 XFS/ext4 文件系统 -> 硬件磁盘 的链路。
这种做法的软肋在于内核双写效应(Journaling Double Write)和文件系统本身的元数据包袱,这在高速 NVMe 时代被放大了延迟。

现代的 Ceph 标配了 BlueStore 存储引擎
BlueStore **完全绕过了本机的 Ext4 / XFS (Bypass Kernel FS)**。它直接接管裸硬盘块设备!

  • RocksDB:使用一个极度优化的嵌入式 RocksDB 来保存 Object 那些海量的元数据和寻址路径。
  • BlueFS:由于 RocksDB 自己需要跑在文件系统上,Ceph 手搓了一个小型的 C++ 极简微型文件系统(只限给 RocksDB 自己用)。
  • **数据直写 (Direct Write)**:用户真实的业务数据比特流,直接通过异步 IO 落进裸盘地址。

借助 BlueStore 的架构,在应对海量机器视觉碎片图像随机小包读取的机器学习负载中,其 IOPS(每秒读写次数)性能相比原来的 FileStore 飞跃式地提升了 2 到 3 倍。

6. 在机器学习云原生平台中的最佳实践:Rook / CSI

回到我们的 Kubeflow / 原生 Kubernetes 场景。作为一堆分布在物理机上的进程,AI 平台的用户不可能亲自去写 librados 代码或调用命令行管理。
这就不得不提 CNCF 毕业级的大神项目:Rook

6.1 Rook + Ceph:驯服凶兽

Rook 充当了 K8s 中的 Operator。它让复杂的存储引擎部署彻底“Kubernetes-Native 化”。
你只需要用一个 YAML 写明 UseAllNodes: true, UseAllDevices: true。Rook 的控制器就会:

  1. 派 DaemonSet 去给节点上的全新裸磁盘自动进行格式化操作。
  2. 将 OSD、MON、MGR 全部作为 K8s 本生的 Pod(带有 HostNetwork 特权)拉起并维稳。
  3. 如果一块盘坏了,Pod 发生 CrashLoop,Rook 自动发起数据恢复重平衡(Rebalancing)。

6.2 PVC 到底层数据结构的映射与挂载使用

在 AI 平台(如 PAI 或者自己搭建的流水线)提交一个训练任务时,算法工程师只看得到 PVC (Persistent Volume Claim)。这一切是如何打通的?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sequenceDiagram
participant User as 算法工程师 (Job YAML)
participant K8s as K8s API Server
participant CSI as Ceph CSI (Container Storage Interface)
participant Ceph as Ceph Cluster (RBD/CephFS)

User->>K8s: kubectl apply -f train-job.yaml (Requesting PVC: data-vol)
K8s->>CSI: Controller parses StorageClass: csi-cephfs-sc
CSI->>Ceph: gRPC/Admin Command: Create SubVolume (subvol-2321)
Ceph-->>CSI: Subvolume Created Path & Secret
CSI-->>K8s: Create PV (Persistent Volume) and bound to PVC
K8s->>K8s: Schedule Pod to Node-A
Note over Node-A: Kubelet invokes CSI NodePlugin
CSI (NodePlugin)->>Node-A: kernel command: "mount -t ceph mon_addrs:/xxx /var/lib/kubelet/..."
Note over Node-A: 容器里的 /data 目录成功指向 Ceph 集群

在实际的训练中的选型场景:

  • 场景 1:大规模 NLP 语料预处理清洗
    清洗任务往往产生几千万个几十 KB 的分词缓存。建议使用 CephFS StorageClass 创建 RWX 的 PVC,分配给多个 Ray Worker Pod 并发清洗;且强烈建议将 CephFS 的 Metadata Pool (MDS 所需的池) 存放在基于纯 NVMe SSD 的设备组合上,避免海量 ls stat 导致的寻道超时。

  • 场景 2:MLflow 或 HuggingFace 模型仓库构建
    对于不可变的、极大的结果压缩包(50GB .safetensors),最佳实践是不要用 K8s 本地 Volume,而是依靠 **Ceph RGW (S3 兼容网关)**。
    平台应用或训练代码只需使用原生的 boto3(S3 python 包)并配置好 Ceph RGW 的内外网网关入口,将生成的 Checkpoint 以 Http Put 的形式抛给集群的大容量低成本 HDD 后备存储中。不仅杜绝了由于存储满导致容器发生 Pod Eviction 的尴尬悲剧,还能利用存储网关极其廉价地做公网预签名分享(Presigned URL)。

7. 总结:承载智能的汪洋之水

当你在使用 PyTorch 优雅地敲下 torch.save(model.state_dict(), '/data/checkpoint.pth') 时,这背后的 2GB 二进制信息,会迅速经过 K8s 宿主机的网络 namespace、跨越虚拟网桥、被切成了 500 个碎片对象。之后,通过伟大的去中心化算法 CRUSH 被打散映射到浩瀚机房深处的不同物理硬盘内。这一切均在一瞬间完成无感流转,并永远抵御任何硬件级的拔线死亡。

对于现代机器学习平台基建工程师而言,如果没有吃透 Ceph (及其上层 Rook 管理链)就等于建房子没有打好地基
Ceph 提供的数据统一视角(文件供训练集、块供平台数据库、对象供制品),极高的高可用与强扩展性(无惧 AI 算力潮汐导致的多节点规模激增),让它真正承载起了驱动百模大战的“汪洋之水”,成为了 AI Infra 版图中最为耀眼、稳定且厚重的定海神针。