云原生存储别乱选:Object、Block、File 到底谁更适合你?
很多团队上云以后,都会遇到一个看起来特别简单、实际上很容易踩坑的问题:
“我们的数据到底该放对象存储、块存储,还是文件存储?”
刚开始的时候,很多人的判断方式非常直接:
业务文件?Object Storage。
数据库?Block Storage。
共享目录?File Storage。
乍一看,好像已经总结完了。
但真正到了生产环境,你会发现事情没这么简单。
为什么同样是“存数据”,对象存储便宜得离谱,数据库却不能直接往里面写?
为什么 Kubernetes 里面挂一个 PVC,看起来都是磁盘,背后却可能是完全不同的存储系统?
为什么有些系统用了共享文件存储以后,开发人员天天抱怨“怎么这么慢”?
说到底,不是 Object、Block、File 谁更高级,而是:
不同的数据,天然就应该用不同的存储方式。
存储选型这件事,本质上不是“哪个性能最高”,而是成本、性能、一致性、扩展性和使用方式之间的权衡。
今天咱们就把这三个家伙掰开揉碎聊一遍。
一、先别急着选,先搞明白三种存储到底是什么
可以把它们想象成三个不同的仓库。
1. Object:像一个超大的快递仓库
对象存储最典型的特点,就是:
数据 + 元数据 + 唯一 Key
组成一个完整对象。
比如:
bucket:
images/
user001/avatar.png
user002/avatar.png
videos/
2026/
demo01.mp4
你不需要关心“这个文件到底放在哪块磁盘”。
你只需要告诉存储系统:
put_object(
bucket="images",
key="user001/avatar.png",
data=file
)
以后再通过 Key 把它取出来:
get_object(
bucket="images",
key="user001/avatar.png"
)
它最大的优势就是:
扩展简单、容量巨大、成本低。
所以特别适合:
图片、视频、备份、日志、模型文件、安装包、归档数据、数据湖等。
例如你的 AI 系统里可能有:
model/
├── llama-8b/
├── embedding/
├── reranker/
└── checkpoints/
这种数据放 Object Storage,通常比拿高性能块存储硬扛更划算。
二、Block:像给服务器插了一块“硬盘”
块存储就比较容易理解了。
对操作系统来说,它基本就是一块磁盘。
例如:
lsblk
可能看到:
sda
├─sda1
└─sda2
sdb
然后你可以:
mkfs.ext4 /dev/sdb
mount /dev/sdb /data
对于应用来说,它根本不需要知道后面是什么云盘、SAN、分布式存储。
它只觉得:
“这是我的磁盘。”
所以数据库特别喜欢它。
比如 MySQL:
/data/mysql/
├── ibdata1
├── ib_logfile0
├── ib_logfile1
└── mydb/
数据库自己控制:
- Page
- WAL
- Buffer Pool
- fsync
- 随机读写
- 顺序读写
这种场景,Block Storage 就非常合适。
因为数据库最怕的不是“容量不够”,而是:
IOPS 不稳定、延迟太高、fsync 不靠谱。
三、File:像公司里的共享网络盘
文件存储最大的特点,就是:
多个机器可以同时看到一个目录。
例如:
/data/share
服务器 A:
touch /data/share/a.txt
服务器 B:
ls /data/share
马上就能看到:
a.txt
这就是 File Storage 的价值。
典型协议包括:
NFS
SMB
Kubernetes 里也经常会看到这种模式:
apiVersion: v1
kind: PersistentVolume
metadata:
name: shared-pv
spec:
accessModes:
- ReadWriteMany
nfs:
server: 10.0.0.10
path: /data/share
然后多个 Pod 可以一起挂:
Pod A ─┐
Pod B ─┼──> NFS
Pod C ─┘
这对于共享配置、共享素材、传统应用迁移特别方便。
但问题也很明显:
共享方便,性能和一致性就需要付出代价。
四、真正难选的地方来了:性能不是唯一标准
很多人做存储选型,第一反应就是:
“哪个性能最高?”
其实这是一个很容易掉坑里的问题。
因为存储不是跑分游戏。
真正应该看的是:
业务访问模式
↓
数据规模
↓
读写方式
↓
一致性要求
↓
共享要求
↓
性能要求
↓
最终成本
比如:
一个 10MB 的图片,偶尔下载一次。
和:
一个数据库每秒进行几万次随机 IO。
虽然都是“存文件”,但完全是两码事。
五、一个简单粗暴的判断方法
我自己比较推荐一个特别接地气的判断方式。
先问自己三个问题。
第一个问题:需要像磁盘一样直接使用吗?
需要。
优先考虑:
Block Storage
例如:
MySQL
PostgreSQL
Redis
Elasticsearch
这些系统通常希望直接控制底层块设备。
第二个问题:是不是很多机器都要访问同一个目录?
是。
优先考虑:
File Storage
比如:
共享文件
用户上传目录
传统应用文件目录
CI/CD 工作空间
多个 Pod 共享数据
第三个问题:是不是大量非结构化数据?
是。
优先考虑:
Object Storage
例如:
图片
视频
日志
备份
AI 模型
数据集
历史归档
这个思路虽然简单,但在实际项目里面非常好用。
六、Kubernetes 里面,这三个存储更容易把人绕晕
Kubernetes 里经常出现:
PV
PVC
StorageClass
CSI
刚接触的时候特别容易产生一个错觉:
“PVC 不就是一块硬盘吗?”
其实不是。
PVC 只是告诉 Kubernetes:
“我想要一份什么样的存储。”
例如:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
背后真正提供存储的,可能是:
云块存储
Ceph RBD
NFS
分布式文件系统
其他 CSI Storage
所以你看到:
PVC = 100Gi
并不代表:
PVC = 某一块真实硬盘
这里千万别搞混。
七、Object Storage 看起来便宜,但千万别拿它当万能硬盘
对象存储最大的诱惑就是:
便宜,而且容量几乎可以无限扩。
于是就有人想:
“既然这么便宜,我所有东西都放 Object Storage 不就行了?”
然后开始踩坑。
比如某个应用原来这样:
with open("/data/test.json", "r") as f:
data = json.load(f)
然后有人想迁移:
/data/test.json
直接变成:
Object Storage
结果代码改成:
data = client.get_object(
Bucket="data",
Key="test.json"
)
这时候问题马上来了。
传统文件系统有:
open
read
write
seek
rename
mkdir
lock
而对象存储的核心思维其实是:
PUT Object
GET Object
DELETE Object
LIST Object
两者的模型根本不一样。
所以:
Object Storage 不是“更大的硬盘”,它是完全不同的数据访问模型。
这一点特别重要。
八、反过来,把数据库塞进对象存储,也一样难受
比如:
MySQL
PostgreSQL
MongoDB
这类系统非常依赖:
随机 IO
低延迟
fsync
WAL
局部更新
高频读写
假设数据库一个 Page 只有几 KB。
如果每次小修改都搞成:
下载对象
修改
重新上传整个对象
这是什么感觉?
基本等于:
拿快递仓库当内存条用。
理论上可以折腾,实际上会非常难受。
所以数据库、缓存、搜索引擎这种系统,通常更适合使用高性能 Block Storage,或者使用其自身面向对象/分布式存储的专用架构。
九、File Storage 最大的坑:共享不等于高性能
File Storage 特别适合:
ReadWriteMany
也就是:
多个 Pod
↓
共享目录
看起来非常舒服。
但是假设 100 个 Pod 同时:
打开文件
写文件
刷新
关闭
后端又只有一个共享文件系统。
这时候性能瓶颈就可能出现。
特别是大量小文件场景。
例如:
/opt/data/
├── 000001.json
├── 000002.json
├── 000003.json
├── ...
└── 500000.json
看着没多少数据,但是 metadata 操作可能非常多。
所以实际项目里经常会出现一种情况:
容量一点问题没有,IO 延迟却已经爆了。
这就是为什么做存储选型的时候:
不要只盯着 TB,要看 IOPS、吞吐、延迟和访问模式。
十、真正生产环境,往往不是三选一,而是“三个一起用”
这是我特别想强调的一点。
很多成熟系统根本不会说:
“我们公司统一使用 Object Storage。”
或者:
“全部用 Block Storage。”
更加合理的方式其实是:
┌──────────────┐
│ Kubernetes │
└──────┬───────┘
│
┌──────────────┼───────────────┐
↓ ↓ ↓
Block File Object
│ │ │
数据库 共享目录 图片/视频
Redis 用户文件 日志
ES 配置共享 模型
备份
比如一个 AI 平台。
你可能这样设计:
MySQL
↓
Block Storage
模型服务临时缓存
↓
Block Storage
多个推理 Pod 共享配置
↓
File Storage
模型权重
↓
Object Storage
训练数据集
↓
Object Storage
训练日志
↓
Object Storage
这才是比较合理的组合。
十一、别忘了成本:性能不是免费的
这可能是很多技术人员最容易忽略的一件事情。
假设三种存储:
Object:便宜
File:中等
Block:昂贵
当然,实际价格会因云厂商、规格、区域以及性能等级不同而变化。
但总体来说:
越接近传统磁盘语义、越强调低延迟和高 IOPS,成本通常越高。
所以千万不要:
所有数据
↓
最高规格 SSD
↓
“性能好就完事了”
这种架构上线以后,账单可能比技术债还先找上门。
特别是:
日志
历史文件
备份
模型
大数据集
归档数据
这些东西如果全部放高性能 Block Storage,很多时候属于:
用跑车运砖头。
十二、我更推荐一个“冷热分层”的思路
比如:
数据
│
┌────────┴────────┐
↓ ↓
热数据 冷数据
│ │
Block/File Object
│ │
高频访问 低频访问
低延迟 低成本
再进一步,可以搞成:
SSD Block
↓
File Storage
↓
Object Storage
↓
Archive
真正需要高性能的数据才放在第一层。
不常用的数据不断往后迁。
这样做最大的好处不是“技术先进”,而是:
成本终于能控制住。
十三、最后送大家一张非常实用的选择表
| 场景 | 推荐存储 |
|---|---|
| MySQL / PostgreSQL | Block |
| Redis 持久化 | Block |
| Elasticsearch | Block |
| 用户上传图片 | Object |
| 视频 | Object |
| 日志归档 | Object |
| 数据湖 | Object |
| 模型文件 | Object |
| 多 Pod 共享目录 | File |
| NFS 共享文件 | File |
| 传统应用文件系统 | File |
| 高并发随机 IO | Block |
| 大文件顺序读写 | Object / Block |
| 大量历史数据 | Object |
当然,这张表不是“绝对真理”。
真正选型还是得结合:
访问频率
访问方式
读写比例
IOPS
吞吐
延迟
一致性
共享需求
数据生命周期
成本
来判断。
写在最后
做云原生这么久,我越来越觉得一个事情特别有意思:
很多所谓的“架构问题”,最后其实都是“选择问题”。
Object、Block、File 没有谁能“一统天下”。
Object Storage 擅长的是:
海量、便宜、非结构化数据。
Block Storage 擅长的是:
低延迟、高 IOPS、像磁盘一样使用。
File Storage 擅长的是:
多节点共享访问。
真正成熟的架构,不是非要选出一个“最牛”的存储。
而是:
让不同的数据,住进最适合自己的房子。
数据库没必要住进对象仓库。
几 TB 的历史日志,也没必要天天占着高性能 SSD。
多个 Pod 需要共享目录的时候,也别非得让每个 Pod 都自己背一块磁盘。
说到底,云原生存储选型就一句大白话:
该省钱的时候别烧钱,该要性能的时候别抠门,该共享的时候别硬搞单机。
技术架构真正的高级感,往往不是用了多少新技术,而是:
知道什么时候该用什么技术,而且知道为什么。
—— Echo_Wish