文件存储系统设计 (S3/网盘)

一、需求分析

设计一个类似 Amazon S3 的对象存储服务,支持:

  • 海量存储:存储 350 万亿对象、EB 级数据
  • 高持久性:11 个 9(99.999999999%)的持久性保证
  • 高可用性:99.99% 以上的可用性
  • 低延迟:读写延迟控制在毫秒到百毫秒级
  • 强一致性:写入后立即可读

二、核心数据模型

对象存储与文件系统有本质区别。对象存储是扁平的键值模型(Bucket + Key → Object),而非层次化的目录树。

概念 说明
Bucket 命名空间容器,全局唯一名称
Object Key 对象在 Bucket 内的唯一标识,如 photos/2024/vacation.jpg
Object Data 对象本身的二进制数据
Metadata 键值对形式的元数据,如 Content-Type、自定义标签
Version ID 启用版本控制后,每次更新生成新版本号

三、系统架构

1
2
3
4
5
6
7
8
9
10
11
用户请求

[负载均衡器]

[API 网关] ← 鉴权、限流、路由

[元数据服务] ← MySQL/TiDB 存储对象元数据

[存储节点集群] ← 对象数据分片存储

[容错层] ← 副本/纠删码

3.1 元数据服务

对象元数据(key、大小、ETag、存储位置)存储在分布式数据库中。元数据服务的核心挑战:单表可能达到千亿行级别,需要精心设计分片策略。

分片方案:按 Bucket + Key 前缀水平分片。

1
2
3
Shard-0: bucket-a/photos/ bucket-a/videos/
Shard-1: bucket-a/videos/ bucket-b/
Shard-2: bucket-b/ bucket-z/

查询优化

  • GetObject(key) → 单行查询,直接走主键索引
  • ListObjects(prefix) → 前缀扫描,利用键的字典序排列

3.2 数据存储服务

对象数据存储在分布式文件系统或裸盘上。每个对象被分割为固定大小的 chunk(如 64MB),分散存储在不同节点上。

关键设计决策:

  • 不需要目录树结构 → 简化了一致性模型
  • 每个 chunk 有多个副本(通常是 3 副本,分布在不同机架/机房)
  • 小对象(< 1MB)可以合并在同一个 chunk 中以减少元数据开销

四、持久性与容错

4.1 11个9的持久性如何保证

层次 措施 目标
副本 3 副本写入(跨机架、跨数据中心) 单盘/单机故障不影响数据
校验 每 chunk 附带 CRC32/MD5 校验和,读取时验证 检测静默数据损坏
自愈 后台进程定期扫描副本完整性,发现缺失自动补充 自动化运维
版本控制 启用后保留所有历史版本,防止误删/误改 应用层容错
跨区域复制 异步复制到另一个区域(如 S3 CRR) 灾难恢复

4.2 纠删码 vs 多副本

方案 存储开销 容错能力 计算开销
3 副本 3x 同时丢失 2 节点
Reed-Solomon(6,3) 1.5x 任意 3 个块丢失可恢复 编解码开销

大对象更适合用纠删码(节省存储成本),小对象用多副本(避免编解码延迟)。

4.3 写入一致性

为保证”写入后立即可读”,对象存储通常采用 Quorum 机制

  • 写入:需要 W 个节点确认后才返回成功
  • 读取:需要 R 个节点确认后返回数据
  • 当 W + R > N 时,保证强一致性

五、大文件分块上传

5.1 为什么需要分块

  • 可靠性:上传 10GB 文件,中途失败不需要重传全部
  • 并行性:多个分块可以并行上传到不同存储节点
  • 断点续传:记录已上传的分块,恢复时只需上传剩余部分

5.2 分块上传流程

1
2
3
4
5
1. Initiate Multipart Upload → 返回 Upload ID
2. Upload Part (part-1) → 返回 ETag-1
3. Upload Part (part-2) → 返回 ETag-2
... (可并行)
N. Complete Multipart Upload → 服务端合并分块

服务端只需要记录 (Upload ID, Part Number, ETag) 的映射关系,合并时按 Part Number 排序拼接即可,不需要实际的物理合并。

六、访问控制

对象存储的访问控制通常支持三层:

层次 机制 示例
IAM 策略 绑定到用户/角色的权限策略 “允许对 Bucket-A 的读操作”
Bucket 策略 绑定到 Bucket 的访问规则 “允许来自特定 VPC 的请求”
预签名 URL 临时授权的下载/上传链接 生成有效期 1 小时的下载链接

预签名 URL 的原理:

1
2
3
URL = https://bucket.s3.com/object?Signature={HMAC-SHA256(SecretKey, StringToSign)}&Expires={timestamp}

StringToSign = HTTP-Verb + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Expires + "\n" + CanonicalizedResource

七、容量估算

假设 1000 万个用户,人均存储 50GB:

  • 总存储需求:1000万 × 50GB = 500PB
  • 3 副本开销:500PB × 3 = 1.5EB

元数据估算:每个对象 64 字节元数据,千亿对象 → 6.4TB 元数据(可全部放在内存中)。

八、小结

对象存储的核心设计原则是扁平命名空间 + 分块存储 + 多副本容错。相比传统的 POSIX 文件系统,它牺牲了目录层级和原地修改的能力,换来了近乎无限的扩展性和极高的持久性。Amazon S3、Google Cloud Storage、阿里云 OSS 等主流对象存储服务都遵循这一架构范式。