对象存储是半个互联网背后默默干活的主力:每一张上传的照片、视频、备份和静态资源,几乎都躺在像 Amazon S3、Google Cloud Storage 或 Azure Blob 这样的对象存储里。它就是我们 Google DrivePastebin 设计里用来卸载字节的那个持久、近乎无限的"桶"。它与数据库或文件系统的不同,在于一组刻意的约束——扁平命名空间不可变对象HTTP API——用便利换来近乎无限的扩展性和持久性。

⚡ 速览要点
  • 是对象,不是文件或块——每个对象 = 一坨字节 + 一个 key + 元数据,存在扁平命名空间里(没有真正的目录),通过 HTTP 访问。
  • 为持久性而生——靠跨可用区复制和纠删码做到约 11 个 9;把"绝不丢这个数据"交给存储层。
  • 近乎无限 + 便宜——可扩展到 EB 级,无需容量规划;按存储量和请求数付费。
  • 对象不可变——你替换整个对象,而不是原地编辑;没有便宜的"重命名"或"追加"。
  • 大文件用分段上传(multipart);客户端通过预签名 URL 直传,字节不经过你的应用服务器。
  • 存储分级 / 生命周期把数据从热到归档逐级下沉以省钱;搭配 CDN 做全球快速读取。
tldr

对象存储把不可变的字节块按 key 存在扁平命名空间里,通过 HTTP API 暴露。它用纠删码加跨可用区复制做到约 11 个 9 的持久性,无需预置就能扩到 EB 级,而且便宜。大文件用分段上传,字节通过预签名 URL 直传。它不是文件系统(无重命名、无原地编辑、列举要分页且不免费),也不是数据库(不能查询)——它就是你往里放字节、再用 CDN 兜在前面的那个持久的桶。

对象 vs 块 vs 文件存储

存储有三种范式,选对象存储意味着你是有意接受它的模型:

方面对象(S3)块(EBS)文件(NFS)
基本单位对象(字节 + 元数据)定长的块目录里的文件
访问方式按 key 走 HTTP API挂载为磁盘挂载、POSIX 路径
修改替换整个对象可改任意块原地编辑
扩展近乎无限单卷有上限受服务器限制
最适合字节块:媒体、备份、资源数据库、操作系统盘共享的应用文件

块存储是裸磁盘(适合数据库的文件);文件存储是可挂载的共享层级(适合老应用)。对象存储放弃了原地编辑和真正的目录树,换来无限扩展和简单的网络 API——非常适合写一次、读多次的字节块。

对象的构成与扁平命名空间

一个对象是三样东西:数据(字节)、唯一的 key(它在桶内的名字)和元数据(内容类型、大小、自定义标签)。关键在于命名空间是扁平的——没有真正的文件夹。像 2023/09/photo.jpg 这样的 key 看着是层级,但斜杠只是 key 里的字符;"文件夹"是按公共前缀列举 key 时由界面制造出来的便利。正是这种扁平让系统能扩展:没有目录树要遍历或加锁,只有一张巨大的分布式 key→字节块的映射。

HTTP API

你用普通的 HTTP 动词对一个 key 操作:

对象存储 API
PUT    /my-bucket/2023/09/photo.jpg     # 上传(已存在则替换)
GET    /my-bucket/2023/09/photo.jpg     # 下载
DELETE /my-bucket/2023/09/photo.jpg     # 删除
GET    /my-bucket?prefix=2023/09/       # 按前缀列举 key(分页)

# 大文件:分段上传(并行、可断点续传)
initiate → upload part 1..N (并行) → complete

两个模式在大规模下很关键。分段上传把大对象切成多个分片并行上传、服务端再拼起来——对几个 GB 的大文件可断点续传、又快。预签名 URL 是有时限的签名链接,让客户端直接对存储 PUT/GET 某对象,而不必让字节经过你的应用服务器——这对把大流量挡在后端之外至关重要(正是 Drive 设计搬运分块的方式)。

靠复制和纠删码做持久性

招牌特性就是持久性——厂商宣称约 11 个 9(99.999999999%),意思是丢一个对象的概率小到可以忽略。靠两个技术达成。复制把副本存到多个可用区(物理隔离的数据中心),所以一个机房着火或被淹不会丢数据。纠删码比整份复制更聪明也更省:它把对象切成 k 个数据分片加 m 个校验分片,只要拿到 k+m 中任意 k 个就能重建对象。比如 10 数据 + 4 校验,可容忍丢任意 4 个分片,而存储开销只有 1.4 倍,而非三副本的 3 倍。

纠删码:不用 3 倍成本也能持久
对象 → 切成 k=10 数据 + m=4 校验 = 14 个分片
       分散到 14 块盘 / 可用区

  从任意 10/14 重建   → 可容忍丢最多 4 个
  存储开销 = 14/10 = 1.4 倍   (对比三副本的 3 倍)

一致性模型

历史上 S3 的某些操作是最终一致的——刚写入的对象在读时可能短暂 404。现代对象存储现在提供强一致的写后读(read-after-write):一旦 PUT 成功,随后的 GET 就返回新数据。这对"写完立刻读"的流水线很重要。不过列举(listing)可能仍略有延迟,而且没有跨对象事务——每个对象操作各自独立、各自原子。

存储分级与生命周期

不是所有数据访问频率都一样,所以对象存储提供不同价格/延迟点的存储类别,以及自动在其间迁移的生命周期规则:

类别用途取舍
标准(热)频繁访问存储最贵,即时访问
低频访问每月访问存储更便宜,取回收费
归档(冷)备份、合规非常便宜,恢复要数分钟到数小时

一条生命周期策略可能让对象在标准类待 30 天,转到低频访问,一年后再转归档,最后过期删除——全自动,大幅降低老数据的成本。

扩展与性能

因为命名空间是扁平的,存储把 key 空间分区,几乎线性扩展——没有目录树成为瓶颈。历史上性能与 key 的前缀相关(存储按前缀分区,所以很多 key 共享一个前缀会形成热点),这也是过去建议把前缀随机化的原因;现代 S3 会自动扩展前缀,但在极端吞吐下把负载分散到多个 key 仍有帮助。对读多的公开内容,你在前面放一个 CDN,大多数读从边缘返回、根本不打到源桶。

用来干什么

常见坑

总结

对象存储用文件系统的便利(重命名、原地编辑、廉价列举)和数据库的能力(查询)换来三个超能力:靠扁平命名空间无限扩展、靠纠删码加跨可用区复制做到约 11 个 9 的持久性、以及极简的 HTTP API。用它存不可变的字节块,用预签名 URL + 分段上传直接搬运字节,用生命周期规则分级,再用 CDN 兜在前面。

🎯 面试速答

对象 vs 块 vs 文件?对象 = 按 key 走 HTTP 的字节块、扁平命名空间、无限(S3);块 = 给数据库用的裸磁盘(EBS);文件 = 可挂载的 POSIX 层级(NFS)。
11 个 9 怎么来的?跨可用区复制加纠删码(k 数据 + m 校验,任意 k 个即可重建)——比三副本便宜得多的持久性。
为什么用预签名 URL 和分段上传?客户端直接对存储上传/下载(字节不碰你的服务器);分段把大上传并行化并支持断点续传。
它是文件系统吗?不是——扁平命名空间、不可变对象、没有便宜的重命名、列举要分页且不免费。"文件夹"只是 key 前缀。
为什么前面要放 CDN?读取是批量且可缓存的;边缘服务热门内容,源桶不被打爆。

← 上一篇
Redis