Skip to content

对象存储 (COS / S3) ​

#组件 · #对象存储 · #COS · #S3 · #云存储 · #MinIO

海量非结构化数据的归宿——存储模型、访问控制、性能优化与典型应用场景。

一、概念模型 ​

1.1 为什么不用文件系统 ​

维度POSIX 文件系统对象存储
数据模型层级目录树扁平命名空间 (Bucket → Object)
扩展性受限于单机/集群规模近乎无限(水平扩展)
元数据inode (有限)K-V 数据库 (可海量)
并发锁竞争,目录瓶颈无锁,Key 级别并发
数据冗余RAID / 副本多副本 + 纠删码 (跨 AZ)
POSIX 兼容完全兼容受限(强最终一致性)
成本高(高性能硬件)低(通用硬件 + 纠删码)

1.2 核心概念 ​

mermaid
flowchart TB
    User["用户 (腾讯云/AWS 账户)"]

    subgraph Buckets["存储桶"]
        B1["Bucket A"]
        B2["Bucket B"]
        B3["Bucket C"]
    end

    User --> B1
    User --> B2
    User --> B3

    subgraph ObjA["Bucket A 对象"]
        O1["Object (Key)<br/>+ Data<br/>+ Metadata<br/>+ VersionID"]
    end
    subgraph ObjB["Bucket B 对象"]
        O2["Object (Key)<br/>+ Data<br/>+ Metadata<br/>+ VersionID"]
    end

    B1 --> ObjA
    B2 --> ObjB
概念说明限制
Bucket存储桶,全局唯一名称,顶级命名空间单用户最多 200 个
Object存储对象,由 Key+Data+Metadata 组成单 Object 最大 5TB (S3) / 48.82TB (COS)
Key对象的唯一标识,支持 / 分隔模拟目录长度 < 1024B
Metadata用户自定义元数据 + 系统元数据自定义元数据 < 2KB
VersionID版本号(开启版本控制后每次上传生成)—

二、存储类型 ​

2.1 生命周期管理 ​

数据访问热度:

  热 ←───────────────────────────────→ 冷

  STANDARD(标准)  →  STANDARD_IA(低频)  →  ARCHIVE(归档)  →  DEEP_ARCHIVE(深度归档)
  毫秒级访问         毫秒级访问          分钟级取回(1-5min)   小时级取回(12-48h)
  高可用(99.95%)     高可用             数据恢复成本高        最低成本
类型最小存储时长最小计费大小取回费用适用
STANDARD——❌热数据、网站、CDN
STANDARD_IA30 天64KB❌备份、灾难恢复
ARCHIVE90 天64KB✅ 按量归档、合规
DEEP_ARCHIVE180 天64KB✅ 按量长期归档

2.2 生命周期规则 ​

xml
<!-- COS 生命周期配置 -->
<LifecycleConfiguration>
  <Rule>
    <ID>log-archival</ID>
    <Filter>
      <Prefix>logs/</Prefix>              <!-- 对 logs/ 前缀生效 -->
    </Filter>
    <Status>Enabled</Status>
    <Transition>
      <Days>30</Days>                      <!-- 30天后转换 -->
      <StorageClass>STANDARD_IA</StorageClass>
    </Transition>
    <Transition>
      <Days>90</Days>                      <!-- 90天后归档 -->
      <StorageClass>ARCHIVE</StorageClass>
    </Transition>
    <Expiration>
      <Days>365</Days>                     <!-- 365天后删除 -->
    </Expiration>
  </Rule>
</LifecycleConfiguration>

三、访问控制 ​

3.1 三层控制体系 ​

┌──────────────────────────────────────────────┐
│              访问控制                          │
│                                               │
│  1. Bucket 策略 (Policy, JSON)               │
│     · 基于资源的精细化权限                    │
│     · 支持跨账号授权                          │
│     · 粒度: Bucket / 前缀 / 对象              │
│                                               │
│  2. ACL (访问控制列表)                        │
│     · 预定义组 (所有用户/认证用户)             │
│     · 粒度: Bucket / 对象                     │
│                                               │
│  3. 临时密钥 (STS)                            │
│     · 临时 AK/SK + SessionToken               │
│     · 精细权限 + 时效性                       │
│     · 前端直传/移动端/第三方                    │
└──────────────────────────────────────────────┘

3.2 访问控制对比 ​

方式粒度时效适用
Bucket PolicyBucket/前缀/对象永久静态网站托管、跨账号分享
ACLBucket/对象永久简单权限(即将废弃)
STS 临时密钥细粒度, 可指定条件15min-12h前端直传、移动端、CI

3.3 预签名 URL ​

GET /photo.jpg
  ?X-Amz-Algorithm=AWS4-HMAC-SHA256
  &X-Amz-Credential=AKIDxxx/20240101/region/s3/aws4_request
  &X-Amz-Date=20240101T000000Z
  &X-Amz-Expires=3600           ← 1小时过期
  &X-Amz-Signature=xxxx

适用: 临时下载/上传,无需暴露 AK/SK

四、上传 ​

4.1 上传方式 ​

方式限制适用
简单上传 (PUT Object)≤ 5GB小文件
分片上传 (Multipart)必选>5GB,单块≥1MB, 最多10000块大文件、网络不稳定
追加上传 (Append, COS)首次≤5GB, 后续≤5GB日志追加(S3不支持)
表单上传 (POST Object)≤ 5GBWeb 页面直传
批量上传 (SDK/CLI)—批量迁移

4.2 分片上传流程 ​

1. Initiate Multipart Upload
   POST /object?uploads
   ← UploadId

2. Upload Part (可并行, 每个 Part 返回 ETag)
   PUT /object?partNumber=1&uploadId=xxx
   PUT /object?partNumber=2&uploadId=xxx
   PUT /object?partNumber=N&uploadId=xxx

3. Complete Multipart Upload (或 Abort)
   POST /object?uploadId=xxx
   Body: <CompleteMultipartUpload>
           <Part><PartNumber>1</PartNumber><ETag>etag1</ETag></Part>
           ...
         </CompleteMultipartUpload>

中断恢复: ListParts 获取已上传分片, 断点续传
中断清理: AbortMultipartUpload 删除碎片 (或生命周期自动清理)

五、数据保护 ​

5.1 冗余方案 ​

方案可用性持久性说明
单 AZ99.5%99.999999999% (11个9)同数据中心多副本
多 AZ99.95%99.9999999999% (12个9)跨可用区
跨域复制——跨 Region 异步复制

5.2 版本控制与 WORM ​

版本控制:
  Bucket 开启版本控制
  覆盖写入 → 生成新版本 (保留旧版本)
  删除 → 标记 DeleteMarker (可恢复)
  彻底删除 → 指定 VersionID 删除

WORM (Write Once Read Many, COS):
  合规保留: 锁定期间任何人(含 root)不可删除/修改
  对象锁定: Retention (保留期限) / Legal Hold (诉讼保留)

5.3 加密 ​

方式说明
SSE-COS (S3-SSE)服务端托管密钥, 自动加解密
SSE-KMS使用 KMS 密钥, 审计日志
SSE-C客户端提供密钥
CSE (客户端加密)客户端本地加密后上传

六、访问加速 ​

6.1 CDN 加速 ​

用户 ──→ CDN 边缘节点 (就近访问)
              │ 未命中
              ▼
         对象存储源站

配置: 绑定 CDN 域名 + 回源鉴权
      Bucket Policy 允许 CDN 回源
      CDN 缓存规则 (按路径/后缀)

6.2 全球加速(COS) ​

国内用户 ──→ 国内 CDN ──→ 国内 COS
海外用户 ──→ CloudFront/海外 CDN ──→ 海外 COS(跨域复制)

6.3 数据取回加速 ​

归档数据直接访问 → 需要先取回(分钟~小时级)

如果需要快速访问归档数据,预先按需转换存储级别,或使用批量取回。


七、事件通知 ​

对象存储操作 → 触发事件 → 通知目标:

触发事件:   PUT (上传), DELETE (删除),
           POST (表单), Replication (复制完成)

通知目标:   SCF 云函数 → 图片压缩/转码
           CMQ/Kafka   → 异步解耦
           HTTP 回调   → 业务系统

典型场景:上传图片 → 事件通知 → 云函数自动生成缩略图。


八、典型应用 ​

静态网站托管 ​

Bucket 开启静态网站托管
  Index Document: index.html
  Error Document: error.html
  绑定自定义域名 + CDN

数据湖 ​

数据源 → 对象存储 (原始数据层)
         ↓ SQL 查询 (SelectObjectContent / Athena)
        × → 数据处理 (EMR, Spark)
        × → 机器学习 (SageMaker / TI-ONE)

日志归档 ​

应用日志 → 本地聚合 → 压缩 → 分片上传到 COS/S3 归档层
  配合生命周期: 30天 → STANDARD_IA, 90天 → ARCHIVE, 365天 → 删除

九、对比 COS vs S3 ​

维度COS (腾讯云)S3 (AWS)
一致性强一致性(所有Region)强一致性(2020.12 后)
最大 Object48.82TB5TB
存储类型STANDARD/IA/ARCHIVE/DEEP_ARCHIVE/MAZ类似 + Intelligent-Tiering/Glacier
追加上传✅❌
清单 (Inventory)✅✅
Select✅ (CSV/JSON)✅ (CSV/JSON/Parquet)
批量操作✅✅ S3 Batch Operations
跨域复制✅ (异步)✅ (CRR, SRR)

对象存储 vs HDFS vs NAS vs 块存储选型 ​

1. 四种存储模型对比 ​

mermaid
flowchart TD
    APP["应用层"]

    subgraph "块存储"
        B1["LUN / Volume (/dev/sdb)"]
        B2["格式化为 ext4/XFS"]
        B3["应用直接读写块"]
    end

    subgraph "文件存储 (NAS)"
        N1["NFS / CIFS 挂载"]
        N2["POSIX 文件接口"]
        N3["多客户端共享"]
    end

    subgraph "对象存储"
        O1["Bucket / Object"]
        O2["REST API (PUT/GET/DELETE)"]
        O3["无限扩展 + 元数据"]
    end

    subgraph "HDFS"
        H1["NameNode + DataNode"]
        H2["文件分块 (128MB/块)"]
        H3["本地磁盘 + 三副本"]
    end

    APP --> B3
    APP --> N3
    APP --> O3
    APP --> H3
维度块存储 (EBS/CBS)NAS (NFS/EFS)对象存储 (S3/COS)HDFS
接口块设备 (/dev/sdb)POSIX 文件系统REST APIHDFS API
访问方式挂载给单实例多客户端共享挂载HTTP(S)客户端 SDK
扩展性单卷最大 32-64TBPB 级无限 (EB 级)PB 级
延迟< 1ms (本地 SSD)1-5ms (同 AZ)10-100ms10-50ms
一致性强一致强一致强一致 (2020+, S3)写一次、读多次
修改随机读写随机读写不支持部分修改 (覆盖整个 Object)不支持修改 (追加)
元数据无文件属性丰富的自定义元数据有限
成本高 ($0.08-0.12/GB/月)中-高低 ($0.02/GB/月)中等 (自建硬件)
适合数据库共享文件 / 容器存储图片/视频/备份/日志大数据批处理

2. S3 一致性模型演进 ​

text
2020 年 12 月之前:
  S3 是"最终一致性"模型
  - PUT 新对象: 写后读一致性 (read-after-write)
  - PUT 覆盖已有对象: 最终一致性 (可能读到旧版本)
  - DELETE: 最终一致性 (可能仍然能读到)

2020 年 12 月之后:
  S3 是"强一致性"模型
  - 所有 PUT/DELETE 操作都是强一致的
  - 写完立即能读到最新版本
  - 不需要等待,不需要重试

为什么能实现强一致性?
  - 内部使用 Paxos/Raft 类共识算法
  - 元数据服务从最终一致升级为强一致
  - 数据复制路径优化

对应用的影响:
  - 2020 年前: 覆盖写入后需要等待或重试
  - 2020 年后: 不需要考虑一致性延迟

3. 对象存储不适合什么? ​

text
❌ 不适合:
  - 数据库存储 (需要 < 1ms 延迟 + 随机写)
  - 高频小文件随机读写 (HTTP 开销 > 磁盘开销)
  - 需要文件锁/NFS 共享语义的场景
  - 需要 POSIX 权限模型

✅ 适合:
  - 静态资源 (图片/视频/JS/CSS)
  - 备份/归档/日志
  - 数据湖 (Parquet/ORC/Avro)
  - 大数据计算中间结果
  - 容器镜像仓库

4. 选型决策树 ​

mermaid
flowchart TD
    Q1{"需要 < 5ms 延迟?"} -->|"是"| Q2{"需要多实例共享?"}
    Q2 -->|"是"| NAS["NAS (NFS/EFS)"]
    Q2 -->|"否"| Block["块存储 (EBS/CBS)"]
    Q1 -->|"否"| Q3{"需要修改已写入数据?"}
    Q3 -->|"是"| NAS2["NAS 或 块存储"]
    Q3 -->|"否"| Q4{"大数据生态 (Spark/Hive)?"}
    Q4 -->|"是"| HDFS["HDFS / S3 Compatible"]
    Q4 -->|"否"| S3["对象存储 (S3/COS)"]

参考 ​


十、纠删码(Erasure Coding)原理 ​

多副本 vs 纠删码 ​

mermaid
flowchart TB
    subgraph Replica["三副本方案"]
        R1["原始数据 1GB"]
        R2["副本 1: 1GB"]
        R3["副本 2: 1GB"]
        R4["副本 3: 1GB"]
        RNote["总存储: 3GB<br/>存储效率: 33%<br/>容忍故障: 2 节点"]
    end

    subgraph EC["纠删码 (4+2)"]
        D1["数据块 1: 256MB"]
        D2["数据块 2: 256MB"]
        D3["数据块 3: 256MB"]
        D4["数据块 4: 256MB"]
        P1["校验块 1: 256MB"]
        P2["校验块 2: 256MB"]
        ECNote["总存储: 1.5GB<br/>存储效率: 67%<br/>容忍故障: 2 节点"]
    end
维度三副本纠删码 (4+2)纠删码 (8+4)
存储效率33%67%67%
容忍故障数224
读性能高(任一副本)中(需读 k 块)中
写性能中(写 3 份)低(编码计算)低
修复开销低(复制 1 份)高(需读 k 块重算)高
适用热数据、小文件温/冷数据、大文件归档数据

纠删码工作原理 ​

Reed-Solomon 编码(最常用):

原始数据: D1, D2, D3, D4 (4 个数据块)
编码矩阵 × 数据向量 = 编码向量

┌     ┐   ┌    ┐   ┌    ┐
│ 1 0 0 0 │   │ D1 │   │ D1 │  ← 数据块(原样保留)
│ 0 1 0 0 │   │ D2 │   │ D2 │
│ 0 0 1 0 │ × │ D3 │ = │ D3 │
│ 0 0 0 1 │   │ D4 │   │ D4 │
│ a b c d │   │    │   │ P1 │  ← 校验块(线性组合)
│ e f g h │   │    │   │ P2 │
└     ┘   └    ┘   └    ┘

恢复:任意丢失 2 块,用剩余 4 块 + 逆矩阵恢复

实际实现:
  - Intel ISA-L 库(SIMD 加速,吞吐 10GB/s+)
  - MinIO 使用 Go 实现 + SIMD 优化
  - AWS S3 内部使用自研纠删码

对象存储中的纠删码应用 ​

AWS S3 Standard:
  跨 3 个 AZ,每个 AZ 内部使用纠删码
  → 11 个 9 的持久性 (99.999999999%)

腾讯云 COS:
  标准存储: 跨 AZ 纠删码
  归档存储: 更高冗余度的纠删码(容忍更多故障)

MinIO (自建):
  默认 EC:4(4 数据 + 4 校验,50% 效率)
  可配置 EC:2 到 EC:8

十一、分片上传性能调优 ​

分片大小选择 ​

分片大小直接影响上传性能,需要根据网络带宽和文件大小权衡:

文件大小推荐分片大小分片数原因
5MB - 100MB5MB1-20小文件,分片开销不值得
100MB - 1GB16-32MB4-64平衡并发和开销
1GB - 10GB64-128MB8-160减少分片数,降低 Complete 开销
10GB+128-256MB40-80大分片减少 HTTP 请求数

并发上传调优 ​

go
// Go SDK 分片上传最佳实践
type UploadConfig struct {
    PartSize    int64 // 分片大小
    Concurrency int   // 并发数
    MaxRetries  int   // 单片重试次数
}

// 根据网络带宽自适应配置
func OptimalConfig(fileSize int64, bandwidthMbps int) UploadConfig {
    // 分片大小:确保每片上传时间 2-10 秒(避免超时)
    partUploadTime := 5 * time.Second
    partSize := int64(bandwidthMbps) * 1024 * 1024 / 8 * int64(partUploadTime.Seconds())

    // 限制范围
    if partSize < 5*1024*1024 {
        partSize = 5 * 1024 * 1024  // 最小 5MB
    }
    if partSize > 256*1024*1024 {
        partSize = 256 * 1024 * 1024  // 最大 256MB
    }

    // 并发数:带宽 / 单片带宽,但不超过 CPU 核数
    concurrency := bandwidthMbps / (int(partSize) * 8 / 1024 / 1024 / 5)
    if concurrency < 2 {
        concurrency = 2
    }
    if concurrency > runtime.NumCPU()*2 {
        concurrency = runtime.NumCPU() * 2
    }

    return UploadConfig{
        PartSize:    partSize,
        Concurrency: concurrency,
        MaxRetries:  3,
    }
}

性能对比数据 ​

测试环境:1Gbps 带宽,上传 5GB 文件到 COS

┌──────────────────────────────────────────────────┐
│ 分片大小 │ 并发数 │ 耗时    │ 实际带宽利用率    │
├──────────┼────────┼─────────┼──────────────────┤
│ 5MB      │ 4      │ 180s    │ 22%(HTTP 开销大)│
│ 16MB     │ 4      │ 85s     │ 47%              │
│ 64MB     │ 4      │ 52s     │ 77%              │
│ 64MB     │ 8      │ 45s     │ 89%              │
│ 128MB    │ 8      │ 43s     │ 93%  ← 最优      │
│ 256MB    │ 8      │ 44s     │ 91%(单片失败代价大)│
└──────────────────────────────────────────────────┘

结论:
  - 分片太小 → HTTP 请求开销占比大
  - 分片太大 → 单片失败重传代价大
  - 最优点:单片上传时间 3-8 秒

断点续传实现 ​

go
// 断点续传核心逻辑
type UploadCheckpoint struct {
    UploadID    string            `json:"upload_id"`
    FilePath    string            `json:"file_path"`
    FileSize    int64             `json:"file_size"`
    FileModTime time.Time         `json:"file_mod_time"`
    PartSize    int64             `json:"part_size"`
    Parts       []CompletedPart   `json:"parts"`  // 已完成的分片
}

func ResumeUpload(checkpoint *UploadCheckpoint) error {
    // 1. 验证文件未被修改
    info, _ := os.Stat(checkpoint.FilePath)
    if info.Size() != checkpoint.FileSize || info.ModTime() != checkpoint.FileModTime {
        return errors.New("file changed, restart upload")
    }

    // 2. 查询已上传的分片(ListParts)
    uploaded := listParts(checkpoint.UploadID)

    // 3. 只上传缺失的分片
    totalParts := (checkpoint.FileSize + checkpoint.PartSize - 1) / checkpoint.PartSize
    for i := int64(0); i < totalParts; i++ {
        if !isPartUploaded(uploaded, i+1) {
            uploadPart(checkpoint.UploadID, i+1, checkpoint.PartSize)
        }
    }

    // 4. Complete
    return completeMultipartUpload(checkpoint.UploadID)
}
批注模式

💬 文章评论

暂无评论,来说点什么吧 👇

编程学习笔记