# Amazon AWS S3

本指南描述了将 [Amazon AWS S3](https://aws.amazon.com/s3/) 配置为 Alluxio 底层存储系统的说明。 Amazon AWS S3，即 Amazon Simple Storage Service，是一种对象存储服务，提供行业领先的可扩展性、数据可用性、安全性和性能。 有关 Amazon AWS S3 的更多信息，请阅读其[文档](https://docs.aws.amazon.com/s3/index.html)。

## 先决条件

如果你还没有满足先决条件，在开始前请阅读[先决条件](https://documentation.alluxio.io/ee-ai-cn/ai-3.2/storage-overview#先决条件)。

准备将Amazon AWS S3与Alluxio一起使用时，请遵循以下步骤。

| `<S3_BUCKET>`        | [创建一个新的S3 bucket](https://docs.ceph.com/en/quincy/radosgw/s3/bucketops/) 或者使用一个现存的 bucket                                                                |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<S3_DIRECTORY>`     | 你想在容器中使用的目录，创建一个新目录，或者使用一个现有的目录。                                                                                                                         |
| `<S3_ACCESS_KEY_ID>` | 用于对 AWS 发出的请求进行签名计算。请参阅 [如何获取 Access Key ID 和 Secret Access Key](https://docs.aws.amazon.com/powershell/latest/userguide/pstools-appendix-sign-up.html)  |
| `<S3_SECRET_KEY>`    | 用于对 AWS 发出的请求进行签名计算。请参阅 [如何获取 Access Key ID 和 Secret Access Key](https://docs.aws.amazon.com/powershell/latest/userguide/pstools-appendix-sign-up.html)。 |

## 基础设置

使用 [挂载表操作](https://documentation.alluxio.io/ee-ai-cn/ai-3.2/feature/alluxio-namespace-and-under-file-system-namespaces#挂载表操作) 来增加一个新的挂载点, 指定Alluxio路径在其上创建挂载，指定S#的路径作为UFS URI。 密钥和配置选项也可以通过指定 `--option` 标志作为挂载命令的一部分来指定，如[配置挂载点](https://documentation.alluxio.io/ee-ai-cn/ai-3.2/feature/alluxio-namespace-and-under-file-system-namespaces#对不同挂载点使用不同的配置)所述。

一个将 `s3://<S3_BUCKET>/<S3_DIRECTORY>` 挂载到 `/s3` 的示例命令：

```shell
bin/alluxio mount add --path /s3/ --ufs-uri s3://<S3_BUCKET>/<S3_DIRECTORY> \
  --option s3.accessKeyId=<S3_ACCESS_KEY_ID> --option s3.secretKey=<S3_SECRET_KEY>
```

请注意，如果您想挂载S# bucket的根，请在bucket名称后面添加一个斜杠（例如`s3://S3_BUCKET/`).

对于其他设置AWS凭证的方法，请参阅[高级设置](#高级设置)中的凭证章节。

## 高级设置

### 配置S3 Region

配置访问 S3 bucket时的 S3 Region，以提高性能。 否则，将启用全局 S3 bucket访问，这会引入额外的请求。 可以在 `conf/alluxio-site.properties` 中设置 S3 Region。

```properties
alluxio.underfs.s3.region=us-west-1
```

### 高级凭证设置

你可以用不同的方式指定凭证（credentials），优先级由高到低排列：

你可以使用多种不同的方式指定凭证，从高优先级到低优先级分别是：

1. 作为挂载选项指定 `s3a.accessKeyId` 和 `s3a.secretKey`
2. 作为 Java 系统属性指定 `s3a.accessKeyId` 和 `s3a.secretKey`
3. 在 `alluxio-site.properties` 中指定 `s3a.accessKeyId` 和 `s3a.secretKey`
4. 在 Alluxio 服务器上使用环境变量 `AWS_ACCESS_KEY_ID` 或者 `AWS_ACCESS_KEY`（两者之一即可）以及 `AWS_SECRET_ACCESS_KEY` 或者 `AWS_SECRET_KEY`（两者之一即可）
5. 包含凭证的配置文件位于 `~/.aws/credentials`
6. 如果您使用的是 EC2 实例，则使用 AWS 实例配置凭证

当使用 AWS 实例配置文件提供凭证时：

* 创建一个具有访问挂载存储桶权限的 [IAM Role](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
* 创建一个[实例配置文件](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#ec2-instance-profile)作为已定义 IAM role的容器
* 使用创建的配置文件启动一个 EC2 实例

请注意，IAM role需要访问存储桶中的文件以及存储桶本身，以确定存储桶的所有者。 通过设置属性 `alluxio.underfs.s3.inherit.acl=false` 可以避免自动分配存储桶所有者。

有关更多详细信息，请参阅 [Amazon 的文档](http://docs.aws.amazon.com/java-sdk/latest/developer-guide/credentials.html#id6)。

### 开启服务端加密

您可以对存储在 S3 中的数据进行加密。 加密仅对 S3 中静态数据有效，当客户端读取数据时将以解密形式传输。 请注意，启用此功能还会启用 HTTPS 以符合读取/写入对象的要求。

通过配置 `conf/alluxio-site.properties` 文件启用此功能：

```properties
alluxio.underfs.s3.server.side.encryption.enabled=true
```

### DNS-Buckets

默认情况下，指向名为"mybucket"的bucket的请求将发送到名为"mybucket.s3.amazonaws.com"的主机。 您可以启用 DNS-Buckets 以使用路径风格的数据访问，例如："<http://s3.amazonaws.com/mybucket"，通过设置以下配置：>

```properties
alluxio.underfs.s3.disable.dns.buckets=true
```

### 通过proxy访问S3

在 `conf/alluxio-site.properties` 中加入以下选项，用以支持使用proxy与S3交互:

```properties
alluxio.underfs.s3.proxy.host=<PROXY_HOST>
alluxio.underfs.s3.proxy.port=<PROXY_PORT>
```

`<PROXY_HOST>` 和 `<PROXY_PORT>` 需要用你的proxy的主机名和端口代替。

### 访问特定region的S3服务

如果你想访问一个特定region的AWS服务，而不是默认的us-east-1，在 `conf/alluxio-site.properties` 中修改下面的选项：

```properties
alluxio.underfs.s3.region=<S3_REGION>
```

如果你想访问AWS服务中特定region的一个特定的endpoint（类似于AWS VPC endpoint），在 `conf/alluxio-site.properties` 中修改下面的选项：

```properties
alluxio.underfs.s3.endpoint=<S3_ENDPOINT>
alluxio.underfs.s3.endpoint.region=<S3_ENDPOINT_REGION>
```

需要将上面的endpoint和region值更新为对应的特定region，而非全局默认region。 在设置后，`alluxio.underfs.s3.region=<S3_REGION>` 将不再生效。

### 使用一个非Amazon服务提供商

如果想使用一个非"s3.amazonaws.com"的S3服务提供商，修改 `conf/alluxio-site.properties` 中下面的选项：

```properties
alluxio.underfs.s3.endpoint=<S3_ENDPOINT>
alluxio.underfs.s3.endpoint.region=<S3_ENDPOINT_REGION>
```

将 `<S3_ENDPOINT>` 替换为您的 S3 服务的主机名和端口，例如：[http://localhost:9000。](https://documentation.alluxio.io/ee-ai-cn/ai-3.2/ufs/http:/localhost:9000。) 仅在使用非 `s3.amazonaws.com` 的提供者时使用此参数。

### 连接到 Oracle Cloud Infrastructure (OCI) 对象存储

endpoint和region值都需要被更新为使用non-home region。

```properties
alluxio.underfs.s3.endpoint=<S3_ENDPOINT>
alluxio.underfs.s3.endpoint.region=<S3_ENDPOINT_REGION>
```

所有的OCI对象存储region都需要使用 `PathStyleAccess`

```properties
alluxio.underfs.s3.disable.dns.buckets=true
alluxio.underfs.s3.inherit.acl=false
```

### 使用v2 S3签名

一些 S3 服务提供商仅支持 v2 签名。 对于这些 S3 提供商，您可以通过设置 `alluxio.underfs.s3.signer.algorithm` 为 `S3SignerType` 来强制使用 v2 签名。

### \[实验性] S3 流式上传功能

由于 S3 作为对象存储的特性，文件上传时会被从客户端发送到Worker节点，并被存储在本地磁盘的临时目录中，默认在 `close()` 方法中被上传到S3。

要启用 S3 流式上传，您需要修改 `conf/alluxio-site.properties` 文件，添加以下内容：

```properties
alluxio.underfs.s3.streaming.upload.enabled=true
```

默认的上传过程更安全，但存在以下问题：

* 上传时间慢。文件必须先发送到 Alluxio worker，然后由 Alluxio worker负责将文件上传到 S3。这两个过程是顺序执行的。
* 临时目录必须有足够的容量来存储整个文件。
* `close()` 方法执行缓慢。`close()` 方法的执行时间与文件大小成正比，与带宽成反比，即 O(FILE\_SIZE/BANDWIDTH)。 `close()` 方法执行缓慢是预期之外的，并且已经成为 Alluxio FUSE 中的一个瓶颈。 Alluxio FUSE 方法调用 `close()` 是异步的，因此如果通过 Alluxio FUSE 将大文件写入 S3，FUSE 写操作会在文件实际写入 S3 之前很久就返回。

S3 流式上传功能解决了上述问题，并且基于 [S3 低级别的分段上传](https://docs.aws.amazon.com/AmazonS3/latest/dev/mpListPartsJavaAPI.html)。

S3 流式上传具有以下优点：

* 更快的上传时间：文件可以直接从客户端流式上传到 S3，而无需先发送到 Alluxio 工作节点。
* 减少本地存储需求：无需在临时目录中存储整个文件，减少了对本地磁盘空间的需求。
* 更快的 `close()` 方法：`close()` 方法执行时间大大缩短，因为文件的上传在写入过程中已经完成。

如果 S3 流式上传被中断，可能会有中间分段上传到 S3，并且 S3 将为这些数据收费。 为了减少费用，用户可以修改 `conf/alluxio-site.properties` 文件，添加以下内容：

```properties
alluxio.underfs.cleanup.enabled=true
```

所有非只读 S3 挂载点中超过clean age（由 `alluxio.underfs.s3.intermediate.upload.clean.age` 配置） 的中间分段上传文件将在达到清理时间间隔（由 `alluxio.underfs.cleanup.interval` 配置）时被清理。

### \[实验性] S3 多部分上传

默认的上传方法一次性从头到尾上传一个完整的文件。 我们使用分段上传方法将一个文件分成多个部分进行上传，每个部分将通过一个线程上传。上传过程中不会生成任何临时文件。 *它会消耗更多内存，但比流式上传模式更快。*

要启用 S3 分段上传，您需要修改 `conf/alluxio-site.properties` 文件，添加以下内容：

```properties
alluxio.underfs.s3.multipart.upload.enabled=true
```

可以在 `conf/alluxio-site.properties` 文件中指定其他参数，让上传过程更快更好。

```properties
# Timeout for uploading part when using multipart upload.
alluxio.underfs.object.store.multipart.upload.timeout
```

```properties
# Multipart upload partition size for S3. The default partition size is `64MB`
alluxio.underfs.s3.multipart.upload.partition.size
```

### 高并发调优

如果在每个 Alluxio server上使用大量client访问 S3，则可以下面调整这些参数，以开启Alluxio 使用针对 S3 的特定后端优化。

如果 S3 连接较慢，则可以尝试设置较大的超时时间：

```properties
alluxio.underfs.s3.socket.timeout=500sec
alluxio.underfs.s3.request.timeout=5min
```

如果需要大量并发元数据操作：

```properties
alluxio.underfs.s3.admin.threads.max=80
```

如果元数据+数据操作的总数很大：

```properties
alluxio.underfs.s3.threads.max=160
```

在worker端，这个参数的含义是worker到S3并发写的最大数量；在master端，这个参数的含义是在一个文件夹中并发rename 文件的最大线程数。

```properties
alluxio.underfs.s3.upload.threads.max=80
```

这个参数的含义是在master端提交delete和rename操作的线程池的大小。

```properties
alluxio.underfs.object.store.service.threads=80
```

## S3 Objects的身份验证和访问控制

[S3 的身份验证和访问管理](https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html) 与传统的 POSIX 权限模型非常不同。 例如，S3 ACL 不支持组或目录级别的设置。 Alluxio 尽最大努力从 S3 ACL 信息中继承权限信息，包括文件所有者、组和权限模式（permission mode）。

### 为什么返回403 Access Denied Error

在 Alluxio 配置中设置的 S3 credentials 对应于一个 AWS 用户。 如果此用户没有访问 S3 bucket或object所需的权限，则将返回 403 permission denied错误。

如果在访问 S3 服务时在 Alluxio 服务器日志中看到 403 错误，请务必检查：

1. 您是否使用了正确的 AWS credentials。请参阅 [高级凭证设置](#高级凭证设置).
2. 您的 AWS 用户是否具有访问挂载到 Alluxio 的存储桶和对象的权限。

阅读更多关于 AWS 403 错误的[故障排除指南](https://aws.amazon.com/premiumsupport/knowledge-center/s3-troubleshoot-403/)。

### 文件所有者和组

Alluxio 文件系统根据在 Alluxio 中配置的用于连接到 S3 的 AWS 账户设置文件所有者。 由于 S3 ACL 中没有组，因此所有者被设为文件的group。

默认情况下，Alluxio 提取此 AWS 账户的显示名称作为文件所有者。 如果此显示名称不可用，则将使用此 AWS 用户的[规范用户 ID](https://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html)。 此规范用户 ID 通常是一个长字符串（例如 `79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be`）， 因此在实践中往往不方便阅读和使用。 可选地，属性 `alluxio.underfs.s3.owner.id.to.username.mapping` 可用于指定从规范用户 ID 到 Alluxio 用户名的预设映射，格式为 "id1=user1;id2=user2"。 例如，编辑 `alluxio-site.properties` 使之包含如下内容：

```properties
alluxio.underfs.s3.owner.id.to.username.mapping=\
79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be=john
```

这个配置帮助 Alluxio 将所有由此 AWS 账户拥有的对象识别为 Alluxio 命名空间中的用户 `john` 拥有。 要找出您账户的 AWS S3 规范用户 ID，可以查看控制台 `https://console.aws.amazon.com/iam/home?#/security_credentials`， 展开 "Account Identifiers" 选项卡，然后参考 "规范用户 ID"。

### 修改权限

Alluxio目录和文件的 `chown`, `chgrp`, 和 `chmod` 不会被传递到底层的S3 buckets或者objects。

## 问题排查

### 启用 AWS-SDK 调试级别

如果在使用 S3 后端时遇到问题，可以启用额外的日志记录来跟踪 HTTP 流量。 修改 `conf/log4j.properties` 文件，添加以下属性：

```properties
log4j.logger.com.amazonaws=WARN
log4j.logger.com.amazonaws.request=DEBUG
log4j.logger.org.apache.http.wire=DEBUG
```

查阅[Amazon文档](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-logging.html)查看详细情况。
