想象你经营着一座大型仓库,每天要接待三种客人。第一种客人拖来一箱箱包裹,要求每个包裹一个独立凭条,扔进储物柜就走,取件时扫码即取;第二种客人运来整台机器,要求把整个集装箱原封不动地搬走、随时还能再搬回来;第三种客人是某公司的员工,他们要在共用的文件柜里,沿着“部门-项目-文档”的目录翻找、修改文件。以前你只能开三座仓库分别打理——三套货架、三支管理团队、三套维修预算,成本高、利用率低。而 Ceph 就是一座“一仓三区”的超级智慧仓库:一套货架体系、一套管理系统、一个统一底座,对象、块、文件三种货物都能进同一座仓库,由同一套分拣规则自动落位、自动复制、自动容灾。本文就借用这座智慧仓库,带你从零看懂 Ceph 如何统一对象、块、文件三类存储,以及它凭什么成为云原生时代的存储主角。

岗位关联

掌握 Ceph 多协议统一存储的架构逻辑,是云存储架构师的核心竞争力——它决定你能否用一套集群优雅承接 AI 数据湖、训练共享数据集与容器云盘等多样负载。

目录
  1. 可视化演示
  2. 三种存储形态
  3. Ceph整体架构
  4. 对象存储RGW
  5. 块存储RBD
  6. 文件存储CephFS
  7. 统一架构优势
  8. 与MinIO对比
  9. 云原生部署
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示RADOS统一存储CRUSH数据分布、RBD/RGW/CephFS三接口架构、副本与纠删码冗余策略对比三阶段探索。

本节配有交互动效(进入视口后自动加载,约 3KB)。

RADOS统一存储与CRUSH分布 客户端计算PG后通过CRUSH定位OSD PG映射到多个OSD实现数据分布 三副本写入保证数据可靠性 PG = hash(object_name) % pg_num 去中心化CRUSH算法无需查表定位

三种存储形态

走进这座智慧仓库,你会看到三个风格迥异的区域。A 区是快递储物柜,一格格小柜子各装各的货,每个柜子贴着一张唯一取件码,你不需要知道货在第几排第几列,只要念出取件码,柜门自己就开——这是“对象存储”。B 区是货运集装箱堆场,整箱整箱的货物被塞进一个标准集装箱,拖车来了直接整箱拉走,上了客户的车再自己拆箱——这是“块存储”。C 区是共享文件柜,员工沿着“部门-项目-文档”的目录逐层打开,像翻文件夹一样找文件——这是“文件存储”。三种区收货、取货的方式完全不同,但它们都有一座仓库在背后支撑。

计算机世界里的“仓库”就是存储系统,这三种区对应三种核心存储形态。对象存储以“桶(Bucket)+ 键(Key)”定位数据,每个对象自带元数据,适合海量非结构化数据;块存储把磁盘切成固定大小的小块(Block),按块号读写,延迟低,适合虚拟机的云硬盘;文件存储则维护一棵目录树,支持按路径打开、追加、修改,语义对开发者最友好。

把它们放进 Ceph 这座统一仓库后,一个必须算清的问题是:仓库会为防盗把每件货复制三份,那你能真正使用的空间是多少?

回到仓库,这段话要记住:储物柜(对象)、集装箱(块)、文件柜(文件)只是三种不同的“取货姿势”,而它们消耗的都是同一批货架。货架总容量要先扣掉防盗复制的占用,才是你真正能堆货的空间。理解这一点,后面看 Ceph 的副本策略、纠删码就都不难了。

C可用=C原始N副本\displaystyle C_{\text{可用}} = \frac{C_{\text{原始}}}{N_{\text{副本}}}
这行公式告诉我们:集群物理磁盘总容量,除以副本数,才是真正能写入用户数据的容量。
  1. 原始容量所有磁盘的物理容量相加,比如 3 块 1TB 磁盘,原始容量就是 3TB。
    C原始=3TB\displaystyle C_{\text{原始}} = 3\text{TB}
  2. 副本数一份数据在集群中保留几份拷贝,Ceph 默认三副本,所以是 3。
    N副本=3\displaystyle N_{\text{副本}} = 3
  3. 相除物理容量按副本数摊薄,3TB ÷ 3 = 1TB,这就是真正可用的写空间。
    C可用=3TB3=1TB\displaystyle C_{\text{可用}} = \frac{3\text{TB}}{3} = 1\text{TB}

Ceph整体架构

要让三个区运转起来,仓库需要一套指挥体系。首先是大门旁的总登记处——一组值班员实时盯着每块货架的位置、剩余仓位和健康状况,任何货架倒了他们第一时间知道,这叫 Monitor(监控)。其次,每个货架配一名管理员,货物存取都经他手,他每天向登记处汇报货架状态,这叫 OSD(对象存储守护进程)。最后,仓库有一本超级分拣手册,新货进门不用问任何人,按手册一查就知道该放哪几块货架,这就是 CRUSH 算法。

这套指挥体系的精妙之处在于“去中心化”。客户端要读写数据时,先找 Monitor 问清楚集群状况,拿到一张“集群地图”,之后所有数据位置都由本地 CRUSH 算法直接算出——不需要每次访问都问总登记处。这就像一个熟练的仓管员,已经记住了分拣规则,货一来自己就动手,效率极高。

那 OS 之间怎么组织?Ceph 把货架划成一个个分区(Pool),每个分区里再划分大量“货位小组”(Placement Group,PG)。数据先粗糙地均匀分到某个 PG,PG 再由 CRUSH 映射到具体货架。PG 数量直接决定数据分布均匀度和恢复速度,运维中有个经验公式:

回到我们的仓库:Monitor 是值班登记处,OSD 是货架管理员,CRUSH 是分拣手册,Pool 和 PG 则是分区的两级编号。这套体系让 Ceph 在没有“总调度长”的情况下,也能做到数据自动分布、自动复制、自动恢复——这正是它能统一三种存储的底气。

NPG≈NOSD×100N副本\displaystyle N_{\text{PG}} \approx \frac{N_{\text{OSD}} \times 100}{N_{\text{副本}}}
这是集群初始化时估算 PG 总数的经验法则:每个 OSD 大约承担 100 个 PG,再除以副本数摊薄。
  1. OSD 总数集群中所有货架管理员(OSD)的个数。
    NOSD=9\displaystyle N_{\text{OSD}} = 9
  2. 乘以 100每个管理员建议同时管约 100 个货位小组,这是经验上性能与内存的平衡点。
    NOSD×100=900\displaystyle N_{\text{OSD}} \times 100 = 900
  3. 除以副本数每个 PG 的副本会分散到多个 OSD 上,所以总数需要按副本数折减。
    NPG≈9003=300\displaystyle N_{\text{PG}} \approx \frac{900}{3} = 300

对象存储RGW

再看储物柜区。最初它只是普通储物柜,后来仓库在门口装了一台“自助取件终端”,写着统一的取件协议,无论谁家的快递小哥来,都按同一套流程存件取件。这台终端就是 RGW(RADOS Gateway),它对外只讲一种“普通话”—— S3 协议,Amazon S3 兼容的对象存储接口。

S3 协议的世界里有两个核心词:Bucket(桶) 和 Key(键)。Bucket 相当于储物柜区里的一个大柜组,你可以把它理解成“相册”或“项目目录”;Key 就是柜组里的某个格子编号,通常就是文件名。要访问某个对象,客户端用 HTTP 协议发一个请求,路径写清楚桶名和键名即可,这便是 REST 风格的读写方式。

用 S3 协议操作对象,本质就是在拼一个“取件地址”:

回到储物柜区:RGW 就是那台自助终端,S3 是统一取件协议,Bucket 和 Key 是两级定位编号。无论客户用 Python、Java、Go 还是命令行工具,只要会说 S3 的“普通话”,就能把海量图片、视频、日志塞进 Ceph 这座大仓库。这也是 AI 数据湖最常用的接入方式。

ObjectURL=scheme://host:port / bucket / key\displaystyle \text{ObjectURL} = \text{scheme}://\text{host}:\text{port}\,/\,\text{bucket}\,/\,\text{key}
一个对象在网络上的完整访问路径:协议 + 仓库地址 + 桶名 + 对象键名。
  1. scheme//host:port:协议头和仓库网络地址,例如 http://ceph-gw:8080。
    scheme=http,host:port=ceph-gw:8080\displaystyle \text{scheme} = \text{http},\quad \text{host}:\text{port} = \text{ceph-gw}:8080
  2. bucket大柜组名,对应 S3 里的桶,例如 my-ai-data。
    bucket=my-ai-data\displaystyle \text{bucket} = \text{my-ai-data}
  3. key柜子里的取件码/对象名,例如 images/cat.jpg。
    key=images/cat.jpg\displaystyle \text{key} = \text{images/cat.jpg}

块存储RBD

B 区集装箱堆场的玩法更“硬核”。客户不是来寄零散包裹的,而是整箱租用:仓库把一块大空地按固定尺寸划成标准集装箱,客户可以往里面任意装自己的东西,改装、拆装都不受仓库管。这种“整块租给你、按块号寻址”的服务,就是 Ceph 的 RBD(RADOS Block Device) 块存储。

想要一块集装箱,客户端通过 rbd create 命令建一个块设备映像(Image),之后通过内核驱动或 librbd 库把它映射成一块“虚拟硬盘”。虚拟机、容器看到的是一块真实的磁盘,可以分分区、装文件系统,读写请求落到底层时被切成一串固定大小的块,由 CRUSH 分散到各个货架。

集装箱业务有两个高级玩法:快照(Snapshot) 和 克隆(Clone)。快照就像给集装箱某一瞬间的货物内容拍一张“定妆照”,只读、秒级完成;克隆则是基于快照生成一个全新的集装箱,新箱子和老箱子先共享同一批货,只有当新箱子里写入新货时,才会复制出属于自己的那份。这种“先共享、写时再复制”的技巧叫写时拷贝(Copy-on-Write):

回到集装箱区:RBD 让 Ceph 化身“虚拟硬盘工厂”,一块块云硬盘以极低延迟供给虚拟机;快照是保险的定妆照,克隆是秒开的新箱子。在 OpenStack 和 Kubernetes 里,RBD 都是最受欢迎的持久化存储方案之一。

Clone=Snapshot+Δ新写入\displaystyle \text{Clone} = \text{Snapshot} + \Delta_{\text{新写入}}
克隆的底层逻辑:从快照继承全部旧数据,叠加自己新产生的增量数据。
  1. 快照某一时刻数据的只读镜像,是克隆的地基。
    Snapshot=某一时刻的数据状态\displaystyle \text{Snapshot} = \text{某一时刻的数据状态}
  2. 增量克隆创建后新写入的数据,只属于新容器。
    Δ新写入=新数据块\displaystyle \Delta_{\text{新写入}} = \text{新数据块}
  3. 叠加客片读旧数据时命中快照,写新数据时才复制,节省大量空间。
    Clone=共享旧数据+私有新数据\displaystyle \text{Clone} = \text{共享旧数据} + \text{私有新数据}

文件存储CephFS

C 区共享文件柜最贴近普通人的直觉:一堆柜子,每层有文件夹,打开文件夹还有子文件夹,所有人都按路径找文件。这就是 CephFS——Ceph 提供的文件存储服务,它完整支持 POSIX 语义,你可以像使用本地 Linux 目录一样 ls、cd、cat、mkdir。

但共享文件柜有个大难题:多人同时找文件,怎么快速定位“这个文件在哪个柜子的哪一层”?仓库专门设了一个“索引卡片室”,里头存放所有文件的目录树和位置索引,这就是 MDS(元数据服务器)。数据本体仍然分散在货架上,MDS 只负责回答“文件在哪”,两者分工明确,所以 CephFS 既能做大目录树,又能扛高并发访问。

从文件系统的视角看,一个文件由“身份证 + 数据块列表”两部分组成。身份证叫 inode,记录权限、大小、时间戳等元数据;数据块列表则记录这个文件被切成哪些块、分别存在哪个货位。读文件时,先查身份证,再按列表把数据块拼起来:

回到文件柜区:CephFS 给了大家一台“无限大的共享文件柜”,MDS 是索引卡片室,inode 加数据块的组合保证了单文件也能被几十台机器并发读取。AI 训练场景里,几十个 GPU 节点同时读同一份数据集,CephFS 是最顺手的方案。

File=inode⏟元数据+∑i=1ndatai⏟数据块\displaystyle \text{File} = \underbrace{\text{inode}}_{\text{元数据}} + \sum_{i=1}^{n} \underbrace{\text{data}_i}_{\text{数据块}}
一个文件等于它的元数据(inode)加上所有数据块的总和。
  1. inode文件的身份证号,记录权限、大小、时间等元数据。
    inode=元数据结构\displaystyle \text{inode} = \text{元数据结构}
  2. data_i文件内容被切成 n 个数据块,每块存到不同货架,天然支持并行读。
    datai, i=1,2,…,n\displaystyle \text{data}_i,\ i = 1,2,\dots,n
  3. 求和把所有数据块按顺序拼起来,就是完整文件内容。
    ∑i=1ndatai=完整文件数据\displaystyle \sum_{i=1}^{n} \text{data}_i = \text{完整文件数据}

统一架构优势

讲到这里,智慧仓库“一仓三区”的设计价值已经浮现:三套取货姿势,背后是同一批货架、同一套分拣规则、同一个值班登记处。传统方案要养三座独立仓库——对象存储一套集群、块存储一套集群、文件存储一套集群,每套集群都有各自的监控、各自的管理员、各自的故障处理流程,光运维成本就是三倍。

Ceph 的统一底座叫 librados,所有上层服务(RGW、RBD、CephFS)都调用它读写同一批 OSD。这带来两个直接优势。其一是资源池共享:A 区储物柜空闲时,货架可以借给 B 区集装箱堆货,物理空间利用率大幅提升。其二是故障域感知:副本不再是“随便放三块货架”,而是按故障域规则分散——比如三块货架必须分属三栋不同楼,防止一栋楼着火全灭。

用概率来量化一下就更有说服力。假设每个故障域(比如一栋机房)同时宕掉的概率是 \(p\),副本被 CRUSH 分散到 \(D\) 个不同故障域,那么数据丢失只发生在 \(D\) 个故障域同时宕机时:

回到仓库:一套管理系统管三个区,货架通用、空间互济、一个保安队巡全场。统一架构不仅省了运维成本,还让“数据不丢”从口号变成了可计算的概率——这正是云原生时代 Ceph 能与 HDFS、传统 SAN 正面竞争的根本原因。

A=1−p D\displaystyle A = 1 - p^{\,D}
可用性 = 1 减去所有容纳副本的故障域同时宕机的概率。
  1. 单个故障域故障率 p假设一栋机房整体宕机的概率为 10%,即 p = 0.1。
    p=0.1\displaystyle p = 0.1
  2. 跨故障域数 D三副本被分到 3 个故障域,D = 3。
    D=3\displaystyle D = 3
  3. 同时宕机概率与可用性\(p^D = 0.001\),可用性高达 99.9%。
    A=1−0.13=99.9%\displaystyle A = 1 - 0.1^3 = 99.9\%

与MinIO对比

说到对象存储,很多人会立刻想到街角的“快递驿站”——MinIO。它门店小、装修快、只做储物柜生意,一个二进制文件启动就能提供服务,几分钟就能开张。而我们的 Ceph 是一座全能大仓库,开业要装货架、配管理员、建管理系统,前期准备重得多。两者定位完全不同,选择取决于你要什么。

功能范围上,MinIO 只提供对象存储(S3 兼容),而 Ceph 一套集群同时提供对象(RGW)、块(RBD)、文件(CephFS)三种服务。部署复杂度上,MinIO 单二进制、无外部依赖,Ceph 至少需要 Mon、MGR、OSD 三类组件,上手门槛明显更高。扩展性上,两者都支持分布式水平扩展,但 Ceph 的单集群规模通常可以做到数百至数千节点,生态整合更重。

两者在数据保护上都支持纠删码(Erasure Coding)技术,把文件切成 k 份数据块加 m 份校验块,任意损失不超过 m 块都能恢复。空间效率是这个比值:

回到街角对比:如果业务只要求“海量对象存储、要快、要轻”,MinIO 这座快递驿站是性价比之选;如果既要对象存储,又要虚拟机云盘、又要共享文件系统,那 Ceph 这座全能大仓库才能一肩挑。两者的关系不是谁替代谁,而是“驿站 vs 全能仓库”的定位差异。

E=kk+m\displaystyle E = \frac{k}{k + m}
纠删码空间效率 = 数据块数除以数据块与校验块之和。
  1. 数据块数 k文件被切成 k 个数据块,比如 4 块。
    k=4\displaystyle k = 4
  2. 校验块数 m额外生成 m 个校验块用于恢复,比如 2 块。
    m=2\displaystyle m = 2
  3. 效率比值实际可用空间占比 \(4/(4+2) \approx 66.7\%\),比三副本的 33.3% 高得多。
    E=44+2≈0.667\displaystyle E = \frac{4}{4+2} \approx 0.667

云原生部署

最后一步,是把这座大仓库搬进现代化的“K8s 公寓小区”。在容器世界里,直接裸机装 Ceph 需要手工配一堆组件,极容易出错。于是出现了专职的“物业装修团队”——Rook,它把 Ceph 的部署、扩容、升级全部定义为 Kubernetes 原生资源,你只要声明“我要一个 3 节点的 Ceph 集群”,Rook 就自动把货架、管理员、登记处逐个部署到位。

公寓里的应用要怎么用仓库?靠的是 CSI(容器存储接口)。CSI 是 K8s 与存储系统之间的“统一水电接口”:应用声明一份存储需求(PVC),K8s 通过 CSI 插件向 Ceph 申请一块存储,创建完成后挂载进 Pod。管理员只需提前定义好各种规格的 StorageClass,比如“高速三副本”“省磁盘纠删码”,用户按需选择即可,整个过程一键自动化。

部署前还要做一道算术题:规划到底需要多少块盘。假设业务目标容量是 10TB,采用三副本,每块盘 4TB:

回到公寓场景:Rook 是自动装修的物业,CSI 是统一水电接口,StorageClass 是一本“套餐菜单”,容量公式则是装修前的预算清单。有了这一套组合拳,Ceph 在 Kubernetes 上的部署从“三天手工大战”变成了“一条命令搞定”,这也就是今天云原生存储架构师最常接触的落地姿势。

NOSD=⌈C目标×N副本C单盘⌉\displaystyle N_{\text{OSD}} = \left\lceil \frac{C_{\text{目标}} \times N_{\text{副本}}}{C_{\text{单盘}}} \right\rceil
所需 OSD(货架)数量 = 目标容量 × 副本数,再除以单盘容量,向上取整。
  1. 目标容量与副本数业务要 10TB 可用空间,三副本意味着物理上要占 30TB。
    C目标×N副本=10TB×3=30TB\displaystyle C_{\text{目标}} \times N_{\text{副本}} = 10\text{TB} \times 3 = 30\text{TB}
  2. 除以单盘容量每块盘 4TB,需要 \(30/4 = 7.5\) 块盘。
    30TB4TB=7.5\displaystyle \frac{30\text{TB}}{4\text{TB}} = 7.5
  3. 向上取整盘必须整块买,7.5 块向上取整为 8 块 OSD。
    NOSD=⌈7.5⌉=8\displaystyle N_{\text{OSD}} = \lceil 7.5 \rceil = 8

AI 应用场景

AI 数据湖与模型归档(对象存储 RGW)

阶段:数据准备与存储层

解决的问题:AI 训练数据爆发式增长,传统 HDFS 元数据压力大、扩容成本高;而 NAS 在面对海量小文件时会严重性能退化。Ceph RGW 对外提供 S3 标准接口,对象可附带自定义元数据,配合生命周期策略自动做冷热分层,让海量原始数据以极低成本长期留存。

具体案例:某 AI 公司每天从移动端采集数百万张图片和视频用于模型迭代。他们把原始数据写入 RGW 的 raw-data 桶,配置生命周期规则:90 天前的对象自动沉降到纠删码冷存储池。半年后存储成本下降约 40%,而数据访问接口完全不变。

分布式训练共享数据集(文件存储 CephFS)

阶段:模型训练

解决的问题:多台 GPU 节点需要同时读取同一份数据集。本地盘不共享,把数据集复制 N 份既浪费空间又增加准备时间。CephFS 提供 POSIX 语义的共享目录,几十个训练 Pod 可同时挂载同一份数据,MDS 高效处理元数据请求。

具体案例:某自动驾驶团队用 32 台 GPU 节点训练检测模型,数据集共 2TB、含 120 万张图片。改用 CephFS 共享数据集后,数据准备时间从 40 分钟压缩到 5 分钟,训练启动速度提升 8 倍,且不再需要每台节点预留本地副本。

训练节点云盘与检查点保护(块存储 RBD)

阶段:模型训练与容错

解决的问题:GPU 节点的本地 NVMe 盘故障会导致整个训练中断,而频繁落盘 checkpoint 需要高性能持久卷。RBD 块存储延迟低、支持秒级快照,是训练节点持久盘和检查点保护的理想选择。

具体案例:某大模型训练平台为每个训练任务创建一个 RBD 云盘,每 30 秒自动打一次快照。当某节点宕机,调度器从最近快照恢复工作负载,训练中断时间从小时级降到分钟级,checkpoint 丢失率降为零。

Python 演示

python80 行
# -*- coding: utf-8 -*-"""迷你Ceph模拟:对象经一致性哈希选OSD,按副本数落盘,单盘故障不影响读取"""import hashlib OSD_NUM = 8REPLICA = 3RING_SIZE = 65536  def hash_ring(key, ring_size=RING_SIZE):    h = int(hashlib.md5(key.encode()).hexdigest(), 16)    return h % ring_size  class MiniCeph:    def __init__(self, osd_num=OSD_NUM, replica=REPLICA):        self.osd_num = osd_num        self.replica = replica        self.disks = [dict() for _ in range(osd_num)]     def _select_osds(self, obj_key):        ring = {}        for i in range(self.osd_num):            for v in range(20):                node_key = "osd-%d-v%d" % (i, v)                ring[hash_ring(node_key)] = i        pos = hash_ring(obj_key)        chosen = []        for step in range(self.osd_num * 20):            p = (pos + step) % RING_SIZE            if p in ring and ring[p] not in chosen:                chosen.append(ring[p])            if len(chosen) >= self.replica:                break        return sorted(chosen)     def put(self, bucket, key, data):        obj_key = "%s/%s" % (bucket, key)        osds = self._select_osds(obj_key)        for oid in osds:            self.disks[oid][obj_key] = data        return osds     def get(self, bucket, key):        obj_key = "%s/%s" % (bucket, key)        osds = self._select_osds(obj_key)        for oid in osds:            if obj_key in self.disks[oid]:                return self.disks[oid][obj_key]        return None     def simulate_disk_failure(self, oid):        self.disks[oid] = {}  def main():    ceph = MiniCeph()    records = []    for i in range(10):        key = "photo-%d.jpg" % i        osds = ceph.put("album", key, "<data-%d>" % i)        records.append((key, osds))    print("写入日志:")    for key, osds in records:        print("  %s -> OSD %s" % (key, osds))    ceph.simulate_disk_failure(3)    print("\n模拟 OSD3 宕机后读取:")    ok = 0    for key, osds in records:        data = ceph.get("album", key)        if data is not None:            print("  %s 仍可读取 (副本在 %s)" % (key, osds))            ok += 1        else:            print("  %s 丢失!" % key)    print("\n数据可用性: %d/%d" % (ok, len(records)))  if __name__ == "__main__":    main()
目的:用纯 Python 模拟 Ceph 的 CRUSH 思想——对象经过一致性哈希选出一组 OSD,按副本数落盘;某块盘宕机后,副本仍能保证数据可读。
  1. hash_ring(key)把字符串哈希到 0~65535 的圆环上,模拟一致性哈希的取模定位。
  2. self.disks = [dict() for _ in range(osd_num)]每个 OSD 就是一个小货架,用字典存放对象。
  3. for v in range(20)每块货架生成 20 个虚拟节点,让数据分布更均匀。
  4. _select_osds从对象哈希位置出发沿环查找,选出不重复的 N 个 OSD,模拟 CRUSH 选主副本。
  5. for oid in osds:同样的数据写入多块“货架”,实现三副本冗余。
  6. simulate_disk_failure(3)模拟 3 号 OSD 宕机,验证其他副本的兜底能力。

常见误区

误区我以为 Ceph 的三副本就像手工复制三份文件放在三个地方,跟传统备份软件一样,任何时刻都能找回“某个时刻的旧版本”。

正解副本和备份是两回事。副本是同一份数据在多个货架上的实时镜像,它们永远保持同步,提供的是“抗硬件故障”能力;而备份是某一时间点的历史快照,提供的是“抗误删、防篡改”能力。就像仓库里同一件货复制三份放不同货架,防止的是货架塌了,而不是防小偷把货偷走后再也不出现。要防误删,得靠快照和备份策略。

为何常见:因为“副本”和“备份”在日常语言里都叫“复制一份”,初学者很容易把实时冗余和历史保护混为一谈。

误区我以为只要 Ceph 提供了 RGW 对象存储,就能像 SMB/NFS 网盘那样 `mount` 到服务器上,获得一个普通文件夹。

正解对象存储没有 POSIX 目录树语义,它的“目录”只是 Key 里的斜杠字符串,不支持随机写、追加写、文件锁等操作。就像快递储物柜只能“整件存、整件取”,你不能把柜门打开后往里一条一条地追加货物。要用对象当网盘,必须加一层 FUSE 网关(如 s3fs),但这层网关会牺牲性能和一致性。

为何常见:很多云产品把对象存储和网盘混在一起宣传,让人误以为 S3 后端就是文件夹,忽略了底层语义的巨大差异。

误区我以为 PG 就像把大饼切得越细越均匀,所以集群 PG 总数越大越好,最好追求更多。

正解PG 太多会导致每个 OSD 需要维护的 PG 数目暴涨,内存占用升高、心跳开销变大,集群异常时 PG 恢复互相争抢资源,反而拖垮性能。PG 太少又会导致单 PG 内数据量过大、均衡性差。运维上有经验公式 \(N_{PG} \approx N_{OSD} \times 100 / N_{副本}\),本质是找平衡点,而不是单调追求更多。

为何常见:直觉上“细粒度 = 更均匀”,但忽略了分布式系统的管理成本会随粒度上升,这是典型的局部最优直觉陷阱。

误区我以为 Rook 把 Ceph 部署在 Kubernetes 里,有了自动编排,存储容量规划、故障域设计、版本升级全都不用管了。

正解Rook 只负责部署和编排,相当于物业帮你把仓库装修好了,但仓库里放什么货、货架怎么布局、着火时怎么隔离,仍需存储团队设计。故障域(Failure Domain)要人工指定,容量规划要按业务增长预估,OSD 坏了要确认替换流程,快照和备份策略也要自己配置。Rook 消灭的是“部署步骤”,不是“架构设计责任”。

为何常见:自动化工具的名字和宣传容易给人“全自动”的错觉,人们倾向于把编排自动化等同于运维智能化。

面试题

Q1. RGW 对外主要提供哪种存储协议接口?

单选题 · easy

  • A.NFS 文件协议
  • B.S3 对象协议← 正确答案
  • C.iSCSI 块协议
  • D.FUSE 文件协议

答案:B。RGW 全称 RADOS Gateway,是 Ceph 的对象存储网关,对外提供与 Amazon S3 兼容的对象存储 API,也支持 OpenStack Swift 协议。NFS 是文件协议、iSCSI 是块协议,均不是 RGW 的默认主力接口。

Q2. Ceph 集群中真正负责落盘保存数据的组件是?

单选题 · easy

  • A.Monitor 组件
  • B.MGR 组件
  • C.OSD 组件← 正确答案
  • D.RGW 组件

答案:C。OSD(Object Storage Daemon)是 Ceph 的“货架管理员”,所有数据最终都写入 OSD 管理的磁盘。Monitor 负责维护集群地图,MGR 负责收集指标,RGW 负责对象网关,三者都不直接存用户数据。

Q3. 一个 3 节点 Ceph 集群,每节点 1TB 磁盘,三副本策略下可用容量约为?

单选题 · mid

  • A.约 3TB
  • B.约 2TB
  • C.约 1TB← 正确答案
  • D.约 0.5TB

答案:C。原始容量 = 3 × 1TB = 3TB,三副本把每份数据复制三份,可用容量 = 原始容量 ÷ 副本数 = 3TB ÷ 3 = 1TB。可用容量公式 \(C_{可用} = C_{原始} / N_{副本}\) 是存储规划的第一道算术题。

Q4. RBD 块存储最典型的应用场景是?

单选题 · mid

  • A.海量照片归档存储
  • B.虚拟机云硬盘存储← 正确答案
  • C.共享目录文件存储
  • D.日志备份到对象库

答案:B。RBD 以块设备形式供给客户端,延迟低、支持快照克隆,最典型用途是给虚拟机或容器提供云硬盘。海量照片归档适合 RGW 对象存储,共享目录适合 CephFS,日志归档走对象存储更合理。

Q5. 关于 CephFS,下列说法正确的有?

多选题 · mid

  • A.提供 POSIX 语义← 正确答案
  • B.支持目录树结构← 正确答案
  • C.需要 MDS 管理元数据← 正确答案
  • D.仅能单进程访问

答案:ABC。CephFS 是 Ceph 的文件存储服务,提供类 POSIX 的目录树语义,多个客户端可并发读写同一文件系统;MDS(元数据服务器)专门维护目录树和 inode 索引。“仅能单进程访问”是错误的,CephFS 恰恰以多节点共享见长,是分布式训练共享数据集的理想选择。

Q6. CRUSH 算法在 Ceph 中的核心作用是什么?

单选题 · mid

  • A.对用户密码加密
  • B.决定数据落哪个 OSD← 正确答案
  • C.压缩对象存储体积
  • D.监控节点心跳状态

答案:B。CRUSH 是 Ceph 的“分拣手册”,输入对象名和集群地图,直接算出数据应放在哪些 OSD 上,无需中央索引表。加密、压缩、心跳监控都不是 CRUSH 的职责。它的去中心化特性让集群无需查表即可定位数据,是 Ceph 高扩展性的基石。

Q7. 假设单个故障域宕机概率为 10%,三副本被分散到 3 个不同故障域,集群数据可用性约为?

单选题 · hard

  • A.99.9%← 正确答案
  • B.99.7%
  • C.97.3%
  • D.99.99%

答案:A。只有三个故障域同时宕机数据才会丢失,概率为 \(0.1^3 = 0.001\),可用性 \(A = 1 - 0.001 = 99.9\%\)。这体现了 Ceph 故障域感知的核心价值:把副本分散到不同故障域,让数据丢失概率随故障域数量指数级下降。

Q8. 与 Ceph 相比,MinIO 主要缺少哪类存储能力?

单选题 · easy

  • A.对象存储能力
  • B.S3 兼容 API
  • C.块文件存储能力← 正确答案
  • D.分布式扩展能力

答案:C。MinIO 是纯对象存储系统,提供 S3 兼容 API 且支持分布式部署,但它没有块存储(RBD)和文件存储(CephFS)能力。如果业务需要一套集群同时支撑云盘、共享目录和海量对象,Ceph 比 MinIO 更合适。

Q9. Rook 在 Kubernetes 中为 Ceph 提供了哪些能力?

多选题 · mid

  • A.自动部署编排 OSD← 正确答案
  • B.通过 CSI 供给存储卷← 正确答案
  • C.编译容器运行时镜像
  • D.采集指标并告警← 正确答案

答案:ABD。Rook 在 K8s 中把 Ceph 当作“云原生公民”管理:自动编排 Mon、OSD 等组件,通过 CSI 插件向 Pod 供给存储卷,并暴露监控指标对接 Prometheus 告警。编译容器运行时镜像不是 Rook 的职责,那是容器运行时团队的活。

Q10. 以下哪些场景更适合使用 RGW 对象存储?

多选题 · mid

  • A.海量图片附件归档← 正确答案
  • B.数据湖冷热分层← 正确答案
  • C.容器共享 NAS 目录
  • D.移动端备份服务← 正确答案

答案:ABD。RGW 以 S3 协议服务海量非结构化数据,图片归档、数据湖分层、移动端备份都适合对象存储。容器共享 NAS 目录需要 POSIX 文件语义,应使用 CephFS 或 NFS,而不是 RGW。