简介

Amazon Simple Storage Service(S3)是 AWS 的对象存储服务,用于存储任意类型的文件(备份、静态资源、日志等),按实际使用量计费。

核心概念:

  • Bucket:存储桶,名字在全球所有 AWS 账号、所有区域共享同一命名空间,全球唯一
  • Object:对象,即一个文件,由 Key(路径)+ 数据 + 元数据组成
  • Key:对象的唯一标识符,形如 path/to/file.txt,只需在桶内唯一(S3 本身是扁平结构,/ 只是命名惯例)
概念 唯一性范围
Bucket 名字 全球唯一(跨账号、跨区域)
Object Key 桶内唯一
数据存储位置 只在创建时指定的区域

区域与高可用

Bucket 在创建时必须指定区域(如 ap-northeast-1 东京),之后无法更改,数据默认只存在于该区域。

S3 在同一个区域内会把数据自动分散到至少 3 个可用区(AZ),设计耐久性是 99.999999999%(11 个 9)。区域内某个数据中心故障,数据不受影响。

如果整个区域发生故障(极罕见),默认情况下无法从其他区域访问该桶的数据。如需跨区域容灾,要显式配置 Cross-Region Replication(CRR):

东京桶(主)  --CRR--> 新加坡桶(副本)

CRR 要求两个桶都开启版本控制(Versioning),并配置 IAM Role 授权跨桶复制权限。

实践建议:用于数据库备份等灾难恢复场景,单区域已经足够,无需配置 CRR。若担心区域级故障,更简单的做法是用 aws s3 sync 定期同步到另一个区域,或下载到本地存一份。

常用命令

# 列出所有 bucket
aws s3 ls

# 列出 bucket 内的对象
aws s3 ls s3://my-bucket/
aws s3 ls s3://my-bucket/prefix/

# 上传文件
aws s3 cp local-file.txt s3://my-bucket/path/file.txt

# 下载文件
aws s3 cp s3://my-bucket/path/file.txt local-file.txt

# 同步目录(本地 → S3)
aws s3 sync ./local-dir s3://my-bucket/prefix/

# 同步目录(S3 → 本地)
aws s3 sync s3://my-bucket/prefix/ ./local-dir

# 删除对象
aws s3 rm s3://my-bucket/path/file.txt

# 删除 prefix 下所有对象
aws s3 rm s3://my-bucket/prefix/ --recursive

Bucket 管理

# 创建 bucket(指定区域)
aws s3api create-bucket \
  --bucket my-bucket \
  --region ap-northeast-1 \
  --create-bucket-configuration LocationConstraint=ap-northeast-1

# 删除 bucket(必须先清空)
aws s3 rm s3://my-bucket --recursive
aws s3api delete-bucket --bucket my-bucket

# 查看 bucket 所在区域
aws s3api get-bucket-location --bucket my-bucket

生命周期策略(Lifecycle)

用于自动过期或转换存储类型,节省费用。

{
  "Rules": [
    {
      "ID": "expire-old-backups",
      "Status": "Enabled",
      "Filter": {},
      "Expiration": {
        "Days": 30
      }
    }
  ]
}
# 应用生命周期规则
aws s3api put-bucket-lifecycle-configuration \
  --bucket my-bucket \
  --lifecycle-configuration file://lifecycle.json

# 查看当前规则
aws s3api get-bucket-lifecycle-configuration --bucket my-bucket

IAM 权限控制

最小权限策略示例(只允许写入指定 bucket)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:DeleteObject"
      ],
      "Resource": [
        "arn:aws:s3:::my-bucket",
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}

EC2 通过 IAM Instance Profile 访问 S3

EC2 实例绑定 IAM Role 后,实例内的程序可以直接使用 aws CLI 或 SDK 访问 S3,无需配置 Access Key。

# 在绑定了 Instance Profile 的 EC2 上,直接可用
aws s3 ls s3://my-bucket/

费用

S3 费用分三块独立计费,以东京区域(ap-northeast-1)标准存储类为例:

存储费用

按实际存储的数据量每月计费:

存储类 费用 适用场景
Standard(标准) $0.025 / GB / 月 频繁访问
Standard-IA(低频访问) $0.0138 / GB / 月 每月访问几次
Glacier Instant Retrieval $0.005 / GB / 月 归档,毫秒级取回
Glacier Flexible Retrieval $0.0045 / GB / 月 归档,分钟~小时取回

请求费用

每次 API 调用单独计费:

操作 费用
PUT / COPY / POST(写) $0.0047 / 1000 次
GET / SELECT(读) $0.00037 / 1000 次
LIST $0.0047 / 1000 次
DELETE 免费

数据传出费用

流量方向 费用
互联网 → S3(上传) 免费
S3 → 同区域 EC2 免费
S3 → 互联网(下载) $0.114 / GB
S3 → 其他 AWS 区域 $0.02 / GB

备份上传免费,平时不下载则流量费为零,只有恢复数据时才产生下载费用。

实际费用估算

以 enx-api 备份场景为例(DB 文件 10 MB,保留 30 天,每日备份一次):

费用项 计算 金额
存储 300 MB × $0.025/GB ~$0.0075 / 月
PUT 请求 30 次 × $0.0047/1000 ~$0.00014 / 月
流量 上传免费 $0
合计 < $0.01 / 月

阻止公开访问

创建 bucket 后建议立即开启全部 Block Public Access 选项,防止误配置导致数据泄露:

aws s3api put-public-access-block \
  --bucket my-bucket \
  --public-access-block-configuration \
    "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

实践案例:SQLite 数据库每日备份

enx-api 项目使用 systemd timer + aws cli 将 SQLite 数据库每日自动备份到 S3:

# 热备份(DB 使用中也安全)
sqlite3 /var/lib/enx-api/enx.db ".backup '/tmp/backup.db'"

# 上传到 S3
aws s3 cp /tmp/backup.db s3://wiloon-enx-backup/enx-api-$(date +%Y%m%d-%H%M%S).db

Bucket 配置了 30 天生命周期自动过期。详见 enx-api 数据库备份文档。