10.9 存储选型

一句话

选型不是选 “最快” 或 “最便宜”,而是按四问落到某一层:数据形态(块/文件/对象)× 访问模式(随机/顺序、读写比)× 一致性(谁能看到谁)× 规模(GB 还是 PB);绝大多数生产系统最终是 “块 + 对象” 两层,文件层只在需要共享目录时出现。

四问决策

问 答案 → 选择
要原地随机写吗?要 fsync 吗? 要 → 块(数据库、WAL、系统盘)
多台机器要共享同一批目录吗? 要 → 文件(NFS/SMB),但要接受元数据瓶颈
一次写、多次读,按 URL 取? 是 → 对象(图片、备份、数据湖)
规模是 PB 级、增长不可预测? 是 → 对象(扁平命名空间,近乎无限扩展)

量级对比(用于排除,不用于精算)

维度 块 文件 对象
延迟 0.1–1ms 0.5–5ms 10–100ms
IOPS 万–百万 千–万(元数据受限) 低(按请求)
单位成本 高 中 最低
共享 单机 多机 天然 HTTP
扩展上限 单卷容量 元数据节点 近乎无限

分层:热、温、冷

层 介质 典型数据 策略
热 本地 NVMe / 云盘 数据库、索引 高 IOPS、低延迟
温 文件存储 / 标准对象 上传文件、日志近期 生命周期 30–90 天
冷 归档对象 / 磁带 备份、合规留存 取回有延迟,成本最低

分层的判据是 “访问频率 × 延迟要求”,不是 “数据重要程度”。重要但不常读的数据,应该待在冷层 + 独立备份。

对象存储的内部结构(元数据/数据分离、EC)见 10.8 对象存储系统设计。

判据表:三问定层

你的情况 结论
需要 fsync / 随机写 / 事务 块(本地盘或云盘),不要跨网络
多机共享目录、需要 rename/flock 文件(NFS),并接受元数据瓶颈
一次写多次读、按 URL 取、PB 级 对象 + CDN
冷数据、合规留存 7 年 归档对象 + 独立备份
# 先量 “真实访问模式”,再谈选型(Linux 上)
iostat -x 1 5 | tail -5          # 看 r/s、w/s、await、%util
df -h /data; du -sh /data/* | sort -h | tail -5

反模式

反模式 后果
用 “最快” 的块存储存所有东西 成本 3–10 倍,且没换来收益
用对象存储跑数据库 无随机写/fsync,事务不可用
文件存储存海量小文件 元数据操作打满
不做生命周期 冷数据一直按热数据计费(见 5.6 云成本结构)
只选一种存储 所有场景都妥协,成本与性能双输
只看单价不看请求/取回费用 账单超预期,小文件场景尤甚

三条铁律

🔑 先按访问语义排除,再按成本择优;语义不匹配的存储,性能再好也用不了。

🔑 分层看访问频率,不看数据 “重要性”。

🔑 备份与存储是两件事:同一种介质上的两份拷贝,不叫备份(见 10.4 快照与备份)。

自检

Q1 一个图片社区要存 500TB 用户上传,怎么选?

▸ 答案:对象存储 + CDN。理由:一次写多次读、按 URL 取、规模大且增长快、成本敏感。需要 “缩略图/裁剪” 时在写入时生成派生对象,而不是运行时改原图。访问热点用 CDN 挡住,对象层的请求费与延迟都能降下来(见 9.1 边缘缓存原理)。

Q2 为什么数据库不选文件存储(NFS)?

▸ 答案:因为数据库依赖严格的 POSIX 语义(fsync、文件锁、rename 原子性),而 NFS 的缓存与锁是弱语义,多客户端下可能出现 “以为落盘实际没有”,崩溃恢复即损坏。数据库要么用块设备,要么用支持 POSIX 的本地文件系统。

Q3 分层存储里最容易被忽略的成本是什么?

▸ 答案:取回成本与请求费。归档层单价很低,但取回有延迟与按 GB 的取回费;对象存储的 GET/LIST 也按请求计费。很多团队把日志放冷层省了容量费,却因为频繁回捞把请求费花超(见 5.6 云成本结构)。

Q4 “数据很重要,所以放最贵的存储” 错在哪?

▸ 答案:错在把 重要性 与 访问频率/延迟要求 混为一谈。重要性应该体现为 “多副本 + 独立备份 + 权限与审计”,而不是 “放在最快的介质上”。一份一年读一次的合规数据,放在归档层 + 异地备份,比放在 NVMe 上更安全也更便宜。

Q5 什么时候值得上分布式文件系统(自建/托管)?

▸ 答案:需要多机共享目录 + POSIX 语义,且规模超过单机 NFS 的能力时(如渲染农场、HPC、AI 训练读取海量小文件)。代价是运维复杂度与元数据瓶颈。若只是 “共享上传目录”,NFS 或对象存储 + 应用层适配更简单(见 10.5 分布式文件系统 (GFS / HDFS 架构))。

Q6 为什么 “先把数据放对象存储,以后需要再迁到块” 通常不划算?

▸ 答案:因为迁移要全量搬运(时间 + 出口流量费),且应用要改访问方式(文件语义 → HTTP API)。更常见的路径是反过来:热数据在块/文件上跑,冷数据生命周期下沉到对象存储,方向与访问频率一致。

关联