机器学习平台技术栈之 Ceph:筑牢 AI 时代的统一数据底座
机器学习平台技术栈之 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 训练任务对存储系统提出了哪些“变态”的要求:
- **海量小文件并发读取 (I/O 梦魇)**:计算机视觉(CV)训练往往需要每个 Epoch 随机打乱并读取数千万张几十 KB 的小图片(通过 PyTorch DataLoader)。传统的集中式存储在面对这种高并发元数据(Metadata)检索时,响应极易拥塞崩溃。
- **大文件极速写入 (Checkpoint 风暴)**:千亿参数的大模型训练往往采用 3D 并行,需要每隔几小时将当前的权重状态同时转储。几百个 GPU 并发写入几百 GB 数据,网络吞吐压力瞬间爆表。
- **多节点数据强一致共享 (RWX 支持)**:分布式训练中,通常需要多台物理机(多个 Pod)同时挂载同一份数据目录进行并行读取。这需要存储系统支持
ReadWriteMany(RWX)语义。 - 结构化与非结构化杂糅:既需要极其快速的文件系统(如挂载训练集),又需要廉价且海量的对象存储(用来做数据集归档和 MLflow 模型无版本管理)。
为了解决同时想要“文件、块、对象”的痛点,Ceph 走上了全能王的王座。
2. 核心架构设计与三种存储形态
Ceph 的架构设计是一首优雅的冰与火之歌。它的基本哲学是:底层构建一个无限可扩展的、强一致的、去中心化的对象存储底座(RADOS),然后再并在其上套不同的马甲(接口)向外界提供服务。
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 --> RADOSCeph 向上方提供的三大引擎:
- **RBD (块存储)**:向 K8s 暴露为一个纯底层的裸盘。速度极快,用于挂载给数据库(如 AI 平台底层的 MySQL 或 Redis),一般仅支持单节点读写(
ReadWriteOnce, RWO)。 - **CephFS (文件存储)**:符合 POSIX 语义标准。可以像普通硬盘一样在多台机器配置中被
mount,并支持群组并发读写(ReadWriteMany, RWX)。在 AI 领域,这是挂载训练源码、日志、数据集最高频的存储方式。 - **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)
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 计算步骤极其精妙的解构:
- **File to Object (文件切被割)**:系统将该文件切分成多个通常是 4MB 固定大小对象的序列,赋予全局唯一名称(OID,比如
obj_1)。 - **Object to PG (对象归属)**:对
obj_1的名称进行哈希运算,并将结果取模PG_NUM。这就不可变更地将其归入了一个具体的 Placement Group(例如:计算出等于 PG 42)。 - 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):
- 客户端使用 CRUSH 算出该 PG 的三个 OSD 列表
[OSD_A, OSD_B, OSD_C]。 - 列表排名第一的
OSD_A自动成为主代理(Primary OSD)。 - 客户端只将数据包发送给 Primary OSD_A。
- OSD_A 收到后,内部并行向次级副本
OSD_B和OSD_C转发写入请求。 - 直到 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 的控制器就会:
- 派 DaemonSet 去给节点上的全新裸磁盘自动进行格式化操作。
- 将 OSD、MON、MGR 全部作为 K8s 本生的 Pod(带有 HostNetwork 特权)拉起并维稳。
- 如果一块盘坏了,Pod 发生 CrashLoop,Rook 自动发起数据恢复重平衡(Rebalancing)。
6.2 PVC 到底层数据结构的映射与挂载使用
在 AI 平台(如 PAI 或者自己搭建的流水线)提交一个训练任务时,算法工程师只看得到 PVC (Persistent Volume Claim)。这一切是如何打通的?
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 的分词缓存。建议使用 CephFSStorageClass创建RWX的 PVC,分配给多个 Ray Worker Pod 并发清洗;且强烈建议将 CephFS 的 Metadata Pool (MDS 所需的池) 存放在基于纯 NVMe SSD 的设备组合上,避免海量lsstat导致的寻道超时。场景 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 版图中最为耀眼、稳定且厚重的定海神针。






