7. 数据存储与云服务基础

当应用需要处理文件上传和持久化存储时,理解不同存储方案的优劣势至关重要。本章从云服务基础概念开始,到对象存储方案的深度对比。


7.1 云服务基础概念

在部署 Web 应用时,你会接触到各种云产品。以下是核心概念的通俗解释:

云服务 全称 通俗类比 核心作用
ECS Elastic Compute Service 云服务器 系统的"大脑",运行业务代码
CDN Content Delivery Network 快递分拣中心 将静态资源缓存到离用户最近的节点
OSS Object Storage Service 云端硬盘 存储图片、视频、备份文件
SLB Server Load Balancer 交通指挥 将流量分发给多台服务器
RDS Relational Database Service 托管数据库 自动备份、高可用的数据库服务
VPC Virtual Private Cloud 逻辑隔离区 云上的私有网络,安全隔离

ECS(云服务器)

原理说明

通过虚拟化技术将物理服务器资源切分,用户可按需调配 CPU、内存和带宽。你购买的"北京服务器"就是一台 ECS 实例。

CDN(内容分发网络)

原理说明

OSS(对象存储服务)

原理说明

SLB(负载均衡)

原理说明

RDS(关系型数据库服务)

原理说明

由云厂商负责底层运维、备份、补丁和高可用架构,用户只需连接使用数据库。相比自建数据库,RDS 免去了备份和主从同步的运维成本。

VPC(专有网络)

原理说明

利用 VXLAN 隧道技术在公共基础设施上构建完全隔离的虚拟网络,提供网络级的安全保障。


7.2 文件存储的问题演进

传统文件系统的痛点

在容器化环境中,使用本地文件系统存储上传文件会遇到一系列问题:

传统文件系统                   对象存储
├── /uploads/avatar/           ├── Bucket: avatar
│   ├── user1.jpg              │   ├── Key: user1/avatar.jpg
│   └── user2.png              │   └── Key: user2/avatar.png
├── /uploads/cover/            ├── Bucket: cover
│   ├── course1.jpg            │   ├── Key: course1/cover.jpg
│   └── course2.jpg            │   └── Key: course2/cover.jpg
└── 权限:755                  └── 策略:IAM + Bucket Policy
问题 说明
权限困境 Docker 卷挂载权限覆盖,需要 entrypoint 脚本"打补丁"
扩展性限制 单机存储有限,无法水平扩展
功能缺失 无版本控制、无生命周期管理、无访问策略
部署复杂 多节点文件同步困难,无高可用

对象存储的优势

对象存储通过 Bucket + Key 的扁平化结构,配合 IAM 策略,解决了上述所有问题。但引入它意味着增加架构复杂度。


7.3 MinIO vs SeaweedFS 深度对比

MinIO 核心特性

SeaweedFS 核心特性

详细对比

维度 MinIO SeaweedFS
设计目标 S3 兼容的对象存储 高性能分布式文件系统
架构模型 单一服务,多节点对等 分层架构(Master+Volume+Filer)
单节点部署 ⭐ 非常简单 ⭐⭐ 需 2 个组件
集群部署 ⭐⭐ 相对简单 ⭐⭐⭐ 组件多
S3 兼容性 完全兼容 通过 Filer 兼容
小文件性能 一般(元数据压力) 优秀(专门优化)
大文件性能 优秀(流式处理) 良好
图形控制台 ✅ 内置 ❌ 需第三方
运维复杂度

MinIO 单节点部署

# docker-compose.yml 中添加 MinIO
services:
  minio:
    image: minio/minio
    command: server /data --console-address ":9001"
    ports:
      - "9000:9000"   # S3 API 端口
      - "9001:9001"   # 管理控制台
    volumes:
      - minio_data:/data
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: secret123
    networks:
      - app-network

volumes:
  minio_data:

代码集成示例

// 安装依赖
// npm install @aws-sdk/client-s3

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const s3 = new S3Client({
  endpoint: process.env.S3_ENDPOINT,
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY,
    secretAccessKey: process.env.S3_SECRET_KEY,
  },
});

async function uploadToS3(file: File, key: string) {
  const command = new PutObjectCommand({
    Bucket: process.env.S3_BUCKET,
    Key: key,
    Body: file,
  });
  await s3.send(command);
  return `${process.env.S3_PUBLIC_URL}/${key}`;
}

Nginx 反向代理对象存储

# 统一访问路径,隐藏内部存储细节
location /storage/ {
    proxy_pass http://minio:9000/bucket/;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

7.4 决策框架:如何选择?

根据项目阶段选择

验证期(用户<1000) → 优化本地存储,不引入新组件
                          ↓
增长期(1000-10000) → MinIO 单节点(S3 兼容,生态丰富)
                          ↓
扩展期(>10000)    → 小文件多 → SeaweedFS
                    → 大文件多 → MinIO 集群

根据团队选择

团队类型 推荐方案 理由
小型团队(1-3 人全栈) MinIO 文档完整,问题易搜索解决,单一服务
专业运维团队 可考虑 SeaweedFS 能处理多组件协调,追求极致性能

渐进式迁移策略

第1步:抽象层准备(1-2天)
// storage.ts — 统一接口,无论底层用什么都一样调用
export interface StorageProvider {
  upload(file: File, path: string): Promise<string>;
  delete(path: string): Promise<void>;
  getUrl(path: string): string;
}

export class LocalStorage implements StorageProvider { ... }
export class MinioStorage implements StorageProvider { ... }
第2步:MinIO 测试环境并行运行(1周)
第3步:灰度迁移新上传走 MinIO(2-4周)
第4步:完全切换,清理旧文件

7.5 总结建议

对于当前项目(验证期)

  1. 修复当前 Docker 卷权限问题(固定 UID/GID + entrypoint 脚本)
  2. 实现存储抽象层(为未来切换做准备)
  3. 不立即引入 MinIO/SeaweedFS — 项目处于验证期,复杂度应最小化

记住:技术选型的核心不是"哪个更好",而是"哪个更适合当前阶段和团队能力"。优雅的解决方案是在正确的时间做正确的事


返回知识库 | 下一篇:扩展知识