# 檔案與物件儲存導論

::: tip 前言
**用户上傳了一张頭像，你把它存在服務器的 `/uploads` 目錄下——然後服務器磁盘满了，或者你加了第二台服務器，用户發現頭像時有時无。** 文件存儲看似简單，但在分布式環境下却是一个需要認真對待的架構問题。對象存儲就是互聯網時代解决這个問题的標準答案。
:::

**這篇文章會带你學什么？**

學完這章後，你将獲得：

- **存儲類型認知**：理解塊存儲、文件存儲、對象存儲的區別和適用場景
- **對象存儲核心概念**：掌握 Bucket、Object、Key、Pre-signed URL 等核心概念
- **上傳方案設計**：學會客户端直傳 vs 服務端中轉的方案選型
- **CDN 加速原理**：理解 CDN 如何加速静態资源的全球分發
- **最佳實踐**：掌握文件命名、權限控制、生命周期管理等實戰技巧

| 章節 | 內容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 存儲類型對比 | 塊存儲、文件存儲、對象存儲 |
| **第 2 章** | 對象存儲核心概念 | Bucket、Object、Key、元數據 |
| **第 3 章** | 文件上傳方案 | 客户端直傳、Pre-signed URL |
| **第 4 章** | CDN 加速 | 邊缘節點、緩存策略、回源 |
| **第 5 章** | 最佳實踐 | 命名規范、權限、生命周期 |

---

## 0. 全景图：禁止本地文件存儲的必要性

刚開始做项目時，把用户上傳的文件存在服務器本地目錄是最直觉的做法。但隨着项目發展，你會遇到一系列問题：

- **磁盘空間有限**：服務器磁盘總會满，擴容麻烦
- **多服務器不共享**：负載均衡後，用户請求可能打到不同服務器，文件找不到
- **没有備份**：服務器挂了，文件就丟了
- **没有 CDN**：全球用户访問同一台服務器，速度慢

::: tip 對象存儲的核心价值
對象存儲（如 AWS S3、阿裡云 OSS）解决了所有這些問题：**容量无限、全球可访問、自動備份、天然支持 CDN**。它已經成為互聯網應用存儲文件的事實標準。
:::

---

## 1. 存儲類型對比：塊、文件、對象

計算機世界有三種主要的存儲方式，它们解决不同層次的問题。

<FileStorageTypeDemo />

| 維度 | 塊存儲 | 文件存儲 | 對象存儲 |
|------|--------|---------|---------|
| 數據單位 | 固定大小的塊 | 文件 + 目錄 | 對象（Key-Value） |
| 访問協议 | iSCSI/FC | NFS/SMB | HTTP REST API |
| 性能 | 最高（毫秒级） | 中等 | 較低（但够用） |
| 擴展性 | 有限 | 中等 | 近乎无限 |
| 成本 | 最高 | 中等 | 最低 |
| 典型場景 | 數據庫 | 共享文件 | 图片/视频/備份 |

::: tip 简單記忆
- **塊存儲**像硬盘——给數據庫用
- **文件存儲**像網絡共享文件夹——给多台服務器共享配置用
- **對象存儲**像網盘——给用户上傳的图片、视频用
:::

---

## 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 分鐘的上傳/下載鏈接 |

::: tip 對象存儲没有真正的"目錄"
`avatars/user-123.jpg` 中的 `avatars/` 不是目錄，只是 Key 的前缀。對象存儲是扁平結構，所有對象在同一層级。控制台顯示的"文件夹"只是按前缀分組的视觉效果。
:::

---

## 3. 文件上傳方案：的可見性範圍界定

文件上傳有兩種主流方案：服務端中轉和客户端直傳。對于大多數場景，**客户端直傳**是更優的選择。

<FileUploadFlowDemo />

::: tip 客户端直傳的優勢
1. **節省服務器带宽**：文件不經過你的服務器，直接到 OSS
2. **避免超時**：大文件上傳不會触發 Nginx/網關的超時限制
3. **降低服務器负載**：服務器只需要簽發凭證，不需要處理文件流
4. **支持断點續傳**：OSS 原生支持分片上傳，前端可以實現断點續傳

實現步骤：前端請求後端獲取 Pre-signed URL → 前端用這个 URL 直接上傳到 OSS → OSS 回調通知後端
:::

---

## 4. CDN 加速：讓全球用户都快

当你的用户遍布全球時，從單一源站下載文件會很慢。CDN（Content Delivery Network）通過在全球部署邊缘節點，将文件緩存到離用户最近的節點，大幅降低访問延遲。

<CDNAccelerationDemo />

| CDN 概念 | 說明 |
|---------|------|
| 邊缘節點 | 分布在全球各地的緩存服務器 |
| 回源 | 邊缘節點没有緩存時，向源站請求文件 |
| 緩存命中率 | 請求被邊缘節點直接響應的比例，越高越好 |
| TTL | 緩存有效期，過期後需要重新回源 |
| 緩存刷新 | 主動清除邊缘節點的緩存，讓新文件生效 |

::: tip 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 應用都會遇到的基础問题。對象存儲以其无限容量、低成本、高可用的特性，成為了互聯網應用的標準選择。

回顧本章的關鍵要點：

1. **三種存儲類型**：塊存儲给數據庫、文件存儲给共享、對象存儲给用户文件
2. **對象存儲模型**：Bucket + Key + Object，扁平結構，HTTP API 访問
3. **客户端直傳**：Pre-signed URL 方案，文件不經過服務器，高效省资源
4. **CDN 加速**：邊缘節點緩存 + 文件名 hash，讓全球用户都快
5. **安全與管理**：權限最小化、生命周期規则、服務端加密

## 延伸阅讀

- [AWS S3 開發者指南](https://docs.aws.amazon.com/s3/) - 對象存儲的標杆文檔
- [阿裡云 OSS 最佳實踐](https://help.aliyun.com/document_detail/31853.html) - 国內最常用的對象存儲
- [MinIO 文檔](https://min.io/docs/minio/linux/index.html) - 開源的 S3 兼容對象存儲
- [Cloudflare R2](https://developers.cloudflare.com/r2/) - 零出口費用的對象存儲
- [Pre-signed URL 詳解](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html) - 客户端直傳的核心機制
