Skip to content

对象存储

欢迎来到对象存储知识库!

📦 对象存储简介

对象存储(Object Storage)是一种将数据作为对象进行管理的存储架构,每个对象包含数据本身、元数据和唯一标识符。它非常适合存储非结构化数据,如图片、视频、文档、日志等。

🎯 三种存储类型对比

对象存储 vs 文件存储 vs 块存储

特性对象存储文件存储块存储
组织方式扁平化,无目录层级文件系统,目录树块设备
访问方式HTTP/HTTPS APIPOSIX 文件接口SCSI/iSCSI
元数据丰富的自定义元数据有限的文件属性
扩展性⭐⭐⭐⭐⭐ 无限扩展⭐⭐⭐ 受限⭐⭐ 受限
性能⭐⭐⭐ 中等⭐⭐⭐⭐ 高⭐⭐⭐⭐⭐ 最高
成本⭐⭐⭐⭐⭐ 低⭐⭐⭐ 中⭐⭐ 高
适用场景静态资源、备份、归档共享文件、日志数据库、虚拟机磁盘

形象比喻

  • 块存储 = 笔记本,可以随意修改任意位置的内容
  • 文件存储 = 文件柜,有清晰的目录结构
  • 对象存储 = 仓库,每个货物有唯一编号,存放位置灵活

✅ 对象存储的优势

1. 无限扩展

传统存储: 容量有限,需要提前规划
对象存储: 按需扩展,理论上无限

2. 高可靠性

多副本存储: 自动备份到多个节点
数据持久性: 99.999999999% (11个9)
自动恢复: 检测并修复损坏的数据

3. 低成本

按需付费: 只为使用的容量付费
生命周期管理: 自动归档冷数据
存储类型: 热、温、冷多种选择

4. HTTP 访问

RESTful API: 通过 HTTP/HTTPS 访问
CDN 友好: 易于集成 CDN 加速
跨平台: 任何支持 HTTP 的环境都可使用

🎯 适用场景

✅ 特别适合

1. 静态资源托管

网站资源:
├── 图片 (jpg, png, webp)
├── 视频 (mp4, mov)
├── CSS/JS 文件
└── 字体文件

2. 多媒体内容

视频平台:
├── 用户上传的视频
├── 缩略图
└── 字幕文件

图片社交:
├── 原图
├── 各种尺寸的缩略图
└── 用户头像

3. 备份与归档

数据备份:
├── 数据库备份
├── 日志归档
├── 文档归档
└── 冷数据存储

4. 大数据分析

数据湖:
├── 原始数据
├── 处理后的数据
└── 分析结果

5. 软件分发

应用下载:
├── 安装包 (APK, IPA, EXE)
├── 更新包
└── 补丁文件

⚠️ 不太适合

  • 需要频繁修改的小文件 - 对象存储不支持追加写入
  • 需要 POSIX 文件系统 - 无法直接挂载
  • 低延迟要求 - 相比块存储延迟较高
  • 事务性操作 - 不支持文件系统级别的事务

📊 主流对象存储服务对比

服务类型特点适用场景
AWS S3公有云事实标准,功能最全国际业务
MinIO私有云S3 兼容,开源免费私有部署
阿里云 OSS公有云国内访问快,生态好国内业务
腾讯云 COS公有云音视频处理强多媒体应用
七牛云 Kodo公有云CDN 加速好静态资源
Ceph私有云企业级,功能强大大规模部署

🔑 核心概念

1. Bucket(桶/存储空间)

类似于顶级目录或容器,用于组织对象。

特点:
- 全局唯一的名称
- 独立的权限控制
- 独立的配置(版本控制、生命周期等)

示例:
my-website-assets/
my-user-uploads/
my-backup-data/

2. Object(对象)

实际存储的文件。

对象组成:
├── Key (对象键/文件名)
│   例: images/2024/01/photo.jpg
├── Value (数据本身)
│   实际的文件内容
├── Metadata (元数据)
│   ├── Content-Type: image/jpeg
│   ├── Content-Length: 1024000
│   └── 自定义元数据
└── Version ID (可选)
    版本控制标识

3. Key(对象键)

对象的唯一标识符,类似文件路径。

扁平化存储:
实际上没有目录,只是 key 的前缀

key = "users/123/avatar.jpg"
     ├── users/123/ 看起来像目录
     └── avatar.jpg 看起来像文件名

4. Region(区域)

对象存储服务的物理位置。

选择依据:
├── 用户地理位置 (降低延迟)
├── 数据合规性 (数据主权)
└── 成本考虑 (不同区域价格不同)

🚀 快速开始示例

AWS S3 (Node.js)

javascript
const AWS = require('aws-sdk');

// 配置
const s3 = new AWS.S3({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  region: 'us-east-1'
});

// 上传文件
const uploadFile = async (file) => {
  const params = {
    Bucket: 'my-bucket',
    Key: `uploads/${Date.now()}-${file.name}`,
    Body: file.data,
    ContentType: file.mimetype
  };
  
  const result = await s3.upload(params).promise();
  return result.Location;  // 返回文件 URL
};

// 下载文件
const getFile = async (key) => {
  const params = {
    Bucket: 'my-bucket',
    Key: key
  };
  
  const data = await s3.getObject(params).promise();
  return data.Body;
};

// 生成预签名 URL (临时访问链接)
const getPresignedUrl = (key) => {
  const params = {
    Bucket: 'my-bucket',
    Key: key,
    Expires: 3600  // 1小时有效
  };
  
  return s3.getSignedUrl('getObject', params);
};

// 列出文件
const listFiles = async (prefix) => {
  const params = {
    Bucket: 'my-bucket',
    Prefix: prefix
  };
  
  const data = await s3.listObjectsV2(params).promise();
  return data.Contents;
};

// 删除文件
const deleteFile = async (key) => {
  const params = {
    Bucket: 'my-bucket',
    Key: key
  };
  
  await s3.deleteObject(params).promise();
};

MinIO (Node.js)

javascript
const Minio = require('minio');

// 配置
const minioClient = new Minio.Client({
  endPoint: 'localhost',
  port: 9000,
  useSSL: false,
  accessKey: 'minioadmin',
  secretKey: 'minioadmin'
});

// 上传文件
const uploadFile = async (bucketName, objectName, filePath) => {
  await minioClient.fPutObject(bucketName, objectName, filePath);
  console.log('File uploaded successfully');
};

// 下载文件
const getFile = async (bucketName, objectName) => {
  const stream = await minioClient.getObject(bucketName, objectName);
  return stream;
};

// 生成预签名 URL
const getPresignedUrl = async (bucketName, objectName) => {
  return await minioClient.presignedGetObject(bucketName, objectName, 3600);
};

🔒 安全性

1. 访问控制

权限层级:
├── IAM 用户权限
├── Bucket Policy (桶策略)
├── ACL (访问控制列表)
└── 预签名 URL (临时访问)

2. 加密

传输加密: HTTPS/TLS
存储加密:
├── 服务端加密 (SSE)
│   ├── SSE-S3 (S3 管理密钥)
│   ├── SSE-KMS (AWS KMS 管理密钥)
│   └── SSE-C (客户提供密钥)
└── 客户端加密 (上传前加密)

3. 防盗链

javascript
// Bucket Policy 示例 - 限制 Referer
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "StringNotLike": {
          "aws:Referer": [
            "https://mywebsite.com/*"
          ]
        }
      }
    }
  ]
}

💰 成本优化

1. 存储类型

S3 存储类型:
├── S3 标准 (高频访问)
│   - 最快,最贵
├── S3 标准-IA (低频访问)
│   - 30天以上不访问
├── S3 单区-IA
│   - 更便宜,单可用区
├── S3 Glacier (归档)
│   - 检索时间:分钟到小时
└── S3 Glacier Deep Archive (深度归档)
    - 检索时间:12小时
    - 最便宜,适合长期归档

2. 生命周期管理

javascript
// 自动转换存储类型
{
  "Rules": [
    {
      "Id": "Archive old files",
      "Status": "Enabled",
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER"
        }
      ],
      "Expiration": {
        "Days": 365  // 1年后删除
      }
    }
  ]
}

🎯 开始学习

根据你的需求选择学习方向:

💡 最佳实践

1. 文件命名

javascript
// ✅ 好的命名
const key = `users/${userId}/avatars/${timestamp}-${uuid}.jpg`;
const key = `documents/2024/01/15/report.pdf`;

// ❌ 不好的命名
const key = `用户头像.jpg`;  // 避免中文
const key = `file (1).jpg`;  // 避免特殊字符
const key = `../../../etc/passwd`;  // 防止路径穿越

2. 使用 CDN

用户请求

CDN 节点 (缓存) ──未命中──> 对象存储
  ↓ 命中
用户 (快速响应)

3. 预签名 URL

javascript
// 临时授权访问,无需公开权限
const url = s3.getSignedUrl('getObject', {
  Bucket: 'my-bucket',
  Key: 'private/document.pdf',
  Expires: 300  // 5分钟有效
});

// 分享给用户
console.log(url);
// https://my-bucket.s3.amazonaws.com/private/document.pdf?AWSAccessKeyId=...&Expires=...&Signature=...

4. 分片上传大文件

javascript
// 大于 5GB 的文件必须使用分片上传
// 5MB - 5GB 建议使用分片上传

const uploadLargeFile = async (file) => {
  const multipartParams = {
    Bucket: 'my-bucket',
    Key: file.name,
    Body: file.stream
  };
  
  const parallelUploads = new AWS.S3.ManagedUpload({
    params: multipartParams,
    partSize: 10 * 1024 * 1024,  // 10MB per part
    queueSize: 4  // 并发上传4个分片
  });
  
  return await parallelUploads.promise();
};

📖 学习资源

官方文档

推荐阅读


准备好了吗?开始你的对象存储学习之旅!