文件存储与对象存储
原始素材:
4-服务器与后端/4.17-file-storage.md
前言
用户上传了一张头像,你把它存在服务器的/uploads 目录下——然后服务器磁盘满了,或者你加了第二台服务器,用户发现头像时有时无。 文件存储看似简单,但在分布式环境下却是一个需要认真对待的架构问题。对象存储就是互联网时代解决这个问题的标准答案。
这篇文章会带你学什么?
学完这章后,你将获得:
- 存储类型认知 :理解块存储、文件存储、对象存储的区别和适用场景
- 对象存储核心概念 :掌握 Bucket、Object、Key、Pre-signed URL 等核心概念
- 上传方案设计 :学会客户端直传 vs 服务端中转的方案选型
- CDN 加速原理 :理解 CDN 如何加速静态资源的全球分发
- 最佳实践 :掌握文件命名、权限控制、生命周期管理等实战技巧
| 章节 | 内容 | 核心概念 |
|---|---|---|
| 第 1 章 | 存储类型对比 | 块存储、文件存储、对象存储 |
| 第 2 章 | 对象存储核心概念 | Bucket、Object、Key、元数据 |
| 第 3 章 | 文件上传方案 | 客户端直传、Pre-signed URL |
| 第 4 章 | CDN 加速 | 边缘节点、缓存策略、回源 |
| 第 5 章 | 最佳实践 | 命名规范、权限、生命周期 |
0. 全景图:为什么不能把文件存在服务器本地?
刚开始做项目时,把用户上传的文件存在服务器本地目录是最直觉的做法。但随着项目发展,你会遇到一系列问题:
- 磁盘空间有限 :服务器磁盘总会满,扩容麻烦
- 多服务器不共享 :负载均衡后,用户请求可能打到不同服务器,文件找不到
- 没有备份 :服务器挂了,文件就丢了
- 没有 CDN :全球用户访问同一台服务器,速度慢
对象存储的核心价值
对象存储(如 AWS S3、阿里云 OSS)解决了所有这些问题:容量无限、全球可访问、自动备份、天然支持 CDN 。它已经成为互联网应用存储文件的事实标准。
1. 存储类型对比:块、文件、对象
计算机世界有三种主要的存储方式,它们解决不同层次的问题。
三种存储方式对比
| 维度 | 块存储 | 文件存储 | 对象存储 |
|---|---|---|---|
| 数据单位 | 固定大小的块 | 文件 + 目录 | 对象(Key-Value) |
| 访问协议 | iSCSI/FC | NFS/SMB | HTTP REST API |
| 性能 | 最高(毫秒级) | 中等 | 较低(但够用) |
| 扩展性 | 有限 | 中等 | 近乎无限 |
| 成本 | 最高 | 中等 | 最低 |
| 典型场景 | 数据库 | 共享文件 | 图片/视频/备份 |
对象存储深入理解
核心定义
通过 HTTP API 存取文件(对象),每个对象有唯一 Key。扁平结构,无目录层级。容量几乎无限,成本最低,是互联网应用的首选。
对象存储的五大特性
| 特性 | 说明 | 示例 |
|---|---|---|
| 访问协议 | HTTP/HTTPS RESTful API | PUT/GET/DELETE 等标准操作 |
| 应用场景 | 图片、视频、备份、静态网站托管、数据湖 | 用户头像、视频流、日志存档、数据分析数据源 |
| 代表产品 | AWS S3、阿里云 OSS、MinIO、Cloudflare R2 | 行业标准方案,功能完整 |
| 扩展性 | 近乎无限扩展,自动分布式存储 | 无需考虑容量上限,自动分片存储 |
| 成本优势 | 按需付费,出口流量最便宜 | 相比块存储便宜 10-100 倍 |
三种存储的快速记忆法
块存储 → 硬盘 → 给数据库用 → 要求:速度快、可靠
↓
文件存储 → 网盘共享 → 给多服务器用 → 要求:共享、协议兼容
↓
对象存储 → 互联网网盘 → 给用户文件用 → 要求:容量大、成本低、可扩展
简单记忆
- 块存储 像硬盘——给数据库用
- 文件存储 像网络共享文件夹——给多台服务器共享配置用
- 对象存储 像网盘——给用户上传的图片、视频用
2. 对象存储核心概念
对象存储的数据模型非常简单:Bucket(桶) 是容器,Object(对象) 是文件,每个对象通过唯一的 Key(键) 来标识。
my-app-bucket/ ← Bucket(桶)
├── avatars/user-123.jpg ← Object Key
├── avatars/user-456.png ← Object Key
├── reports/2024/q1-report.pdf ← Object Key("目录"只是 Key 的前缀)
└── uploads/temp/file.zip ← Object Key
| 概念 | 说明 | 示例 |
|---|---|---|
| Bucket | 存储容器,全局唯一命名 | my-app-prod、company-assets |
| Object | 存储的文件本体 + 元数据 | 一张图片、一个 PDF |
| Key | 对象的唯一标识符 | avatars/user-123.jpg |
| 元数据 | 对象的附加信息 | Content-Type、自定义标签 |
| ACL | 访问控制列表 | public-read、private |
| Pre-signed URL | 临时授权访问链接 | 有效期 15 分钟的上传/下载链接 |
对象存储没有真正的"目录"
avatars/user-123.jpg 中的 avatars/ 不是目录,只是 Key 的前缀。对象存储是扁平结构,所有对象在同一层级。控制台显示的"文件夹"只是按前缀分组的视觉效果。
3. 文件上传方案:谁来传文件?
文件上传有两种主流方案:服务端中转和客户端直传。对于大多数场景,客户端直传 是更优的选择。
3.1 两种方案对比
| 维度 | 服务端中转 | 客户端直传 |
|---|---|---|
| 数据流向 | 客户端 → 服务器 → OSS | 客户端 → OSS(直传) |
| 服务器负载 | 高(需处理文件流) | 低(仅签发凭证) |
| 上传效率 | 低(文件传输两次) | 高(一次直传) |
| 大文件支持 | 差(易超时/超限) | 好(支持分片续传) |
| 实现复杂度 | 简单 | 需配置 Pre-signed URL + CORS |
3.2 服务端中转流程
文件先经过后端服务器,再由服务器转发到对象存储:
-
客户端 → 服务器
- 用户选择文件,上传到后端服务器
- ⚠️ 大文件会占用服务器带宽和内存
-
服务器接收文件
- 后端将文件暂存到本地磁盘或内存
- ⚠️ 可能触发 Nginx 的
client_max_body_size限制
-
服务器 → OSS
- 后端再将文件转发到对象存储
- ⚠️ 文件传输了两次,效率低
-
OSS 返回 URL
- 对象存储返回文件的访问地址
-
服务器 → 客户端
- 后端将文件 URL 返回给前端
3.3 客户端直传流程
文件直接从客户端上传到 OSS,服务器只负责签发凭证:
- 客户端请求凭证 — 前端请求后端获取 Pre-signed URL
- 客户端直传 OSS — 前端用 Pre-signed URL 将文件直接上传到 OSS
- OSS 回调通知 — 上传完成后 OSS 回调通知后端记录文件信息
3.4 客户端直传的优势
- 节省服务器带宽 :文件不经过你的服务器,直接到 OSS
- 避免超时 :大文件上传不会触发 Nginx/网关的超时限制
- 降低服务器负载 :服务器只需要签发凭证,不需要处理文件流
- 支持断点续传 :OSS 原生支持分片上传,前端可以实现断点续传
实现步骤:前端请求后端获取 Pre-signed URL → 前端用这个 URL 直接上传到 OSS → OSS 回调通知后端
4. CDN 加速:让全球用户都快
当你的用户遍布全球时,从单一源站下载文件会很慢。CDN(Content Delivery Network)通过在全球部署边缘节点,将文件缓存到离用户最近的节点,大幅降低访问延迟。
CDN 加速原理
对比有无 CDN 时的文件访问路径
无 CDN有 CDN
北京用户
5ms
北京 CDN 节点
缓存命中
缓存未命中时回源
源站(美西 S3)
首字节时间 (TTFB)
~30ms
下载 1MB 图片
~50ms
| CDN 概念 | 说明 |
|---|---|
| 边缘节点 | 分布在全球各地的缓存服务器 |
| 回源 | 边缘节点没有缓存时,向源站请求文件 |
| 缓存命中率 | 请求被边缘节点直接响应的比例,越高越好 |
| TTL | 缓存有效期,过期后需要重新回源 |
| 缓存刷新 | 主动清除边缘节点的缓存,让新文件生效 |
CDN 最佳实践
- 文件名加 hash :
logo.a3f2b1.png而不是logo.png,这样更新文件时不需要刷新缓存 - 设置合理的 TTL :静态资源(JS/CSS/图片)设长 TTL(1年),HTML 设短 TTL(5分钟)
- 开启 Gzip/Brotli 压缩 :文本类资源压缩后体积减少 60-80%
5. 最佳实践
| 实践 | 说明 | 示例 |
|---|---|---|
| Key 命名规范 | 用有意义的前缀组织文件 | {type}/{date}/{uuid}.{ext} |
| 避免热点 Key | 不要用递增数字开头 | 用 UUID 或 hash 前缀 |
| 权限最小化 | Bucket 默认 private | 只对需要公开的文件设置 public-read |
| 生命周期规则 | 自动清理过期文件 | 临时文件 7 天后自动删除 |
| 跨域配置 | 前端直传需要配置 CORS | 允许你的域名 PUT/POST |
| 服务端加密 | 敏感文件开启 SSE | SSE-S3 或 SSE-KMS |
总结
文件存储是每个 Web 应用都会遇到的基础问题。对象存储以其无限容量、低成本、高可用的特性,成为了互联网应用的标准选择。
回顾本章的关键要点:
- 三种存储类型 :块存储给数据库、文件存储给共享、对象存储给用户文件
- 对象存储模型 :Bucket + Key + Object,扁平结构,HTTP API 访问
- 客户端直传 :Pre-signed URL 方案,文件不经过服务器,高效省资源
- CDN 加速 :边缘节点缓存 + 文件名 hash,让全球用户都快
- 安全与管理 :权限最小化、生命周期规则、服务端加密
延伸阅读
- AWS S3 开发者指南 - 对象存储的标杆文档
- 阿里云 OSS 最佳实践 - 国内最常用的对象存储
- MinIO 文档 - 开源的 S3 兼容对象存储
- Cloudflare R2 - 零出口费用的对象存储
- Pre-signed URL 详解 - 客户端直传的核心机制