存储服务

AWS 常见三种存储服务:

  1. Amazon Elastic Block Store(EBS 弹性块存储)
  2. Amazon Simple Storage Service(简称 S3 对象存储)
  3. Amazon Elastic File System(EFS 文件存储)

EBS 存储

借助 EBS,可以创建个人存储卷并将其挂载到 Amazon EC2 实例上。

说明 EC2 的硬盘存储设备可以是 EBS。

主要功能:

  • EBS 提供数据块存储
  • 卷自动在其可用区中进行复制(可用性极高)
  • 可自动备份到 Amazon S3 中

使用场景:

  1. 针对 Amazon EC2 实例的启动卷和存储
  2. 具有文件系统的数据存储
  3. 数据库主机
  4. 企业应用服务

EBS 有两种存储类型,他的区别和使用场景如下:

image-20240302095426110

EBS 作为一种实例的硬盘,往往是不能共享的。

但 IOPS 可以多实例共享,且预配置保证每秒 64000 的 IOPS,所以价格也是最贵的。

其他 EBS 类型均不可多实例共享。

其他特点:

  1. 快照:EBC 可以设置时间点快照,并随时重新创建新卷。快照可以备份到 S3 中。快照可以跨 region 进行复制,具有容灾作用。

  2. 加密:EBS 卷可以加密,无额外成本。

    有两种方式实现加密:

    • 创建一个加密 EBS 卷,将普通卷的内容复制进去。
    • 给普通卷创建快照,然后加密快照,最后由快照生成加密卷。
  3. 弹性:随时增加容量,更改为不同类型。

S3 对象存储

Amazon S3 (Simple Storage Service) 是一种云存储服务,提供了简单易用的 Web 服务接口来存储和检索任意数量的数据。

Amazon S3 旨在进行无缝扩展和提供 99.999999999%的持久性。

特点:

  • 存储任意数量的对象,存储空间无上限
  • 单个对象的大小不超过 5TB,对文件类型没有限制
  • 数据以冗余方式存储
  • 存储桶名称在 Amazon S3 的所有现有存储桶名称中必须具有唯一性
  • 通过互联网直接访问
  • 对象上传或删除可以触发通知、工作流程甚至脚本
  • 传输及静态数据加密
  • 多种存储类适应企业不同存储需求

它的主要功能有:

  1. 存储和检索数据:您可以上传任意数量的数据到 S3,并在任何时间从任何地点检索这些数据。
  2. 数据备份和恢复:S3 提供了高持久性的存储,使其成为备份和恢复数据的理想选择。
  3. 静态网站托管:您可以使用 S3 来托管静态网站,包括 HTML、CSS、JavaScript 等文件。
  4. 数据归档:S3 提供了一种名为 Glacier 的低成本存储选项,用于长期归档数据。
  5. 大数据分析:S3 是大数据和分析工作负载的理想存储解决方案,因为它可以存储和检索大量的数据
  6. 内容分发:S3 可以与 Amazon CloudFront 集成,用于分发内容(CDN)。

要上传数据(照片、视频、文档等),请执行以下操作:

  1. 创建一个存储桶。
  2. 将任意数量的对象上传到存储桶中。

访问对象的 URL 也是有规则的:

image-20240302185126236

S3 没有目录的结构,但是为了方便用户搜索和筛选,把 media/作为前缀使用。

创建 S3 对象

创建 S3 存储桶

image-20240302192156657

设置存储桶的权限——默认是私有的。

为了让我的存储桶里的数据能够被浏览器访问,这里启用了 ALC 和反选了阻止所有公开访问

image-20240302192522485

上传数据

image-20240302192854319

上传成功后将上传的对象访问权限设置为:使用 ACL 设为公开

image-20240302193050854

这样上传后的对象就可以被浏览器访问到啦。

版本控制

S3 的数据删除后,就会永久消失。

如果我们开启版本控制的话,就会有新版本和旧版本的区分,这样即使是删除后的对象,也会保留在旧版本中。

image-20240302193503621

与 Cloud Front 配合分发资源

官方教程在这里:https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/GettingStarted.SimpleDistribution.html

  1. 创建可访问的桶。(ACL 启用,取消屏蔽所有公共访问权限)

  2. 随便传一个文件(上传后的文件不需要设置 ACL 公开访问)

  3. 创建 CloudFront 分配

    • origin domain 选择 S3

    image-20240302214803002

    • 创建一个 OAC

      image-20240302215120592

    • 其他配置基本可以使用默认的

    • 创建分配

  4. 复制 S3 存储桶策略(创建后会提示复制)

    image-20240302215402004

  5. 将策略拷贝到 S3 存储桶策略中并保存修改

    image-20240302215537596

  6. 使用 cloudFront 提供的 url 加上对象名称访问。

    image-20240302220036237

  7. 完成!

静态网站托管

S3 还可以被设置为静态网站托管,首先到 S3 中设置静态网站托管。

存储桶-属性-静态网站托管-编辑

image-20240302195811079

将索引文档的主页名称设置一下,然后点击保存。

AWS 会分配一个基于桶的静态网站托管域名给你。

image-20240302200101265

将打包好之后的静态网站的所有资源都存入桶中,并设置成 ACL 公开。

image-20240302200003026

最后打开域名就可以看到结果啦!

image-20240302200441513

静态网站托管功能本质上就是一次性让存储在桶里的资源可以互相访问、在浏览器中公开访问等。

API 调用

准备工作:

  1. 必须拥有Security Credentials(安全凭证),获取方式:

    • 登陆 AWS account

    • 右上方点击你的账户名,选择 “Security Credentials”

      image-20231220174431728

    • 创建 Access Keys

      image-20231220174536680

  2. 在首页选择一个 region,并记住它的编码

    image-20231220175503348

在 root 用户下直接启用 token 的方式不是很安全,最佳的方式是指定一个 IAM 用户,为该用户创建 token,最后对该用户设置访问策略。

上传文件至 S3

在上传文件之前,需要下载这个包:

bash
1yarn add @aws-sdk/client-s3

创建一个 bucket(存储桶),以便分类你想储存的数据。

typescript
1import { S3Client, CreateBucketCommand, CreateBucketCommandInput } from '@aws-sdk/client-s3'
2
3const accessKeyId = 'YOUR_ACCESS_KEY'
4const secretAccessKey = 'YOUR_ACCESS_KEY_SECRET'
5const REGION = 'ap-northeast-1'
6const BUCKET_NAME = 'bucket-1-2021-10-12'
7
8// 创建 S3 客户端
9const s3Client = new S3Client({
10  region: REGION,
11  credentials: {
12    accessKeyId,
13    secretAccessKey,
14  },
15})
16
17// 设置 bucket 参数
18const bucketParams: CreateBucketCommandInput = {
19  Bucket: BUCKET_NAME,
20  CreateBucketConfiguration: {
21    LocationConstraint: REGION,
22  },
23}
24
25const run = async () => {
26  try {
27    const data = await s3Client.send(new CreateBucketCommand(bucketParams))
28    console.log('Success', data)
29  } catch (err) {
30    console.log('Error', err)
31  }
32}
33
34run()

列出所有 budgets 代码

js
1const listBucketParams: ListBucketsCommandInput = {}
2
3const run = async () => {
4  try {
5    const data = await s3Client.send(new ListBucketsCommand(listBucketParams))
6    console.log('Success', data)
7  } catch (err) {
8    console.log('Error', err)
9  }
10}
11
12run()

上面的代码可以获得以下结果

bash
1Success {
2  '$metadata': {
3    httpStatusCode: 200,
4    requestId: 'H4DHV61DTTES539P',
5    extendedRequestId: 'vVDUOTQ8xWFKepIh20pPNwRQxcC1eDinXuqXxjKAOy3H8L+ssCipCmoF0MiXygRcPv+deQkBcCk=',
6    cfId: undefined,
7    attempts: 1,
8    totalRetryDelay: 0
9  },
10  Buckets: [
11    {
12      Name: 'bucket-1-2021-10-12',
13      CreationDate: 2023-12-20T12:42:05.000Z
14    }
15  ],
16  Owner: {
17    DisplayName: 'qiuyanxi1992',
18    ID: 'd74d029e781c3ee592f3469502fae45404c41279d20e5944ef5e338767f97493'
19  }
20}

创建好 budget 后,就可以上传文件了。

将文件上传至 S3 有很多种渠道:

  • s3.upload
  • s3.putObject
  • 通过 signedUrl

...

大部分情况下,我们都可以使用signedUrl来上传。它的逻辑是这样的:

  1. 前端向后端发送请求以获取签名 Url

  2. 后端获取签名 Url 后发送回前端

    js
    1import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
    2
    3const command = new PutObjectCommand({
    4  Bucket: BUCKET_NAME,
    5  Key: 'example.txt',
    6})
    7
    8const run = async () => {
    9  try {
    10    const url = await getSignedUrl(s3Client, command, { expiresIn: 3600 })
    11    console.log('Success', url)
    12  } catch (err) {
    13    console.log('Error', err)
    14  }
    15}
  3. 前端直接将文件发送至签名 Url

    js
    1import https from 'https'
    2
    3function put(url, data) {
    4  return new Promise((resolve, reject) => {
    5    const req = https.request(
    6      url,
    7      { method: 'PUT', headers: { 'Content-Length': new Blob([data]).size } },
    8      (res) => {
    9        let responseBody = ''
    10        res.on('data', (chunk) => {
    11          responseBody += chunk
    12        })
    13        res.on('end', () => {
    14          resolve(responseBody)
    15        })
    16      },
    17    )
    18    req.on('error', (err) => {
    19      reject(err)
    20    })
    21    req.write(data)
    22    req.end()
    23  })
    24}
    25
    26await put(data, '123')
  4. 文件通过签名 Url 传输到 S3 中

官方示例代码

从 S3 下载文件

从 S3 下载文件同样能够使用 signedUrl 来获取下载链接,核心代码:

js
1const command = new GetObjectCommand({
2  Bucket: BUCKET_NAME,
3  Key: 'example.txt',
4})
5
6const clientUrl = await getSignedUrl(s3Client, command, {
7  expiresIn: 3600,
8})
9console.log('——————🚀🚀🚀🚀🚀 —— clientUrl:', clientUrl)

前端拿到 URL 后直接调用 fetch 来下载

js
1function download(href, filename = '') {
2  const a = document.createElement('a')
3  a.download = filename
4  a.href = href
5  document.body.appendChild(a)
6  a.click()
7  a.remove()
8}
9
10function downloadFile(url, filename = '') {
11  fetch(url)
12    .then((res) => res.blob())
13    .then((blob) => {
14      const blobUrl = window.URL.createObjectURL(blob)
15      download(blobUrl, filename)
16      window.URL.revokeObjectURL(blobUrl)
17    })
18}

官方示例代码

EFS 存储

多个实例需要在存储中同一时间频繁读写,这种情况下就适合 Elastic File System 了。

  • EBS 有跨实例共享限制

  • S3 是对象存储,适合一写多读,不适合频繁读写和修改

Elastic File System(简称 EFS)主要功能:

  • 文件存储
  • 适用于大数据和分析、媒体处理工作流程、内容管理、Web 服务和主目录
  • PB 级低延迟文件系统
  • 共享存储
  • 弹性容量