分布式存储概览:Ceph / Longhorn / Rook
这一篇不深入运维——分布式存储自己就是个大坑、动辄需要专业团队。但作为 K8s 工程师心智模型必须有:知道它们各自的设计哲学、什么场景用哪个、生产事故的征兆。
这篇要回答什么
- 分布式存储和 NFS / 单点存储区别在哪?
- Ceph / Longhorn / Rook / MinIO / OpenEBS 各自是什么、有什么区别?
- Replicate vs Erasure Coding 哪个适合什么场景?
- CAP / 一致性模型对存储意味着什么?
- K8s 上用分布式存储的几种模式?
- 生产部署有哪些"血泪经验"?
1. 为什么要分布式存储
graph LR
subgraph 单机存储
S1[一块盘 SSD] --> F1[盘坏 = 数据丢]
end
subgraph 单机RAID
R1[RAID 5/6 多盘] --> F2[整机挂 = 数据不可用]
end
subgraph NFS
N1[一台 NFS server] --> F3[server 挂 = 所有客户端挂]
end
subgraph 分布式
D1[N 台机器] --> D2[副本/EC]
D2 --> F4[单点挂 = 自动重建<br>性能近线性扩展]
end
style F1 fill:#ffe1e1
style F2 fill:#ffe1e1
style F3 fill:#ffe1e1
style F4 fill:#e1ffe1
分布式存储的核心两个能力:
- 高可用 —— 单机 / 单盘挂、数据不丢
- 可扩展 —— 加机器 = 容量和性能都线性涨
代价:
- 复杂度爆炸 —— 自己运维需要专业团队
- 延迟更高 —— 多节点协调比单盘慢
- 资源开销 —— 副本占 N 倍空间、EC 占 1.5x
经验法则
- 100 节点以上 K8s 集群 + 重度 IO → 必须分布式存储
- 50 节点以下 + 不重度 IO → 本地 SSD + Local PV 性价比最高
- 中间地带 → 看团队能力 + 业务关键度
2. 主流方案速查
mindmap
root((分布式存储))
传统方案
Ceph
RBD 块
CephFS 文件
RGW 对象
GlusterFS
MooseFS
云原生方案
Longhorn
简单
块存储
K8s 原生
OpenEBS
多种引擎
cStor/Mayastor/Jiva
Portworx
商业
企业级
对象存储
MinIO
S3 兼容
自建
Ceph RGW
MooseFS
K8s 编排
Rook
把 Ceph 装进 K8s
Longhorn
本身就 K8s 原生
一张表对比
| 方案 | 类型 | 复杂度 | K8s 集成 | 适合规模 | 资源占用 |
|---|---|---|---|---|---|
| Ceph | 块 + 文件 + 对象 | 极高 | 通过 Rook | 大型 (100+ 节点) | 高 |
| Rook + Ceph | K8s 自动化 Ceph | 高 | ✅ 原生 | 中大型 | 高 |
| Longhorn | 块 | 低 | ✅ 原生 | 小中型 (< 50 节点) | 中 |
| OpenEBS | 多引擎 | 中 | ✅ 原生 | 中型 | 中(看引擎) |
| Portworx | 块 + 文件 | 中(商业产品) | ✅ | 企业 | 中 |
| MinIO | 对象(S3) | 低 | ✅ | 任意 | 低 |
| GlusterFS | 文件 | 中 | ⚠️ 衰落 | 中 | 中 |
| NFS server | 文件 | 低 | ✅ CSI | 小型 | 低 |
3. Ceph —— 工业标准
graph TB
subgraph 客户端
K8sPod["K8s pod"]
S3Client["S3 客户端"]
CephFSClient["CephFS 客户端"]
end
subgraph Ceph核心
MON["MON<br>(Monitor)<br>集群状态 / map"]
MGR["MGR<br>(Manager)<br>web UI / metrics"]
OSD1["OSD 1<br>(实际存储)<br>盘 + 进程"]
OSD2["OSD 2"]
OSD3["OSD 3"]
MDS["MDS<br>(metadata server)<br>CephFS 用"]
RGW["RGW<br>(S3 网关)"]
end
K8sPod -->|RBD<br>(块)| OSD1
K8sPod -->|RBD| OSD2
CephFSClient --> MDS
MDS --> OSD1
S3Client --> RGW
RGW --> OSD3
style Ceph核心 fill:#e1f5ff
Ceph 的三种服务
| 服务 | 提供 | K8s 用 |
|---|---|---|
| RBD (RADOS Block Device) | 块存储 | PV (RWO) |
| CephFS | 文件存储 | PV (RWX) |
| RGW (RADOS Gateway) | S3 / Swift 对象 | 应用通过 SDK |
三个跑在同一个 Ceph 集群上——存的都是底层 RADOS object。
Ceph 基础概念
- OSD (Object Storage Daemon):一个 OSD = 一块盘 + 一个进程。一个节点上可以跑多个 OSD(每块盘一个)。
- PG (Placement Group):一组 object 的集合、副本一起放。
- CRUSH:决定 PG 放在哪些 OSD 上的算法(保证副本分散)。
- MON:维护 cluster map(哪些 OSD 在线 / pg 位置)。
- 副本数(replicas):默认 3。
- Erasure Coding:类似 RAID5 / 6 算法、省空间但性能差、用于冷数据。
副本 vs Erasure Coding
副本 (replicas=3):
数据 1G → 占盘 3G
读写: 直接随便读一个副本、写需要等多数副本
Erasure Coding (k=4, m=2):
数据 1G → 切 4 块 + 2 块奇偶校验 → 占盘 1.5G
读: 任意 4/6 块就能恢复
写: 需要计算 + 6 块都写、慢
适用:
- 副本 → 热数据(数据库、虚拟机镜像)
- EC → 冷数据(备份、归档、大对象)
生产 Ceph 集群规模
- MON:3 或 5(奇数 quorum)
- OSD:至少 10、生产推荐 30+
- 副本数:3(不要 2)
- 节点数:至少 3 个故障域(机柜 / AZ)
Ceph 的"坑"声誉
Ceph 在社区有"运维难"的口碑、主要原因:
- 概念多(OSD / PG / CRUSH / pool)
- 故障传播快(一个 OSD 慢拖累整个 pool)
- rebalance 风暴(节点加入 / 退出时大量数据迁移)
- 升级风险高
结论:除非有专门 Ceph 运维团队、否则不要自建 Ceph。考虑:
- 云上用云原生存储(EBS / 阿里云盘)
- 用 Rook 包装 Ceph 进 K8s
- 或者用 Longhorn(更简单)
4. Rook —— K8s 原生 Ceph
Rook = K8s Operator + Ceph 自动化部署 / 升级 / 监控
把 Ceph 跑成 K8s Operator——CRD 描述 cluster、Rook controller 帮你装。
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
cephVersion:
image: quay.io/ceph/ceph:v17.2.6
dataDirHostPath: /var/lib/rook
storage:
useAllNodes: true
useAllDevices: true # 用节点上所有未用盘
mon:
count: 3
dashboard:
enabled: true
$ kubectl apply -f cephcluster.yaml
# Rook 自动:
# 1. 在每个节点上跑 OSD pod、占用空闲盘
# 2. 跑 MON / MGR pod
# 3. 提供 RBD / CephFS StorageClass
看 Ceph 状态
$ kubectl exec -n rook-ceph rook-ceph-tools-... -- ceph status
cluster:
id: abc-def-...
health: HEALTH_OK
services:
mon: 3 daemons, quorum a,b,c
mgr: a(active)
osd: 9 osds: 9 up, 9 in
data:
pools: 3 pools, 96 pgs
objects: 5.21k objects, 12 GiB
usage: 36 GiB used, 270 GiB / 306 GiB avail
pgs: 96 active+clean
HEALTH_OK = 一切好。HEALTH_WARN / HEALTH_ERR 要查。
Rook + Ceph 的优劣
✅ 好处:
- K8s 原生(CRD 管理)
- 自动化升级
- 多 storage type(块 / 文件 / 对象)
- 健康检查 + 告警都进 Prometheus
❌ 挑战:
- Ceph 本身的复杂度还在
- 资源开销大(每节点 OSD 内存 ~4G)
- 升级风险高(Ceph 升级 + Rook 升级)
5. Longhorn —— K8s 原生 + 简单
Rancher 出品。专门为 K8s 设计的块存储。
graph TB
subgraph LonghornNode1[节点 m1]
E1["Engine<br>(per volume)"]
R1["Replica 1<br>本地数据"]
end
subgraph LonghornNode2[节点 m2]
R2["Replica 2"]
end
subgraph LonghornNode3[节点 m3]
R3["Replica 3"]
end
Pod[Pod] -->|iSCSI| E1
E1 -->|同步写| R1
E1 -->|同步写| R2
E1 -->|同步写| R3
style Pod fill:#e1f5ff
Longhorn 的设计
- 每个 volume 一个独立的 Engine (进程 / pod)
- 多副本(默认 3)分布在不同节点
- 客户端走 iSCSI 跟 Engine 通信
- 管理面 UI —— web 界面看 volume / replica / snapshot
优劣
✅ 好处:
- 极易安装:
helm install longhorn一行 - 漂亮 UI、健康可视
- K8s 原生 snapshot / clone / backup
- 不需要专门盘(用节点 filesystem 上的文件作 storage)
❌ 限制:
- 只块存储(RWO,不支持 RWX)
- 性能不如裸盘(多了 iSCSI 一跳)
- 不适合 100+ 节点 / 100TB+ 规模
适合场景
- 小到中型集群(< 50 节点)
- VM 替代品(替代 vSphere VSAN 类)
- 需要 snapshot / clone 但不要 Ceph 复杂度
- 数据库 / StatefulSet 用 RWO 块存储
6. OpenEBS —— 多引擎
OpenEBS 是个框架——支持多种存储引擎、各引擎特点不同:
| 引擎 | 适合 |
|---|---|
| Local PV | 本地盘、零开销 |
| cStor | 块存储、多副本(类似 Longhorn) |
| Jiva | 老引擎、轻量 |
| Mayastor | NVMe-oF + SPDK、超高性能(生产推荐) |
| ZFS Local PV | 基于 ZFS 的本地 PV(snapshot / 压缩) |
# 装 OpenEBS
helm install openebs openebs/openebs --namespace openebs --create-namespace
Mayastor —— NVMe-oF
graph LR
Pod[Pod] -->|NVMe-oF| Mayastor[Mayastor Engine]
Mayastor -->|本地 NVMe| Disk1[本地 NVMe SSD]
Mayastor -->|网络 NVMe| Disk2[远程 NVMe]
style Mayastor fill:#fff4e1
Mayastor 用 SPDK(Storage Performance Dev Kit)+ NVMe-oF(NVMe over Fabrics)协议——接近裸盘性能。
适合:
- 数据库 / 高 IOPS 应用
- 有 NVMe SSD 的节点
- 性能比简洁 / 通用更重要
7. MinIO —— 自建 S3
K8s 上跑个对象存储最简方案。
# minio-tenant.yaml (用 MinIO Operator)
apiVersion: minio.min.io/v2
kind: Tenant
metadata:
name: my-minio
spec:
pools:
- servers: 4 # 4 节点
volumesPerServer: 4 # 每节点 4 盘
size: 100Gi
...
何时用 MinIO
- 不想用云对象存储(成本 / 数据不出 K8s)
- S3 兼容 API —— 应用代码不用改
- 大量大对象(备份 / 图片 / 视频 / 训练数据)
- 跨集群 / 跨云数据共享
不适合:
- 小文件(对象存储不擅长)
- 数据库(用块)
- 配置 / Secret(用 ConfigMap / Secret)
8. K8s 用分布式存储的模式
云厂商 LBS / NAS / OSS
↓ CSI driver
K8s
↓ StorageClass
PVC / 应用
最省心——AWS EBS / EFS / S3、阿里 ESSD / NAS / OSS。 不需要自己运维存储集群。
集群内部部署 Ceph
↓ Rook Operator 管理
K8s 提供 RBD / CephFS / S3
大集群 + 自建机房典型方案。资源开销大、运维复杂、但功能全。
集群内部装 Longhorn
↓ 块存储 (RWO)
StatefulSet / 数据库
100 节点以下集群简单可靠方案。
节点 NVMe SSD
↓ Mayastor / SPDK
K8s 块存储
性能极致——数据库 / AI 训练 / 高 IOPS 场景。
节点本地盘 (Local PV)
↓ K8s 调度
数据库 (MySQL / PG 自带复制)
最朴素但极有效——让数据库自己做高可用(master/slave / 多主),存储用最快的本地盘。
适合:单库性能要求高、不在乎"K8s storage 标准化"。
9. 生产部署的"血泪经验"
经验 1:不要自建 Ceph、除非有专门团队
Ceph 自建需要:
- 至少 2 个全职 SRE
- 6 个月学习 + 试错周期
- 紧急联系厂商 / 社区支持的渠道
- 严格的 capacity planning
没这些就用云上 / Longhorn / 委托厂商。
经验 2:升级前完整快照+演练
Ceph / Longhorn / OpenEBS 升级风险高。永远在测试集群演练 + 生产前做快照。
K8s 1.27+ 的 VolumeSnapshot 标准化了——所有现代 CSI driver 都支持。
经验 3:监控 capacity 永远要监控
# Ceph
ceph df
ceph health
ceph osd df
# Longhorn
kubectl get volumes -n longhorn-system
# 通用
df -h # 节点级
kubectl get pvc -A # 所有 PVC
加 Prometheus alert:
# 80% 就告警
(kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) > 0.8
# Ceph 集群剩余空间
ceph_cluster_used_bytes / ceph_cluster_capacity_bytes > 0.7
经验 4:副本必须放不同故障域
# Ceph CRUSH map
crushtool -d /tmp/crush -o /tmp/crush.txt
# 确保 rule 是 rack / host 级 replication
- 副本数 = 3
- 故障域 = 节点 at minimum
- 故障域 = rack / AZ 理想
否则:节点挂 = N 个副本同时失效 = 数据丢。
经验 5:网络比磁盘更可能挂
存储集群 依赖网络 —— 节点间复制 / 心跳。专用网络(万兆 / 25G)+ 双链路。
K8s 节点间 1G 网络 → 跑 Ceph 备份 / rebalance 时业务流量被淹。
经验 6:snapshot 不是 backup
快照 = 同集群里、底层共用 chunk
备份 = 跨集群 / 跨地理位置、完全独立的副本
集群整个挂 → 快照也没了。
真备份用 Velero 跨集群 / 跨云。详见 velero.md。
经验 7:不要"all-in-one"——K8s 节点 + 存储节点分离
✗ K8s worker 节点同时跑业务 + 跑 Ceph OSD
✓ K8s worker 节点跑业务、独立的存储节点(裸金属或 Rook 专用节点池)跑 Ceph
业务突发负载会拖累存储;存储 rebalance 会拖累业务。物理隔离或至少节点池隔离。
10. 反面教材
反面 1:用 GlusterFS 在新集群
GlusterFS 社区维护减弱(Red Hat 撤资)、bug 修复慢、稳定性下降。新集群不要用 Gluster。
迁移:用 Ceph / Longhorn 替代。
反面 2:把 Ceph cluster_network 和 public_network 合一
ceph.conf:
cluster_network: 10.0.0.0/24
public_network: 10.0.0.0/24 # ← 同网段!
cluster_network 是 OSD 之间复制 / rebalance、流量极大。 public_network 是客户端访问。
合一 → rebalance 时把客户端流量打挂。
生产分离两个网络:
cluster_network: 10.0.1.0/24 # 内部专用
public_network: 10.0.2.0/24 # 客户端
反面 3:Longhorn 默认副本数 3 装在 2 节点集群
defaultDataPath: /var/lib/longhorn
numberOfReplicas: 3 # ← 但只有 2 节点
2 节点跑不出 3 副本(K8s 默认不允许同节点放多副本)。volume 状态 Degraded。
修:
numberOfReplicas: 2 # 跟节点数匹配
或者加节点。
反面 4:用 K8s default storageClass 是 RWO 然后期望共享
$ kubectl get storageclass
NAME PROVISIONER ... IS-DEFAULT
fast-ssd ebs.csi.aws.com ... yes ← default
accessMode: RWO
应用 yaml 没写 accessMode → 默认 RWO → 多副本 deployment 起不来。
修:要 RWX 显式声明:
spec:
accessModes: [ReadWriteMany]
storageClassName: efs-sc # ← 用 RWX 的 SC(NFS / EFS / CephFS)
反面 5:MinIO 用单副本(distributed=false)
spec:
pools:
- servers: 1 # 单节点
= 单点。盘挂 = 数据丢。
生产 MinIO 至少 4 节点(EC k=2,m=2)。
11. 选型决策图
flowchart TD
Start[需要存储] --> Q1{云上 / 自建?}
Q1 -->|云上| Q2{要不要 RWX?}
Q2 -->|RWO 够| C1["云盘 (EBS / SSD)"]
Q2 -->|RWX| C2["云 NAS (EFS / NAS)"]
Q2 -->|大对象| C3["云 OSS (S3 / OSS)"]
Q1 -->|自建| Q3{规模?}
Q3 -->|小 < 50 节点| L1[Longhorn]
Q3 -->|中 < 200 节点| Q4{有专门团队?}
Q4 -->|是| C4[Rook+Ceph]
Q4 -->|否| L2[Longhorn 或者 NFS]
Q3 -->|大 200+ 节点| C5[Rook+Ceph 或 商业方案]
Q3 -->|要极致性能| M1[Mayastor / OpenEBS]
Q3 -->|要对象存储| MI[MinIO]
12. 下一步
| 篇 | 内容 |
|---|---|
| 00-storage-mental-model.md | 心智模型 |
| 01-container-volumes.md | 容器挂载 |
| 02-k8s-volumes.md | K8s Volume 大全 |
| 03-pv-pvc-storageclass.md | PV / PVC / CSI |
| 04-nfs-deep.md | NFS |
| 本篇 | 分布式存储概览 |
| 06-storage-troubleshooting.md | 故障 runbook |
深入学习资源
分布式存储自身就是个大领域。强烈推荐:
- Ceph 官方文档 docs.ceph.com
- Longhorn 文档 longhorn.io/docs
- OpenEBS 文档 openebs.io/docs
- 书:《Designing Data-Intensive Applications》(Kleppmann)—— 分布式存储基础