

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 DynamoDB TTL 自动将项目归档到 Amazon S3
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl"></a>

*Tabby Ward，Amazon Web Services*

## Summary
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl-summary"></a>

此模式提供了从 Amazon DynamoDB 表中删除较旧的数据并将其存档到 Amazon Web Services（AWS）上的 Amazon Simple Storage Service（Amazon S3）存储桶的步骤，而无需管理服务器实例集。 

此模式使用 Amazon DynamoDB 生存时间（TTL）自动删除旧项目，使用 Amazon DynamoDB Streams 来捕获 TTL 过期项目。然后，它将 DynamoDB Streams 连接到 AWS Lambda，后者无需预调配或管理任何服务器即可运行代码。 

向 DynamoDB 流中添加新项目时，Lambda 函数将启动并将数据写入 Amazon Data Firehose 传输流。Firehose 提供了一种简单、完全托管的解决方案，可将数据作为存档加载到 Amazon S3 中。

DynamoDB 通常用于存储时间序列数据，例如来自传感器和联网设备的网页点击流数据或物联网（IoT）数据。许多客户不想删除访问频率较低的项目，而是将其存档以供审计。TTL 根据时间戳属性自动删除项目，从而简化了存档。 

DynamoDB Streams 中可以识别由 TTL 删除的项目，DynamoDB Streams 可捕获按时间排序的项目级修改序列，并将该序列存储在日志中长达 24 个小时。这些数据可由 Lambda 函数使用并存档在 Amazon S3 存储桶中，以降低存储成本。[为了进一步降低成本，可以创建 [Amazon S3 生命周期规则](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html)，自动将数据（一旦创建）转换为成本最低的存储类别。](https://aws.amazon.com/s3/storage-classes/)

## 先决条件和限制
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl-prereqs"></a>

**先决条件**
+ 一个活跃的 AWS 账户。
+ [AWS 命令行界面（AWS CLI）1.7 或更高版本](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html)，已在 macOS、Linux 或 Windows 上安装并配置。
+ [Python 3.7](https://www.python.org/downloads/release/python-370/) 或更高版本。
+ [Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html)，已安装并配置。如果Boto3 尚未安装，请运行 `python -m pip install boto3` 命令进行安装。

## 架构
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl-architecture"></a>

**技术堆栈**
+ Amazon DynamoDB
+ Amazon DynamoDB Streams
+ Amazon Data Firehose
+ AWS Lambda
+ Amazon S3

![\[从 DynamoDB 到 S3 存储桶的四步流程。\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/9dbc833f-cf3c-4574-8f09-d0b81134fe41/images/50d9da65-5398-4a99-bc8f-58afc80e9d7b.png)


1. TTL 会删除项目。

1. DynamoDB 流触发器调用 Lambda 流处理器函数。

1. Lambda 函数以批处理格式将记录放入 Firehose 传输流中。

1. 数据记录存档在 S3 存储桶中。

## 工具
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl-tools"></a>
+ [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) – AWS 命令行界面（AWS CLI）是用于管理 Amazon Web Services 的统一工具。
+ [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) – Amazon DynamoDB 是一个键值和文档数据库，在任何规模上都能提供个位数的毫秒性能。
+ [Amazon DynamoDB 生存时间（TTL）](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html)– Amazon DynamoDB TTL 可以定义每个项目的时间戳，以确定何时不再需要某个项目。
+ [Amazon DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Types_Amazon_DynamoDB_Streams.html) – Amazon DynamoDB Streams 可在任何 DynamoDB 表中捕获按时间排序的项目级修改序列，并将这类信息存储在日志中长达 24 个小时。
+ [Amazon Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/what-is-this-service.html) – Amazon Data Firehose 是将流数据可靠地加载到数据湖、数据存储和分析服务的最简单方法。
+ [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) – AWS Lambda 无需预调配或管理服务器即可运行代码。您只需按使用的计算时间付费。
+ [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/dev/Welcome.html) – Amazon Simple Storage Service（Amazon S3）是一种对象存储服务，提供行业领先的可扩展性、数据可用性、安全性和性能。

**代码**

此模式的代码可在[使用 DynamoDB TTL 存储库将项目 GitHub 存档到 S3](https://github.com/aws-samples/automatically-archive-items-to-s3-using-dynamodb-ttl) 中找到。

## 操作说明
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl-epics"></a>

### 设置 DynamoDB 表、TTL 和 DynamoDB 流
<a name="set-up-a-dynamodb-table-ttl-and-a-dynamodb-stream"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 DynamoDB 表。 | 使用 AWS CLI 在 DynamoDB 中创建一个名为 `Reservation`的表。选择随机读取容量单位（RCU）和写入容量单位（WCU），并给表两个属性：`ReservationID` 和 `ReservationDate`。 <pre>aws dynamodb create-table \<br />--table-name Reservation \<br />--attribute-definitions AttributeName=ReservationID,AttributeType=S AttributeName=ReservationDate,AttributeType=N \<br />--key-schema AttributeName=ReservationID,KeyType=HASH AttributeName=ReservationDate,KeyType=RANGE \<br />--provisioned-throughput ReadCapacityUnits=100,WriteCapacityUnits=100 </pre>`ReservationDate` 是一个纪元时间戳，将用于开启 TTL。 | 云架构师、应用程序开发人员 | 
| 开启 DynamoDB TTL。 | 使用 AWS CLI 为 `ReservationDate` 属性开启 DynamoDB TTL。<pre>aws dynamodb update-time-to-live \<br />--table-name Reservation\<br />  --time-to-live-specification Enabled=true,AttributeName=ReservationDate</pre> | 云架构师、应用程序开发人员 | 
| 开启 DynamoDB 流。 | 使用 AWS CLI 通过 `NEW_AND_OLD_IMAGES` 流类型为 `Reservation` 表打开 DynamoDB 流。 <pre>aws dynamodb update-table \<br />--table-name Reservation \<br />  --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES</pre>此流将包含新项目、更新项目、已删除项目和由 TTL 删除的项目的记录。由 TTL 删除的项目的记录包含一个额外的元数据属性，用于将其与手动删除的项目区分开来。TTL 删除的 `userIdentity` 字段表示 DynamoDB 服务执行了删除操作。 在这种模式中，只有通过 TTL 删除的项目才会被存档，但只能存档 `eventName` 为 `REMOVE` 以及 `userIdentity` 包含等于 `dynamodb.amazonaws.com` 的 `principalId` 的记录。 | 云架构师、应用程序开发人员 | 

### 创建和配置 S3 存储桶
<a name="create-and-configure-an-s3-bucket"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 S3 存储桶。 | 使用 AWS CLI 在您的 AWS 区域中创建目标 S3 存储桶，`us-east-1`替换为您的区域，将 amzn-s3-demo-destination-bucket 替换为存储桶的名称。 <pre>aws s3api create-bucket \<br />--bucket amzn-s3-demo-destination-bucket \<br />--region us-east-1</pre>确保 S3 存储桶名称是全局唯一的，因为命名空间由所有 AWS 账户共享。 | 云架构师、应用程序开发人员 | 
| 为 S3 存储桶创建 30 天的生命周期策略。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/automatically-archive-items-to-amazon-s3-using-dynamodb-ttl.html) | 云架构师、应用程序开发人员 | 

### 创建 Firehose 传输流
<a name="create-a-akf-delivery-stream"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建并配置 Firehose 传输流。 | 从 GitHub 存储库下载并编辑`CreateFireHoseToS3.py`代码示例。 此代码使用 Python 编写，向您展示如何创建 Firehose 传输流和 AWS Identity and Access Management（IAM）角色。IAM 角色将有一个策略，Firehose 可以使用该策略写入目标 S3 存储桶。要运行该脚本，使用以下命令和命令行参数。参数 1= `<Your_S3_bucket_ARN>`，这是您之前创建的存储桶的 Amazon 资源名称（ARN）参数 2= Firehose 名称（此试点正在使用 `firehose_to_s3_stream`。）参数 3= IAM 角色名称（此试点正在使用 `firehose_to_s3`。）<pre>python CreateFireHoseToS3.py <Your_S3_Bucket_ARN> firehose_to_s3_stream firehose_to_s3</pre>如果指定的 IAM 角色不存在，则该脚本将创建一个具有可信关系策略和授予充足 Amazon S3 权限的策略的分派角色。有关这些政策的示例，请参阅*其他信息*部分。 | 云架构师、应用程序开发人员 | 
| 验证 Firehose 传输流。 | 通过使用 AWS CLI 描述 Firehose 传输流，以验证该传输流是否已成功创建。<pre>aws firehose describe-delivery-stream --delivery-stream-name firehose_to_s3_stream </pre> | 云架构师、应用程序开发人员 | 

### 创建 Lambda 函数来处理 Firehose 传输流
<a name="create-a-lambda-function-to-process-the-akf-delivery-stream"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 Lambda 函数的信任策略。 | 请使用以下信息创建信任策略文件。<pre> {<br />     "Version": "2012-10-17",		 	 	 <br />     "Statement": [<br />      {<br />          "Effect": "Allow",<br />          "Principal": {<br />              "Service": "lambda.amazonaws.com"<br />           },<br />           "Action": "sts:AssumeRole"<br />      }<br />    ]<br />  } </pre>这向您的函数授予访问 AWS 资源的权限。 | 云架构师、应用程序开发人员 | 
| 创建 Lambda 函数的执行角色。 | 要创建执行角色，请运行以下代码。<pre>aws iam create-role --role-name lambda-ex --assume-role-policy-document file://TrustPolicy.json</pre> | 云架构师、应用程序开发人员 | 
| 向角色添加权限。 | 要向角色添加权限，请使用 `attach-policy-to-role` 命令。<pre>aws iam attach-role-policy --role-name lambda-ex --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole<br />aws iam attach-role-policy --role-name lambda-ex --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole<br />aws iam attach-role-policy --role-name lambda-ex --policy-arn arn:aws:iam::aws:policy/AmazonKinesisFirehoseFullAccess<br />aws iam attach-role-policy --role-name lambda-ex --policy-arn arn:aws:iam::aws:policy/IAMFullAccess </pre> | 云架构师、应用程序开发人员 | 
| 创建一个 Lambda 函数。 | 通过运行以下命令从代码存储库中压缩 `LambdaStreamProcessor.py` 文件。<pre>zip function.zip LambdaStreamProcessor.py</pre>当创建 Lambda 函数时，您将需要 Lambda 执行角色 ARN。要获取 ARN，请运行以下代码。<pre>aws iam get-role \<br />--role-name lambda-ex </pre>要创建 Lambda 函数，请运行以下代码。<pre># Review the environment variables and replace them with your values.<br /><br />aws lambda create-function --function-name LambdaStreamProcessor \<br />--zip-file fileb://function.zip --handler LambdaStreamProcessor.handler --runtime python3.8 \<br />--role {Your Lamda Execution Role ARN}\<br />  --environment Variables="{firehose_name=firehose_to_s3_stream,bucket_arn = <Your_S3_bucket_ARN>,iam_role_name = firehose_to_s3, batch_size=400}"</pre> | 云架构师、应用程序开发人员 | 
| 配置 Lambda 函数触发器。 | 使用 AWS CLI 配置触发器（DynamoDB Streams），该触发器将调用 Lambda 函数。批量大小为 400 是为了避免遇到 Lambda 并发问题。<pre>aws lambda create-event-source-mapping --function-name LambdaStreamProcessor \<br />--batch-size 400 --starting-position LATEST \<br />--event-source-arn <Your Latest Stream ARN From DynamoDB Console></pre> | 云架构师、应用程序开发人员 | 

### 测试功能
<a name="test-the-functionality"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 将时间戳已过期的项目添加到预留表。 | 要测试该功能，请将带有过期纪元时间戳的项目添加到 `Reservation` 表中。TTL 将根据时间戳自动删除项目。 Lambda 函数是在 DynamoDB Stream 活动时启动的，它会筛选事件以识别 `REMOVE` 活动或已删除的项目。然后，它以批处理格式将记录放入 Firehose 传输流中。Firehose 传输流将项目传输到带有 `firehosetos3example/year=current year/month=current month/ day=current day/hour=current hour/` 前缀的目标 S3 存储桶。要优化数据检索，请使用 `Prefix` 和 `ErrorOutputPrefix` 配置 Amazon S3，详见*其他信息*部分。 | 云架构师  | 

### 清理资源
<a name="clean-up-the-resources"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 删除所有资源。 | 删除所有资源，确保不会为未使用的任何服务付费。  | 云架构师、应用程序开发人员 | 

## 相关资源
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl-resources"></a>
+ [管理存储生命周期](https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html)
+ [Amazon S3 存储类](https://aws.amazon.com/s3/storage-classes/)
+ [适用于 Python 的 Amazon SDK（Boto3）文档](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html)

## 附加信息
<a name="automatically-archive-items-to-amazon-s3-using-dynamodb-ttl-additional"></a>

**创建并配置 Firehose 传输流 – 策略示例**

*Firehose 可信关系策略示例文档*

```
firehose_assume_role = {
        'Version': '2012-10-17',
        'Statement': [
            {
                'Sid': '',
                'Effect': 'Allow',
                'Principal': {
                    'Service': 'firehose.amazonaws.com'
                },
                'Action': 'sts:AssumeRole'
            }
        ]
    }
```

*S3 权限策略示例*

```
s3_access = {
        "Version": "2012-10-17",		 	 	 
        "Statement": [
            {
                "Sid": "",
                "Effect": "Allow",
                "Action": [
                    "s3:AbortMultipartUpload",
                    "s3:GetBucketLocation",
                    "s3:GetObject",
                    "s3:ListBucket",
                    "s3:ListBucketMultipartUploads",
                    "s3:PutObject"
                ],
                "Resource": [
                    "{your s3_bucket ARN}/*",
                    "{Your s3 bucket ARN}"
                ]
            }
        ]
    }
```

**测试功能 – Amazon S3 配置**

选择具有以下 `Prefix` 和 `ErrorOutputPrefix` 前缀的 Amazon S3 配置来优化数据检索。 

*prefix*

```
firehosetos3example/year=! {timestamp: yyyy}/month=! {timestamp:MM}/day=! {timestamp:dd}/hour=!{timestamp:HH}/
```

Firehose 首先直接在 S3 存储桶下创建名为 `firehosetos3example` 的基本文件夹。然后，它使用 Java [DateTimeFormatter](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html)格式`!{timestamp:HH}`将表达式`!{timestamp:yyyy}``!{timestamp:MM}``!{timestamp:dd}`、、和计算为年、月、日和小时。

例如，在 Unix 纪元时间中，1604683577 的近似到达时间戳的评估结果为 `year=2020`、`month=11`、`day=06` 和 `hour=05`。因此，Amazon S3 中数据记录的传输位置评估为 `firehosetos3example/year=2020/month=11/day=06/hour=05/`。

*ErrorOutputPrefix*

```
firehosetos3erroroutputbase/!{firehose:random-string}/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd}/
```

`ErrorOutputPrefix` 结果会直接在 S3 存储桶下生成名为 `firehosetos3erroroutputbase` 的基本文件夹。表达式 `!{firehose:random-string}` 的评估结果为 11 个字符的随机字符串，例如 `ztWxkdg3Thg`。传输失败记录的 Amazon S3 对象的位置可以评估为 `firehosetos3erroroutputbase/ztWxkdg3Thg/processing-failed/2020/11/06/`。