本文系统梳理对象存储与 CDN 的核心知识,涵盖架构原理、主流产品实战、文件上传方案、CDN 配置、成本优化与监控运维。适合中后端工程师和运维人员快速上手。


一、对象存储基础

1.1 架构原理

对象存储(Object Storage)是一种扁平化、分布式的存储架构,与传统文件系统(层级目录)和块存储(裸磁盘)有本质区别:

传统文件系统:  /data/images/2024/avatar.jpg  → 逐级寻址
块存储:       LUN → Block 0~N               → 随机读写
对象存储:     Bucket + Key + Data + Metadata → HTTP RESTful 访问

核心特征:

特性

说明

扁平命名空间

无目录层级,Key 全局唯一(路径由 Key 前缀模拟)

RESTful API

通过 HTTP 接口操作,天然适合云和分布式场景

无限扩展

自动横向扩容,无需预分配容量

高持久性

通常 11 个 9(99.999999999%),多副本/纠删码

丰富元数据

可附加自定义键值对、Content-Type、ACL 等

1.2 主流产品对比

维度

阿里云 OSS

AWS S3

MinIO

腾讯云 COS

华为云 OBS

部署模式

公有云

公有云

私有/混合

公有云

公有云

API 兼容

自有 + S3 兼容

原生 S3

S3 兼容

S3 兼容

S3 兼容

免费额度

5GB/月

5GB/12月

开源免费

10GB/月

5GB/月

最大对象

48.8TB

5TB

5TB

50TB

50TB

存储类型

标准/低频/归档/冷归档

S3 Standard/IA/Glacier

单一

标准/低频/归档/深度归档

标准/低频/归档

生态集成

非常丰富

最丰富

K8s/容器友好

丰富

丰富


二、MinIO 实战

2.1 安装部署

单节点快速启动(Docker):

# 创建数据目录
mkdir -p /data/minio/{data,config}

# 启动 MinIO
docker run -d \
  --name minio \
  -p 9000:9000 \
  -p 9001:9001 \
  -e "MINIO_ROOT_USER=admin" \
  -e "MINIO_ROOT_PASSWORD=YourStr0ngP@ssword!" \
  -v /data/minio/data:/data \
  -v /data/minio/config:/root/.minio \
  minio/minio server /data --console-address ":9001"

# 访问管理控制台: http://<IP>:9001

systemd 服务化部署(生产推荐):

# /etc/systemd/system/minio.service
[Unit]
Description=MinIO Object Storage
After=network.target

[Service]
User=minio
Group=minio
Type=simple
Environment="MINIO_ROOT_USER=admin"
Environment="MINIO_ROOT_PASSWORD=YourStr0ngP@ssword!"
ExecStart=/usr/local/bin/minio server /data/minio --console-address ":9001"
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now minio

2.2 mc 客户端

# 安装 mc
curl -O https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc && mv mc /usr/local/bin/

# 配置别名
mc alias set myminio http://localhost:9000 admin 'YourStr0ngP@ssword!'

# 基本操作
mc mb myminio/avatars                    # 创建桶
mc cp ./photo.jpg myminio/avatars/       # 上传文件
mc ls myminio/avatars/                   # 列出文件
mc cat myminio/avatars/photo.jpg         # 下载到 stdout
mc rm myminio/avatars/photo.jpg          # 删除文件
mc mirror ./dist/ myminio/website/       # 同步目录
mc share download myminio/avatars/photo.jpg  # 生成临时下载链接

2.3 桶管理与策略

# 设置桶为公开读
mc anonymous set download myminio/avatars

# 查看桶策略
mc anonymous get myminio/avatars

# 设置生命周期(7天后过期)
cat > lifecycle.json << 'EOF'
{
  "Rules": [
    {
      "ID": "expire-7d",
      "Status": "Enabled",
      "Expiration": { "Days": 7 },
      "Filter": { "Prefix": "tmp/" }
    }
  ]
}
EOF
mc ilm import myminio/avatars < lifecycle.json

# 版本控制
mc version enable myminio/avatars
mc version info myminio/avatars

2.4 MinIO 集群(纠删码模式)

4 节点 4 磁盘部署(分布式模式):

# 在每个节点准备数据目录
mkdir -p /data/minio-disk{1,4}

# 启动命令(所有节点相同)
minio server \
  http://node1/data/minio-disk{1...4} \
  http://node2/data/minio-disk{1...4} \
  http://node3/data/minio-disk{1...4} \
  http://node4/data/minio-disk{1...4}

纠删码原理: 4 节点 × 4 磁盘 = 16 块数据,每 4 块编码产生 4 块校验,最多允许同时损坏 4 块而不丢数据。生产环境建议至少 4 节点。


三、阿里云 OSS 实战

3.1 SDK 使用(Python)

import oss2

# 初始化客户端
auth = oss2.Auth('LTAI5txxxxxxxxxxxx', 'YourAccessKeySecret')
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'my-bucket')

# 上传文件
bucket.put_object('images/photo.jpg', open('photo.jpg', 'rb'),
                  headers={'Content-Type': 'image/jpeg'})

# 分片上传(大文件)
oss2.resumable_upload(bucket, 'videos/movie.mp4', 'movie.mp4',
                      store=oss2.ObjectStore(),
                      part_size=10 * 1024 * 1024,  # 10MB 分片
                      num_threads=4)

# 生成签名 URL(临时访问)
url = bucket.sign_url('GET', 'images/photo.jpg', 3600)  # 1小时有效
print(url)

# 列举文件
for obj in oss2.ObjectIterator(bucket, prefix='images/'):
    print(f'{obj.key}  {obj.size}  {obj.last_modified}')

3.2 防盗链配置

通过控制台或 API 设置 Referer 白名单:

# 通过 ossutil 设置
ossutil cors put oss://my-bucket cors.xml
<!-- cors.xml -->
<CORSConfiguration>
  <CORSRule>
    <AllowedOrigin>https://www.example.com</AllowedOrigin>
    <AllowedOrigin>https://cdn.example.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
    <MaxAgeSeconds>86400</MaxAgeSeconds>
  </CORSRule>
</CORSConfiguration>

Referer 白名单(控制台):

  • Bucket → 权限管理 → 防盗链 → 设置空 Referer 拒绝

  • 白名单添加:*.example.com

3.3 生命周期规则

{
  "Rules": [
    {
      "ID": "auto-archive",
      "Status": "Enabled",
      "Prefix": "logs/",
      "Transitions": [
        { "Days": 30, "StorageClass": "IA" },
        { "Days": 90, "StorageClass": "Archive" }
      ],
      "Expiration": { "Days": 365 }
    },
    {
      "ID": "abort-multipart",
      "Status": "Enabled",
      "Prefix": "",
      "AbortMultipartUpload": { "Days": 7 }
    }
  ]
}

四、AWS S3 实战

4.1 CLI 操作

# 安装 AWS CLI
pip install awscli
aws configure  # 输入 Access Key / Secret Key / Region

# 桶操作
aws s3 mb s3://my-bucket --region us-east-1
aws s3 ls
aws s3 ls s3://my-bucket --recursive --human-readable

# 文件操作
aws s3 cp ./file.txt s3://my-bucket/
aws s3 cp ./dist/ s3://my-bucket/static/ --recursive
aws s3 sync ./dist/ s3://my-bucket/static/ --delete
aws s3 rm s3://my-bucket/tmp/ --recursive

# 生成预签名 URL
aws s3 presign s3://my-bucket/file.txt --expires-in 3600

4.2 存储桶策略

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadForStaticAssets",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/static/*"
    },
    {
      "Sid": "DenyUnencryptedUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "AES256"
        }
      }
    }
  ]
}

4.3 版本控制

# 开启版本控制
aws s3api put-bucket-versioning \
  --bucket my-bucket \
  --versioning-configuration Status=Enabled

# 查看对象的所有版本
aws s3api list-object-versions --bucket my-bucket

# 恢复到指定版本
aws s3api copy-object \
  --bucket my-bucket \
  --key config/app.yml \
  --copy-source my-bucket/config/app.yml?versionId=abc123

4.4 Glacier 归档

# 创建生命周期规则,自动迁移到 Glacier
aws s3api put-bucket-lifecycle-configuration \
  --bucket my-bucket \
  --lifecycle-configuration '{
    "Rules": [
      {
        "ID": "archive-old-logs",
        "Filter": { "Prefix": "logs/" },
        "Status": "Enabled",
        "Transitions": [
          { "Days": 30, "GlacierStorageTier": true }
        ],
        "Expiration": { "Days": 365 }
      }
    ]
  }'

# 从 Glacier 恢复(需要先发起请求,等待数小时)
aws s3api restore-object \
  --bucket my-bucket \
  --key logs/2024-01.log \
  --restore-request '{"Days":5,"GlacierJobParameters":{"Tier":"Standard"}}'

五、文件上传方案

5.1 前端直传(推荐方案)

架构: 前端 → 预签名 URL → 直传 OSS/S3,不经过应用服务器

前端请求签名 → 后端生成预签名 URL → 前端直传对象存储

后端生成预签名 URL(Python Flask):

from flask import Flask, jsonify
import boto3

app = Flask(__name__)
s3 = boto3.client('s3')

@app.route('/api/upload/presign', methods=['POST'])
def presign():
    key = f"uploads/{uuid4()}.jpg"
    url = s3.generate_presigned_url(
        'put_object',
        Params={
            'Bucket': 'my-bucket',
            'Key': key,
            'ContentType': 'image/jpeg',
        },
        ExpiresIn=300  # 5 分钟有效
    )
    return jsonify({
        'upload_url': url,
        'key': key,
        'access_url': f'https://cdn.example.com/{key}'
    })

前端上传:

async function uploadFile(file) {
  // 1. 获取预签名 URL
  const { data } = await axios.post('/api/upload/presign', {
    filename: file.name,
    contentType: file.type
  });

  // 2. 直传到 OSS/S3
  await axios.put(data.upload_url, file, {
    headers: { 'Content-Type': file.type }
  });

  // 3. 使用 CDN 域名访问
  return data.access_url;
}

5.2 分片上传

大文件(>100MB)建议分片上传,支持断点续传:

import boto3
from boto3.s3.transfer import TransferConfig

s3 = boto3.client('s3')

# 配置分片参数
config = TransferConfig(
    multipart_threshold=100 * 1024 * 1024,  # 100MB
    max_concurrency=10,
    multipart_chunksize=50 * 1024 * 1024,   # 50MB
)

# 使用 boto3 的高层 API
s3_resource = boto3.resource('s3')
s3_resource.Bucket('my-bucket').upload_file(
    'large-video.mp4',
    'videos/large-video.mp4',
    Config=config,
    ExtraArgs={'ContentType': 'video/mp4'}
)

手动分片(精细控制):

# 1. 初始化分片上传
resp = s3.create_multipart_upload(Bucket='my-bucket', Key='videos/big.mp4')
upload_id = resp['UploadId']

# 2. 上传各分片
parts = []
with open('big.mp4', 'rb') as f:
    part_num = 1
    while chunk := f.read(50 * 1024 * 1024):
        resp = s3.upload_part(
            Bucket='my-bucket', Key='videos/big.mp4',
            UploadId=upload_id, PartNumber=part_num, Body=chunk
        )
        parts.append({'PartNumber': part_num, 'ETag': resp['ETag']})
        part_num += 1

# 3. 完成分片上传
s3.complete_multipart_upload(
    Bucket='my-bucket', Key='videos/big.mp4',
    UploadId=upload_id,
    MultipartUpload={'Parts': parts}
)

5.3 预签名 URL 最佳实践

# 限制上传大小(通过 Content-Length 范围)
url = s3.generate_presigned_url(
    'put_object',
    Params={
        'Bucket': 'my-bucket',
        'Key': 'uploads/user-avatar.jpg',
        'ContentType': 'image/jpeg',
        'ContentLengthRange': [1024, 10 * 1024 * 1024],  # 1KB~10MB
    },
    ExpiresIn=300
)

安全要点:

  • 预签名 URL 有效期尽量短(5~15 分钟)

  • 限制上传文件类型和大小

  • 使用独立的 IAM 用户/角色,权限最小化

  • 上传完成后回调后端校验


六、CDN 基础

6.1 工作原理

用户请求 → DNS 调度 → 最近边缘节点 → 有缓存? → 直接返回
                                            ↓ 无缓存
                                      回源到源站 → 缓存到边缘 → 返回用户

核心概念:

术语

说明

边缘节点(Edge)

全球分布的缓存服务器,离用户最近

回源(Origin Pull)

边缘节点向源站请求内容

源站(Origin)

实际存储内容的服务器/对象存储

CNAME

将自定义域名解析到 CDN 域名

缓存命中率

边缘直接返回的请求占比

6.2 缓存策略

缓存优先级: Cache-Control 响应头 > CDN 控制台配置 > 默认规则

# 常见 Cache-Control 头
Cache-Control: max-age=31536000, immutable    # 静态资源(1年,不可变)
Cache-Control: max-age=3600, must-revalidate  # API 响应(1小时)
Cache-Control: no-cache                       # 每次验证
Cache-Control: no-store                       # 不缓存

推荐缓存策略:

资源类型

缓存时间

Cache-Control

说明

静态 JS/CSS(带 hash)

1年

max-age=31536000, immutable

文件名含 hash,内容变则 URL 变

图片

30天~1年

max-age=2592000

按业务需求调整

HTML 入口

不缓存或短缓存

no-cache / max-age=300

避免用户看到旧版

API 响应

不缓存

no-store

动态内容

字体文件

1年

max-age=31536000

很少变更

6.3 回源策略

# Nginx 作为源站时的典型配置
location ~* \.(js|css|png|jpg|gif|ico|svg|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Access-Control-Allow-Origin "*";
}

# CDN 回源时隐藏源站 IP
# 对象存储作为源站时天然实现

七、CDN 配置实战

7.1 阿里云 CDN

域名配置流程:

# 1. 添加加速域名
#    控制台 → CDN → 域名管理 → 添加域名
#    加速域名:cdn.example.com
#    源站类型:OSS 域名
#    源站地址:my-bucket.oss-cn-hangzhou.aliyuncs.com

# 2. 配置 CNAME(DNS)
#    cdn.example.com → cdn.example.com.w.kunlunsl.com

# 3. 验证 CNAME 生效
dig cdn.example.com +short
# 应返回 CDN 分配的域名

# 4. 缓存配置(通过控制台或 API)
# 静态资源:jpg|png|gif|css|js → 缓存30天
# HTML:html → 不缓存或缓存5分钟

阿里云 CDN API 操作:

# 刷新缓存(内容更新后必须执行)
aliyun cdn RefreshObjectCaches \
  --ObjectPath "https://cdn.example.com/css/app.css" \
  --ObjectType File

# 预热缓存(提前回源到边缘)
aliyun cdn PushObjectCache \
  --ObjectPath "https://cdn.example.com/images/hero.jpg"

# 查询刷新状态
aliyun cdn DescribeRefreshTaskById --TaskId 12345678

7.2 Cloudflare 配置

免费计划即可使用的基础配置:

// Cloudflare Page Rules(免费计划限3条)

// 规则1:静态资源长缓存
// URL: cdn.example.com/assets/*
// 设置:Cache Level = Cache Everything, Edge Cache TTL = 1 month

// 规则2:HTML 短缓存
// URL: cdn.example.com/*
// 设置:Browser Cache TTL = 30 minutes, Always Online = On

Cloudflare Workers(边缘计算):

// worker.js - 自定义缓存逻辑
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)
  
  // 图片自动优化
  if (url.pathname.match(/\.(jpg|png|gif)$/i)) {
    const imageUrl = url.href
    // 使用 Cloudflare Image Resizing
    const resizeUrl = `/cdn-cgi/image/width=800,quality=80,format=webp${url.pathname}`
    
    const response = await fetch(resizeUrl, request)
    const headers = new Headers(response.headers)
    headers.set('Cache-Control', 'public, max-age=31536000, immutable')
    
    return new Response(response.body, {
      status: response.status,
      headers
    })
  }
  
  return fetch(request)
}

7.3 腾讯云 CDN

# 刷新 URL
tccli cdn PurgePathCache --Paths '["https://cdn.example.com/css/"]' --FlushType flush

# 预热
tccli cdn PushUrlsCache --Urls '["https://cdn.example.com/index.html"]'

腾讯云 CDN + COS 组合配置:

# 1. COS 开启默认 CDN 加速域名
#    COS 控制台 → 基础配置 → CDN 加速

# 2. 绑定自定义域名
#    COS 控制台 → 基础配置 → 自定义域名 → cdn.example.com

# 3. 配置回源 host 为 COS 域名
#    my-bucket-1250000000.cos.ap-guangzhou.myqcloud.com

八、静态资源加速

8.1 前端部署方案

方案一:对象存储 + CDN(经典方案)

# 构建前端项目
npm run build

# 上传到 OSS/ S3
aws s3 sync ./dist/ s3://my-bucket/static/v2/ \
  --cache-control "public, max-age=31536000, immutable" \
  --exclude "*.html"

# HTML 不缓存
aws s3 sync ./dist/ s3://my-bucket/ \
  --cache-control "no-cache" \
  --include "*.html"

方案二:使用 ossutil(阿里云)批量上传

# 设置缓存头
ossutil cp -r ./dist/ oss://my-bucket/static/ \
  --include "*.js,*.css,*.png,*.jpg" \
  --meta "Cache-Control:public,max-age=31536000,immutable" \
  --jobs 8

# HTML 文件单独处理
ossutil cp -r ./dist/ oss://my-bucket/ \
  --include "*.html" \
  --meta "Cache-Control:no-cache"

8.2 图片处理

阿里云 OSS 图片处理:

# 原图 URL
https://cdn.example.com/photo.jpg

# 缩放 + 格式转换 + 质量
https://cdn.example.com/photo.jpg?x-oss-process=image/resize,w_800/format,webp/quality,q_80

# 裁剪
https://cdn.example.com/photo.jpg?x-oss-process=image/crop,w_400,h_400,x_100,y_100

# 水印(Base64 编码文字)
https://cdn.example.com/photo.jpg?x-oss-process=image/watermark,text_SGVsbG8,size_30

S3 + Lambda@Edge 图片处理:

# lambda-edge-resize.py
import boto3
import json
from PIL import Image
import io

def handler(event, context):
    request = event['Records'][0]['cf']['request']
    uri = request['uri']
    
    # 解析参数: /800x600/image.jpg
    parts = uri.strip('/').split('/')
    if len(parts) >= 2 and 'x' in parts[0]:
        width, height = parts[0].split('x')
        key = '/'.join(parts[1:])
        
        # 从 S3 获取原图
        s3 = boto3.client('s3')
        obj = s3.get_object(Bucket='images-bucket', Key=key)
        img = Image.open(obj['Body'])
        
        # 缩放
        img.thumbnail((int(width), int(height)), Image.LANCZOS)
        buffer = io.BytesIO()
        img.save(buffer, format='WEBP', quality=80)
        
        return {
            'status': '200',
            'headers': {
                'content-type': [{'key': 'Content-Type', 'value': 'image/webp'}],
                'cache-control': [{'key': 'Cache-Control', 'value': 'max-age=31536000'}]
            },
            'body': base64.b64encode(buffer.getvalue()).decode(),
            'bodyEncoding': 'base64'
        }
    
    return request  # 无参数则原样返回

8.3 视频加速

视频点播 + CDN 方案:

# 视频上传并触发转码(阿里云 VOD)
import oss2

def upload_and_transcode(video_path, title):
    # 1. 上传原始视频
    bucket.put_object(f'videos/raw/{title}.mp4', open(video_path, 'rb'))
    
    # 2. 通过 VOD API 触发转码
    # 转码模板:HLS + 多码率(360p/720p/1080p)
    transcode_config = {
        'TemplateGroupId': 'your-template-group-id',
        'Output': {
            'Bucket': 'my-vod-bucket',
            'Location': 'oss-cn-hangzhou'
        }
    }
    # 调用 VOD API 创建转码任务...
    
    # 3. 生成播放地址
    # HLS: https://cdn.example.com/videos/title/360p.m3u8
    return f'https://cdn.example.com/videos/{title}/1080p.m3u8'

HLS 播放配置:

# 源站 Nginx 配置 HLS 流
location ~* \.m3u8$ {
    add_header Cache-Control "no-cache";
    add_header Access-Control-Allow-Origin "*";
}

location ~* \.ts$ {
    expires 1d;
    add_header Cache-Control "public";
}

九、成本优化

9.1 存储成本

# 分析存储用量
aws s3api list-buckets --query 'Buckets[].Name' --output text | \
  xargs -I {} aws s3 ls s3://{} --recursive --summarize | \
  grep "Total Size"

# 查找大文件
aws s3 ls s3://my-bucket --recursive --summarize | \
  sort -k3 -rn | head -20

存储类型优化策略:

数据类型

存储类型

成本(约)

适用场景

频繁访问

标准存储

¥0.12/GB/月

网站图片、API 数据

偶尔访问

低频存储

¥0.08/GB/月

日志、历史数据

归档

归档存储

¥0.033/GB/月

合规备份

深度归档

冷归档

¥0.015/GB/月

长期保留

生命周期自动转换示例:

{
  "Rules": [
    {
      "ID": "cost-optimize",
      "Status": "Enabled",
      "Transitions": [
        { "Days": 30, "StorageClass": "STANDARD_IA" },
        { "Days": 90, "StorageClass": "GLACIER" }
      ],
      "NoncurrentVersionTransitions": [
        { "NoncurrentDays": 7, "StorageClass": "STANDARD_IA" }
      ],
      "NoncurrentVersionExpiration": { "NoncurrentDays": 30 }
    }
  ]
}

9.2 流量成本

# CDN 流量监控(阿里云)
aliyun cdn DescribeDomainFlowData \
  --DomainName cdn.example.com \
  --StartTime "2024-01-01T00:00:00Z" \
  --EndTime "2024-01-31T23:59:59Z"

节省流量的实用技巧:

  1. 启用 Gzip/Brotli 压缩: JS/CSS 可减少 60~80% 体积

  2. 图片格式优化: WebP 比 JPEG 小 25~35%,AVIF 更优

  3. 合理设置缓存: 提高命中率,减少回源

  4. 使用 CDN 节省带宽: CDN 流量费通常低于源站直接出口

# Nginx 开启 Brotli 压缩
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript 
             text/xml application/xml image/svg+xml;

9.3 请求成本

# 减少不必要的 LIST 请求
# 差量同步替代全量扫描
aws s3 sync ./dist/ s3://my-bucket/static/ --size-only

# 使用 S3 Inventory 替代频繁 LIST
aws s3api put-bucket-inventory-configuration \
  --bucket my-bucket \
  --id daily-inventory \
  --inventory-configuration '{
    "Destination": {
      "S3BucketDestination": {
        "Bucket": "arn:aws:s3:::inventory-bucket",
        "Format": "CSV"
      }
    },
    "IsEnabled": true,
    "Schedule": { "Frequency": "Daily" },
    "Filter": { "Prefix": "" },
    "IncludedObjectVersions": "Current"
  }'

十、监控与运维

10.1 存储监控

# MinIO 监控指标(Prometheus 格式)
curl http://localhost:9000/minio/v2/metrics/cluster

# 关键指标
# minio_cluster_capacity_free_bytes       - 可用空间
# minio_cluster_capacity_total_bytes      - 总容量
# minio_s3_requests_total                 - 请求总数
# minio_s3_requests_errors_total          - 错误数
# minio_s3_ttfb_seconds_distribution      - 首字节时间

Prometheus + Grafana 监控配置:

# prometheus.yml
scrape_configs:
  - job_name: 'minio'
    metrics_path: /minio/v2/metrics/cluster
    scheme: http
    static_configs:
      - targets: ['minio:9000']
        labels:
          cluster: 'prod'

10.2 CDN 监控

# 关键监控指标
# - 带宽峰值
# - 流量消耗
# - 缓存命中率(目标 > 90%)
# - 回源率(越低越好)
# - 状态码分布(关注 4xx/5xx 比例)
# - P95 延迟

# 阿里云 CDN 查询(CLI)
aliyun cdn DescribeDomainBpsData \
  --DomainName cdn.example.com \
  --StartTime "2024-01-01T00:00:00Z" \
  --EndTime "2024-01-01T23:59:59Z" \
  --Interval 300

10.3 告警配置

# 阿里云告警规则示例
# 当 CDN 缓存命中率低于 85% 时告警
MetricName: ByteHitRate
ComparisonOperator: LessThanThreshold
Threshold: 85
Period: 300
EvaluationCount: 3

# 当存储空间使用率超过 80% 时告警
MetricName: StorageUtilization
ComparisonOperator: GreaterThanThreshold
Threshold: 80

10.4 运维 Checklist

□ 定期检查存储用量和增长趋势
□ 确认生命周期规则正常执行
□ 验证 CDN 缓存命中率(>90%)
□ 检查回源带宽和延迟
□ 审查 IAM 权限(最小权限原则)
□ 验证备份和恢复流程
□ 检查 CORS 配置安全性
□ 确认防盗链/Referer 配置
□ 监控异常流量(DDoS/CC 防护)
□ 更新和轮换 Access Key
□ 检查分片上传的未完成任务
□ 验证跨区域复制状态(如有)

附录:常用工具速查

工具

用途

安装

ossutil

阿里云 OSS 命令行

curl -o ossutil https://gosspublic.alicdn.com/ossutil/1.7.19/ossutil-v1.7.19-linux-amd64/ossutil64

aws cli

AWS S3 命令行

pip install awscli

mc

MinIO 客户端

curl -O https://dl.min.io/client/mc/release/linux-amd64/mc

s3cmd

S3 兼容命令行

apt install s3cmd

rclone

多云存储同步

curl https://rclone.org/install.sh | bash

rclone 多云同步示例:

# 配置多云端点
rclone config
# → 阿里云 OSS: alias=oss
# → AWS S3:     alias=aws
# → MinIO:      alias=minio

# 跨云同步
rclone sync oss:my-bucket/images/ aws:my-bucket/images/ --progress
rclone sync minio:avatars/ oss:backup-bucket/avatars/ --transfers 8

本文为《服务器运维笔记》系列第 26 篇。对象存储与 CDN 是现代 Web 架构的基石,合理配置可以显著降低成本、提升用户体验。