

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 Amazon API Gateway 和 Amazon DynamoDB Streams 非同步處理事件
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams"></a>

*Andrea Meroni、Mariem Kthiri、Nadim Majed、Alessandro Trisolini 和 Michael Wallner，Amazon Web Services*

## 總結
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-summary"></a>

[Amazon API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) 是一項全受管服務，開發人員可用來建立、發佈、維護、監控和保護任何規模APIs。它會處理涉及接受和處理多達數十萬個並行 API 呼叫的任務。

API Gateway 的一項重要服務配額是整合逾時。逾時是後端服務必須在 REST API 傳回錯誤之前傳回回應的最長時間。對於同步工作負載，通常可接受 29 秒的硬性限制。不過，該限制對想要將 API Gateway 與非同步工作負載搭配使用的開發人員來說是一項挑戰。

此模式顯示使用 API Gateway、Amazon DynamoDB Streams 和 非同步處理事件的範例架構 AWS Lambda。架構支援使用相同的輸入參數執行平行處理任務，並使用基本 REST API 做為界面。在此範例中，使用 Lambda 做為後端會將任務持續時間限制為 15 分鐘。您可以使用替代服務來處理傳入事件 （例如，)，以避免此限制 AWS Fargate。

[Projen](https://pypi.org/project/projen/) 用於設定本機開發環境 AWS 帳戶，以及搭配 [AWS Cloud Development Kit (AWS CDK) Toolkit](https://docs.aws.amazon.com/cdk/v2/guide/cli.html)、[Docker](https://docs.docker.com/get-docker/) 和 [Node.js](https://nodejs.org/en/download/) 將範例架構部署至目標。Projen 會自動使用[預先遞交](https://pre-commit.com/)和用於程式碼品質保證、安全掃描和單元測試的工具來設定 [Python](https://www.python.org/downloads/) 虛擬環境。如需詳細資訊，請參閱[工具](#processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-tools)一節。

## 先決條件和限制
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-prereqs"></a>

**先決條件 **
+ 作用中 AWS 帳戶
+ 工作站上安裝了下列工具：
  + [AWS Cloud Development Kit (AWS CDK) 工具組](https://docs.aws.amazon.com/cdk/v2/guide/cli.html) 2.85.0 版或更新版本
  + [Docker](https://docs.docker.com/get-docker/) 20.10.21 版或更新版本
  + [Node.js](https://nodejs.org/en/download/) 第 18 版或更新版本
  + [Projen](https://pypi.org/project/projen/) 0.71.111 版或更新版本
  + [Python](https://www.python.org/downloads/) 3.9.16 版或更新版本

**限制 **
+ DynamoDB Streams 建議的讀取器數目上限為兩個，以避免限流。
+ 任務的最大執行時間受限於 Lambda 函數的最大執行時間 (15 分鐘）。
+ 並行任務請求的數量上限受限於 Lambda 函數的預留並行。

## Architecture
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-architecture"></a>

**架構**

下圖顯示任務 API 與 DynamoDB Streams 的互動，以及事件處理和錯誤處理 Lambda 函數的互動，以及存放在 Amazon EventBridge 事件封存中的事件。

![\[架構和程序的圖表，步驟列在圖表後面。\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/patterns/images/pattern-img/68a46501-16e5-48e4-99c6-fc67a8b4133a/images/29fe6982-ad81-4099-9c65-08b17c96e78f.png)


典型的工作流程包括以下步驟：

1. 您可以驗證 AWS Identity and Access Management (IAM) 並取得安全登入資料。

1. 您可以將 HTTP `POST`請求傳送至`/jobs`任務 API 端點，在請求內文中指定任務參數。

1. 任務 API 會傳回包含任務識別符的 HTTP 回應給您。

1. 任務 API 會將任務參數放在 Amazon DynamoDB `jobs_table` 資料表中。

1. `jobs_table` DynamoDB 資料表 DynamoDB 串流會叫用事件處理 Lambda 函數。

1. 事件處理 Lambda 函數會處理事件，然後將任務結果放入 `jobs_table` DynamoDB 資料表。為了協助確保結果一致，事件處理函數實作[樂觀鎖定](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html)機制。

1. 您可以將 HTTP `GET`請求傳送至`/jobs/{jobId}`任務 API 端點，並將步驟 3 的任務識別符做為 `{jobId}`。

1. 任務 API 會查詢 `jobs_table` DynamoDB 資料表來擷取任務結果。

1. 任務 API 會傳回包含任務結果的 HTTP 回應。

1. 如果事件處理失敗，事件處理函數的來源映射會將事件傳送至錯誤處理 Amazon Simple Notification Service (Amazon SNS) 主題。

1. 錯誤處理 SNS 主題會以非同步方式將事件推送至錯誤處理函數。

1. 錯誤處理函數會將任務參數放在 `jobs_table` DynamoDB 資料表中。

   您可以透過傳送 HTTP `GET`請求至任務 API 端點來擷取`/jobs/{jobId}`任務參數。

1. 如果錯誤處理失敗，錯誤處理函數會將事件傳送至 Amazon EventBridge 封存。

   您可以使用 EventBridge 重播封存的事件。

## 工具
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-tools"></a>

**AWS 服務**
+ [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/v2/guide/home.html) 是一種軟體開發架構，可協助您在程式碼中定義和佈建 AWS 雲端基礎設施。
+ [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) 是一項全受管 NoSQL 資料庫服務，可提供快速、可預期且可擴展的效能。
+ [Amazon EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html) 是一種無伺服器事件匯流排服務，可協助您將應用程式與來自各種來源的即時資料連線。例如，AWS Lambda 函數、使用 API 目的地的 HTTP 調用端點，或其他 AWS 帳戶中的事件匯流排。
+ [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) 是一項運算服務，可協助您執行程式碼，無需佈建或管理伺服器。它只會在需要時執行程式碼並自動擴展，因此您只需支付使用的運算時間。
+ [Amazon Simple Notification Service (Amazon SNS)](https://docs.aws.amazon.com/sns/latest/dg/welcome.html) 可協助您協調和管理發佈者和用戶端之間的訊息交換，包括 Web 伺服器和電子郵件地址。

**其他工具**
+ [autopep8](https://github.com/hhatto/autopep8) 會根據 Python Enhancement Proposal (PEP) 8 樣式指南自動格式化 Python 程式碼。
+ [Bandit](https://bandit.readthedocs.io/en/latest/) 會掃描 Python 程式碼以尋找常見的安全問題。
+ [Commitizen](https://commitizen-tools.github.io/commitizen/) 是 Git 遞交檢查程式和`CHANGELOG`產生器。
+ [cfn-lint](https://github.com/aws-cloudformation/cfn-lint) 是 AWS CloudFormation linter
+ [Checkov](https://github.com/bridgecrewio/checkov) 是一種靜態程式碼分析工具，可將基礎設施檢查為程式碼 (IaC) 是否有安全性和合規設定錯誤。
+ [jq](https://stedolan.github.io/jq/download/) 是用於剖析 JSON 的命令列工具。
+ [Postman](https://www.postman.com/) 是 API 平台。
+ [預先遞交](https://pre-commit.com/)是 Git hooks 管理員。
+ [Projen](https://github.com/projen/projen) 是專案產生器。
+ [pytest](https://docs.pytest.org/en/7.2.x/index.html) 是一種 Python 架構，用於撰寫小型、可讀取的測試。

**程式碼儲存庫**

您可以在 GitHub [非同步處理搭配 API Gateway 和 DynamoDB Streams ](https://github.com/aws-samples/asynchronous-event-processing-api-gateway-dynamodb-streams-cdk)儲存庫中找到此架構程式碼範例。

## 最佳實務
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-best-practices"></a>
+ 此範例架構不包含對已部署基礎設施的監控。如果您的使用案例需要監控，請評估新增 [CDK 監控建構](https://constructs.dev/packages/cdk-monitoring-constructs)或其他監控解決方案。
+ 此範例架構使用 [IAM 許可](https://docs.aws.amazon.com/apigateway/latest/developerguide/permissions.html)來控制對任務 API 的存取。有權擔任 的任何人`JobsAPIInvokeRole`都可以叫用任務 API。因此，存取控制機制是二進位。如果您的使用案例需要更複雜的授權模型，請使用不同的[存取控制機制](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html)進行評估。
+ 當使用者傳送 HTTP `POST`請求到`/jobs`任務 API 端點時，輸入資料會在兩個不同的層級進行驗證：
  + API Gateway 負責第一個[請求驗證](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-method-request-validation.html)。
  + 事件處理函數會執行第二個請求。

    當使用者對`/jobs/{jobId}`任務 API 端點提出 HTTP `GET`請求時，不會執行驗證。如果您的使用案例需要額外的輸入驗證和更高的安全性，請使用 評估 [AWS WAF 來保護您的 API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-aws-waf.html)。
+ 為了避免限流，[DynamoDB Streams 文件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html#Streams.Processing)會阻止使用者從相同串流碎片中讀取兩個以上的取用者。若要擴展消費者數量，建議使用 [Amazon Kinesis Data Streams](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/kds.html)。
+ 此範例中已使用[樂觀鎖定](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html)，以確保 `jobs_table` DynamoDB 資料表中項目的一致更新。根據使用案例需求，您可能需要實作更可靠的鎖定機制，例如漸進式鎖定。

## 史詩
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-epics"></a>

### 設定環境
<a name="set-up-the-environment"></a>


| 任務 | Description | 所需的技能 | 
| --- | --- | --- | 
| 複製儲存庫。 | 若要在本機複製儲存庫，請執行下列命令：<pre>git clone https://github.com/aws-samples/asynchronous-event-processing-api-gateway-dynamodb-streams-cdk.git</pre> | DevOps 工程師 | 
| 設定專案。 | 將目錄變更為儲存庫根目錄，並使用 [Projen](https://github.com/projen/projen) 設定 Python 虛擬環境和所有工具：<pre>cd asynchronous-event-processing-api-gateway-api-gateway-dynamodb-streams-cdk<br />npx projen</pre> | DevOps 工程師 | 
| 安裝預先遞交掛鉤。 | 若要安裝預先遞交掛鉤，請執行下列動作：[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/patterns/processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams.html) | DevOps 工程師 | 

### 部署範例架構
<a name="deploy-the-example-architecture"></a>


| 任務 | Description | 所需的技能 | 
| --- | --- | --- | 
| 引導 AWS CDK。 | 若要在 [AWS CDK](https://aws.amazon.com/cdk/)中引導 AWS 帳戶，請執行下列命令：<pre>AWS_PROFILE=$YOUR_AWS_PROFILE npx projen bootstrap</pre> | AWS DevOps | 
| 部署範例架構。 | 若要在 中部署範例架構 AWS 帳戶，請執行下列命令：<pre>AWS_PROFILE=$YOUR_AWS_PROFILE npx projen deploy</pre> | AWS DevOps | 

### 測試架構
<a name="test-the-architecture"></a>


| 任務 | Description | 所需的技能 | 
| --- | --- | --- | 
| 安裝測試先決條件。 | 在工作站上安裝 [AWS Command Line Interface (AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)、[Postman](https://www.postman.com/downloads/) 和 [jq](https://jqlang.github.io/jq/)。建議使用 [Postman](https://www.postman.com/downloads/) 測試此範例架構，但並非強制性。如果您選擇替代 API 測試工具，請確定它支援 [AWS Signature 第 4 版身分驗證](https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html)，並參考可透過[匯出 REST API 檢查的公開 API ](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-export-api.html)端點。 | DevOps 工程師 | 
| 擔任 `JobsAPIInvokeRole`。 | [假設](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/assume-role.html)`JobsAPIInvokeRole`從 `deploy`命令列印為輸出的 ：<pre>CREDENTIALS=$(AWS_PROFILE=$<YOUR_AWS_PROFILE> aws sts assume-role \<br />--no-cli-pager \<br />--role-arn $<JOBS_API_INVOKE_ROLE_ARN> \<br />--role-session-name JobsAPIInvoke)<br />export AWS_ACCESS_KEY_ID=$(cat $CREDENTIALS | jq ‘.Credentials’’.AccessKeyId’)<br />export AWS_SECRET_ACCESS_KEY=$(cat $CREDENTIALS | jq ‘.Credentials’’.SecretAccessKey’)<br />export AWS_SESSION_TOKEN==$(cat $CREDENTIALS | jq ‘.Credentials’’.SessionToken’)</pre> | AWS DevOps | 
| 設定 Postman。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/patterns/processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams.html) | AWS DevOps | 
| 測試範例架構。 | 若要測試範例架構，請將請求傳送至任務 API。如需詳細資訊，請參閱 [Postman 文件](https://learning.postman.com/docs/getting-started/first-steps/sending-the-first-request/#send-an-api-request)。 | DevOps 工程師 | 

## 疑難排解
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-troubleshooting"></a>


| 問題 | 解決方案 | 
| --- | --- | 
| 範例架構的銷毀和後續重新部署失敗，因為 [Amazon CloudWatch Logs 日誌群組](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html)`/aws/apigateway/JobsAPIAccessLogs`已存在。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/patterns/processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams.html) | 

## 相關資源
<a name="processing-events-asynchronously-with-amazon-api-gateway-and-amazon-dynamodb-streams-resources"></a>
+ [API Gateway 映射範本和存取記錄變數參考](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html)
+ [變更 DynamoDB Streams 的資料擷取](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html)
+ [具有版本編號的樂觀鎖定](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html)
+ [使用 Kinesis Data Streams 擷取對 DynamoDB 的變更](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/kds.html)