# S3 API

Alluxio 提供与 Amazon S3 API 兼容的 RESTful API，允许为 S3 构建的应用程序与 Alluxio 管理的数据进行交互。这使您能够利用 Alluxio 的数据缓存、共享和存储抽象功能，而无需修改现有的基于 S3 的应用程序。

## 入门指南

### 先决条件

首先，通过将以下属性添加到您的 `conf/alluxio-site.properties` 文件中，在所有 Alluxio worker 上启用 S3 API：

```properties
alluxio.worker.s3.api.enabled=true
```

### 连接到 S3 端点

S3 API 在每个 Alluxio worker 上公开。强烈建议设置一个负载均衡器（例如 Nginx、LVS 或 DNS 轮询）以在所有 worker 之间分发 API 请求。您的负载均衡器的地址将作为客户端的 S3 端点。

* **HTTP 端口**：`29998`（默认）
* **HTTPS 端口**：`29996`（默认）

要启用 HTTPS，请参阅 TLS 配置指南。您可以通过设置 `alluxio.worker.s3.only.https.access=true` 来强制仅使用 HTTPS 访问。

### 配置您的 S3 客户端

配置您的 S3 客户端涉及设置端点、身份验证凭据和寻址样式。

#### 身份验证方法

Alluxio 的 S3 API 支持两种身份验证方法：`SIMPLE`（默认）和基于令牌的 `OIDC`。

**SIMPLE 身份验证（默认）**

默认情况下，Alluxio 使用 `SIMPLE` 身份验证方案，而不是标准的 AWS 凭据验证。

* **工作原理**：为了兼容性，客户端仍应生成根据 [AWS Signature Version 4](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html) 格式化的 `Authorization` 标头。Alluxio 解析此标头以提取用户，但**不**验证加密签名。
* **访问密钥**：您希望执行操作的 Alluxio 用户名。这是 `Authorization` 标头的 `Credential` 部分。如果您不提供访问密钥，操作将以启动 Alluxio worker 进程的用户身份执行。
* **秘密密钥**：可以是任何虚拟值。客户端需要它来生成签名，但 Alluxio 会忽略它。

**基于 OIDC 令牌的身份验证**

为了更安全、集中的身份管理，您可以将 S3 API 配置为使用 OIDC (OpenID Connect) 令牌。有关更多详细信息，请参阅完整的[身份验证](/ee-ai-cn/ai-3.7/administration/security/enabling-authentication.md)指南。

#### 寻址样式

* 客户端**必须**使用**路径样式请求**（例如，`http://<endpoint>/<bucket>/<object>`）。
* **不**支持虚拟托管样式请求（`http://<bucket>.<endpoint>/<object>`）。

## 高级配置

### 性能和 HTTP 重定向

默认情况下，Alluxio 的 S3 API 使用 HTTP 重定向来实现零拷贝读取。当客户端请求一个对象时，它会被重定向到持有该数据的特定 worker。

但是，某些 S3 客户端，如 Python 的 `boto3` 和 PyTorch S3 连接器，无法正确处理这些重定向。如果您正在使用此类客户端，则必须通过设置以下属性来禁用重定向：

```properties
alluxio.worker.s3.redirect.enabled=false
```

禁用重定向后，数据将通过最初接收请求的 worker 进行代理，这会引入额外的网络跳数，并可能影响性能。

### 标签和元数据

* **启用标签**：要使用 S3 对象标签，您必须为您的 UFS 启用扩展属性 (xattr) 支持。

  ```properties
  alluxio.underfs.xattr.change.enabled=true
  ```
* **标签限制**：默认情况下，存储桶和对象上的用户定义标签限制为 10 个，并遵守 [S3 标签限制](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-tagging.html)。您可以使用 `alluxio.proxy.s3.tagging.restrictions.enabled=false` 禁用此功能。
* **元数据大小**：根据 [S3 对象元数据限制](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html)，PUT 请求中用户定义元数据的最大大小默认为 2KB。您可以使用 `alluxio.proxy.s3.header.metadata.max.size` 更改此设置。

### HTTP 持久连接（Keep-Alive）

HTTP 持久连接（也称为 HTTP keep-alive）是使用单个 TCP 连接发送和接收多个 HTTP 请求/响应的想法，而不是为每个请求/响应对打开一个新连接。

持久连接的主要优点包括：

* **减少延迟**：最大限度地减少频繁请求引起的延迟。
* **节省资源**：通过更少的连接和更少的重复请求来减少服务器和客户端的资源消耗。
* **实时能力**：能够快速传输最新数据。

但是，长连接也有一些缺点，例如：

* **增加服务器压力**：许多打开的连接会增加服务器的内存和 CPU 负担。
* **超时问题**：需要处理连接长时间无响应的情况，以确保超时机制的有效性。

要为 S3 API 启用 HTTP 长连接 keep-alive，您需要修改 `conf/alluxio-site.properties` 文件以包含以下内容：

```properties
# Enable keep-alive
alluxio.worker.s3.connection.keep.alive.enabled=true

# Set an idle timeout. The connection will be closed if idle for this duration.
# A value of 0 means to turn off this function.
alluxio.worker.s3.connection.idle.max.time=0sec
```

### 限制

* **存储桶**：只有 Alluxio 命名空间中的顶级目录被视为 S3 存储桶。根目录 (`/`) 不是存储桶，并且无法通过 S3 API 访问根目录下的对象。 为了无缝迁移现有应用程序逻辑而不编辑 S3 URI，请务必使用存储桶名称作为挂载路径。例如：

  ```
  alluxio mount add --path /<bucket-name> --ufs-uri s3://<bucket-name>/
  ```
* **对象覆盖**：Alluxio 不提供对象锁定或版本控制。如果多个客户端同时写入同一个对象，则最后一次写入将获胜。
* **不支持的字符**：不要在对象键中使用 `?`、`\`、`./` 或 `../`。在路径中使用 `//` 可能会导致未定义的行为。
* **文件夹对象**：子目录在 `ListObjects(V2)` 响应中作为 0 字节的文件夹对象返回，与 AWS S3 控制台的行为相匹配。

### 支持的 S3 操作

下表列出了支持的 S3 API 操作。有关详细用法，请参阅[官方 S3 API 文档](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Operations.html)。

| S3 API 操作                                                                                                   | 支持的标头                                                                                                       | 支持的查询参数                                                                                 |
| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| [AbortMultipartUpload](https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html)       | 不适用                                                                                                         | 不适用                                                                                     |
| [CompleteMultipartUpload](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html) | 不适用                                                                                                         | 不适用                                                                                     |
| [CopyObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html)                           | `Content-Type`, `x-amz-copy-source`, `x-amz-metadata-directive`, `x-amz-tagging-directive`, `x-amz-tagging` | 不适用                                                                                     |
| [CreateMultipartUpload](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html)     | 不适用                                                                                                         | 不适用                                                                                     |
| [DeleteBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketTagging.html)         | 不适用                                                                                                         | 不适用                                                                                     |
| [DeleteObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html)                       | 不适用                                                                                                         | 不适用                                                                                     |
| [DeleteObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html)                     | 不适用                                                                                                         | 不适用                                                                                     |
| [DeleteObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html)         | 不适用                                                                                                         | 不适用                                                                                     |
| [GetBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html)               | 不适用                                                                                                         | 不适用                                                                                     |
| [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html)                             | `Range`                                                                                                     | 不适用                                                                                     |
| [GetObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html)               | 不适用                                                                                                         | 不适用                                                                                     |
| [HeadBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html)                           | 不适用                                                                                                         | 不适用                                                                                     |
| [HeadObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html)                           | 不适用                                                                                                         | 不适用                                                                                     |
| [ListBuckets](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html)                         | 不适用                                                                                                         | 不适用                                                                                     |
| [ListMultipartUploads](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html)       | 不适用                                                                                                         | 不适用                                                                                     |
| [ListObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html)                         | 不适用                                                                                                         | `delimiter`, `encoding-type`, `marker`, `max-keys`, `prefix`                            |
| [ListObjectsV2](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html)                     | 不适用                                                                                                         | `continuation-token`, `delimiter`, `encoding-type`, `max-keys`, `prefix`, `start-after` |
| [ListParts](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html)                             | 不适用                                                                                                         | 不适用                                                                                     |
| [PutBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html)               | 不适用                                                                                                         | 不适用                                                                                     |
| [PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)                             | `Content-Length`, `Content-MD5`, `Content-Type`, `x-amz-tagging`                                            | 不适用                                                                                     |
| [PutObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html)               | 不适用                                                                                                         | 不适用                                                                                     |
| [UploadPart](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html)                           | `Content-Length`, `Content-MD5`                                                                             | 不适用                                                                                     |

## 用法示例

### boto3 客户端

由于 boto3 客户端无法处理重定向响应，因此通过配置显式禁用重定向

```properties
alluxio.worker.s3.redirect.enabled=false
```

以下示例 python 脚本显示了如何初始化 `boto3` 客户端并使用列出存储桶请求对其进行测试。

```python
import boto3
from botocore.exceptions import ClientError
​
ALLUXIO_S3_ENDPOINT = "http://<LOAD_BALANCER_ADDRESS>"  # Alluxio's S3 API endpoint when using a load balancer to distribute requests to all workers
# ALLUXIO_S3_ENDPOINT = "http://<ALLUXIO_WORKER>:29998"  # an alternative to a load balancer is to directly connect to a worker
ACCESS_KEY = "placeholder"  # Alluxio does not validate credentials
SECRET_KEY = "placeholder"
REGION = "us-east-1"
​
FOLDER_PREFIX_TO_LIST = "/"
​
def main():
    try:
        s3 = boto3.client(
            "s3",
            aws_access_key_id=ACCESS_KEY,
            aws_secret_access_key=SECRET_KEY,
            region_name=REGION,
            endpoint_url=ALLUXIO_S3_ENDPOINT
        )
        print("Client initialized successfully.")
​
        # Example: list objects with prefix
        response = s3.list_buckets()
        print("Buckets (Alluxio mount points):")
        for bucket in response.get("Buckets", []):
            print(f" - {bucket['Name']}")
    except Exception as e:
        print(f"Error: {e}")
​
if __name__ == "__main__":
    main()
```

这假定 boto3 是通过 `pip install -r requirements.txt` 安装的，其中 `boto3` 是 `requirements.txt` 中的唯一条目。

### Pytorch

由于 Pytorch 客户端无法处理重定向响应，因此通过配置显式禁用重定向

```properties
alluxio.worker.s3.redirect.enabled=false
```

以下示例 python 脚本使用 Pytorch 的 S3 连接器读取数据。它假定 UFS 已沿路径 `/s3-mount` 挂载。

```python
# ref https://github.com/awslabs/s3-connector-for-pytorch/tree/main?tab=readme-ov-file#sample-examples

from s3torchconnector import S3MapDataset, S3IterableDataset, S3ClientConfig
import random

S3_ENDPOINT_URL = "http://<LOAD_BALANCER_ADDRESS>"  # Alluxio's S3 API endpoint when using a load balancer to distribute requests to all workers
# S3_ENDPOINT_URL = "http://<ALLUXIO_WORKER>:29998"  # an alternative to a load balancer is to directly connect to a worker
DATASET_URI="s3://s3-mount"
REGION = "us-east-1"

s3_client_config = S3ClientConfig(
  force_path_style=True,
)

iterable_dataset = S3IterableDataset.from_prefix(DATASET_URI,
  region=REGION,
  endpoint=S3_ENDPOINT_URL,
  s3client_config=s3_client_config,
)

for item in iterable_dataset:
  content = item.read()
  print(f"{item.key}:{len(content)}")

map_dataset = S3MapDataset.from_prefix(DATASET_URI,
  region=REGION,
  endpoint=S3_ENDPOINT_URL,
  s3client_config=s3_client_config,
)

# Randomly access to an item in map_dataset.
item = random.choice(map_dataset)
# # Learn about bucket, key, and content of the object
bucket = item.bucket
key = item.key
content = item.read()
print(f"{bucket} {key} {len(content)}")
This assumes Pytorch and related libraries are installed with pip.
$ pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
$ pip install --upgrade pip
$ pip install s3torchconnector
```

这假定 Pytorch 和相关库是使用 pip 安装的。

```shell
$ pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
$ pip install --upgrade pip
$ pip install s3torchconnector
```

### Nvidia Triton 推理服务器

以下步骤显示了如何准备 Triton 模型存储库、服务器和客户端。它假定为 Alluxio 进行了以下准备：

* Alluxio 部署在 K8s 中
* Alluxio S3 端点在 `<LOAD_BALANCER_ADDRESS>` 可用
* 一个名为 `<MY_BUCKET>` 的 S3 存储桶在 Alluxio 的挂载点 `/s3-mount` 处挂载

准备模型存储库并上传到挂载的 S3 存储桶。

```shell
$ kubectl run -it --rm debug-shell --image=ubuntu:22.04 --restart=Never -- sh
$ apt update -y
$ apt install -y awscli git python3 python3.10-venv wget
$ git clone -b r25.06 https://github.com/triton-inference-server/server.git
$ cd server/docs/examples
$ ./fetch_models.sh

# upload to s3. note that "/triton_model_repo" it will be used for the triton server
$ aws s3 sync model_repository s3://<MY_BUCKET>/triton_model_repo
```

创建 `triton-server.yaml` 并使用 `kubectl create -f triton-server.yaml` 部署它。

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: triton-inference-server-s3
  labels:
    app: triton-s3
spec:
  hostNetwork: true
  containers:
    - name: triton-s3-server
      image: nvcr.io/nvidia/tritonserver:24.05-py3
      imagePullPolicy: IfNotPresent
      ports:
        - name: http
          containerPort: 8000
          protocol: TCP
        - name: grpc
          containerPort: 8001
          protocol: TCP
        - name: metrics
          containerPort: 8002
          protocol: TCP
      command: ["/opt/tritonserver/bin/tritonserver"]
      args:
        - "--model-repository=s3://<LOAD_BALANCER_ADDRESS>/s3-mount/triton_model_repo"
        - "--log-verbose=1"
        - "--log-info=true"
      readinessProbe:
        httpGet:
          path: /v2/health/ready
          port: 8000
        initialDelaySeconds: 30
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 3
      livenessProbe:
        httpGet:
          path: /v2/health/live
          port: 8000
        initialDelaySeconds: 60
        periodSeconds: 30
        timeoutSeconds: 5
        failureThreshold: 3
```

作为启动服务器的一部分，模型数据将被读取，因此会缓存在 Alluxio 中。

创建 `triton-client.yaml` 并使用 `kubectl create -f triton-client.yaml` 部署它。

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: triton-client
  labels:
    app: triton-s3
spec:
  hostNetwork: true
  containers:
    - image: nvcr.io/nvidia/tritonserver:24.05-py3-sdk
      imagePullPolicy: IfNotPresent
      name: tritonserver-client-test
      command: ["sleep", "infinity"]
```

从客户端内部发送请求

```shell
$ kubectl exec -it triton-client -- /workspace/install/bin/image_client -u $(kubectl get pod triton-inference-server-s3 -o jsonpath='{.status.podIP}'):8000 -m densenet_onnx -c 3 -s INCEPTION /workspace/images/mug.jpg
Request 0, batch size 1
Image '/workspace/images/mug.jpg':
    15.349564 (504) = COFFEE MUG
    13.227464 (968) = CUP
    10.424892 (505) = COFFEEPOT
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://documentation.alluxio.io/ee-ai-cn/ai-3.7/data-access/s3-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
