

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

# 使用來自其他服務的事件叫用 Lambda AWS
<a name="lambda-services"></a>

有些 AWS 服務 可以使用*觸發*直接叫用 Lambda 函數。這些服務會將事件推送至 Lambda，並在發生指定事件時立即調用函數。觸發條件適用於離散事件和即時處理。當您[使用 Lambda 主控台建立觸發](#lambda-invocation-trigger)時，主控台會與對應的 AWS 服務互動，以在該服務上設定事件通知。觸發條件實際上由產生事件的服務 (而非 Lambda) 儲存和管理。

事件是以 JSON 格式構建的資料。JSON 結構因產生它的服務和事件類型而異，但它們都包含函數處理事件所需的資料。

函數可以有多個觸發條件。每個觸發條件皆做為獨立調用函數的用戶端，而 Lambda 傳遞給函數的每個事件只會包含來自一個觸發條件的資料。Lambda 將事件文件轉換為物件並將其傳遞給您的函數處理常式。

視服務而定，事件驅動型調用可以是[同步](invocation-sync.md)或[非同步](invocation-async.md)。
+ 對於同步調用，產生事件的服務會等待來自您的函數回應。該服務定義函數需要在回應中傳回的資料。服務控制項錯誤策略，例如發生錯誤時是否重試。
+ 對於非同步調用，Lambda 會先將事件排入佇列，再將事件傳送至您的函數。當 Lambda 將事件排入佇列時，它會立即向產生事件的服務傳送成功回應。在函數處理事件後，Lambda 不會向事件產生服務傳回回應。

## 建立觸發條件
<a name="lambda-invocation-trigger"></a>

建立觸發條件的最簡單方式是使用 Lambda 主控台。當您使用主控台建立觸發條件時，Lambda 會自動將必要的許可新增至函數的[資源型政策](access-control-resource-based.md)。

**若要使用 Lambda 主控台建立觸發條件**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選取您要為其建立觸發條件的函數。

1. 在**函數概觀**窗格中，選擇**新增觸發條件**。

1. 選取您要叫用函數 AWS 的服務。

1. 填寫**觸發條件組態**窗格中的選項，然後選擇**新增**。根據您 AWS 服務 選擇叫用函數的 ，觸發組態選項會有所不同。

## 可調用 Lambda 函數的服務
<a name="listing-of-services-and-links-to-more-information"></a>

下表列出可調用 Lambda 函數的服務。


****  

| 服務 | 調用的方法 | 
| --- | --- | 
|  [Amazon Managed Streaming for Apache Kafka](with-msk.md)  |  [事件來源映射](invocation-eventsourcemapping.md)  | 
|  [自我管理的 Apache Kafka](with-kafka.md)  |  [事件來源映射](invocation-eventsourcemapping.md)  | 
|  [Amazon API Gateway](services-apigateway.md)  |  事件驅動；同步調用  | 
|  [AWS CloudFormation](services-cloudformation.md)  |  事件驅動；非同步叫用  | 
|  [Amazon CloudWatch Logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#LambdaFunctionExample)  |  事件驅動；非同步調用  | 
|  [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/how-to-notify-lambda-cc.html)  |  事件驅動；非同步調用  | 
|  [AWS CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html)  |  事件驅動；非同步調用  | 
|  [Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-events.html)  |  事件驅動；同步調用  | 
|  [AWS Config](governance-config.md)  |  事件驅動；非同步調用  | 
|  [Amazon Connect](https://docs.aws.amazon.com/connect/latest/adminguide/connect-lambda-functions.html)  |  事件驅動；同步調用  | 
|  [Amazon DocumentDB](with-documentdb.md)  |  [事件來源映射](invocation-eventsourcemapping.md)  | 
|  [Amazon DynamoDB](with-ddb.md)  |  [事件來源映射](invocation-eventsourcemapping.md)  | 
|  [Elastic Load Balancing (Application Load Balancer)](services-alb.md)  |  事件驅動；同步調用  | 
|  [Amazon EventBridge (CloudWatch Events)](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html)  |  事件驅動型；非同步調用 (事件匯流排)、同步或非同步調用 (管道和排程)  | 
|  [AWS IoT](services-iot.md)  |  事件驅動；非同步調用  | 
|  [Amazon Kinesis](with-kinesis.md)  |  [事件來源映射](invocation-eventsourcemapping.md)  | 
|  [Amazon Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/data-transformation.html)  |  事件驅動；同步調用  | 
|  [Amazon Lex](https://docs.aws.amazon.com/lexv2/latest/dg/lambda.html)  |  事件驅動；同步調用  | 
|  [Amazon MQ](with-mq.md)  |  [事件來源映射](invocation-eventsourcemapping.md)  | 
|  [Amazon Simple Email Service](https://docs.aws.amazon.com/ses/latest/dg/receiving-email-action-lambda.html)  |  事件驅動；非同步調用  | 
|  [Amazon Simple Notification Service](with-sns.md)  |  事件驅動；非同步調用  | 
|  [Amazon Simple Queue Service](with-sqs.md)  |  [事件來源映射](invocation-eventsourcemapping.md)  | 
|  [Amazon Simple Storage Service (Amazon S3)](with-s3.md)  |  事件驅動；非同步調用  | 
|  [Amazon Simple Storage Service 批次](services-s3-batch.md)  |  事件驅動；同步調用  | 
|  [Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotate-secrets_lambda.html)  |  秘密輪換  | 
|  [AWS Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/connect-lambda.html)  |  事件驅動型；同步或非同步調用  | 
|  [Amazon VPC Lattice](https://docs.aws.amazon.com/vpc-lattice/latest/ug/lambda-functions.html)  |  事件驅動；同步調用  | 

# 將 Lambda 與 Apache Kafka 搭配使用
<a name="with-kafka-esm"></a>

Lambda 支援 [Apache Kafka](https://kafka.apache.org/) 作為[事件來源](invocation-eventsourcemapping.md)。Apache Kafka 是一種開放原始碼事件串流平台，旨在處理高輸送量、即時資料管道和串流應用程式。可透過以下兩種主要方式將 Lambda 與 Apache Kafka 搭配使用：
+ [搭配使用 Lambda 與 Amazon MSK](with-msk.md) – Amazon Managed Streaming for Apache Kafka (Amazon MSK) 是一種完全受管的服務 AWS。Amazon MSK 可協助自動管理 Kafka 基礎結構，包括佈建、修補和擴展。
+ [搭配使用 Lambda 與自我管理 Apache Kafka](with-kafka.md) – 在 AWS 術語中，自我管理叢集包含非AWS 託管的 Kafka 叢集。例如，您仍然可以將 Lambda 與託管於非AWS 雲端提供者的 Kafka 叢集搭配使用，例如 [ Confluent Cloud](https://www.confluent.io/confluent-cloud/) 或 [Redpanda](https://www.redpanda.com/)。

在決定使用 Amazon MSK 還是自我管理的 Apache Kafka 時，建議考量操作需求和控制要求。如果您想要 AWS 快速協助您以最少的營運開銷管理可擴展、生產就緒的 Kafka 設定，Amazon MSK 是更好的選擇。該服務能簡化安全性設定、監控機制與高可用性部署，讓您專注於應用程式開發，無需費心底層基礎結構管理。另一方面，自我管理的 Apache Kafka 更適合在非AWS 託管環境中執行的使用案例，包括內部部署叢集。

**Topics**
+ [

# 搭配使用 Lambda 與 Amazon MSK
](with-msk.md)
+ [

# 搭配使用 Lambda 與自我管理 Apache Kafka
](with-kafka.md)
+ [

# Lambda 中的 Apache Kafka 事件輪詢器擴展模式
](kafka-scaling-modes.md)
+ [

# Lambda 中的 Apache Kafka 輪詢與串流開始位置
](kafka-starting-positions.md)
+ [

# Lambda 中可自訂的取用者群組 ID
](kafka-consumer-group-id.md)
+ [

# 從 Amazon MSK 和自我管理的 Apache Kafka 事件來源篩選事件
](kafka-filtering.md)
+ [

# 在 Lambda 中將結構描述登錄檔與 Kafka 事件來源搭配使用
](services-consume-kafka-events.md)
+ [

# Kafka 事件來源的低延遲處理
](with-kafka-low-latency.md)
+ [

# 設定 Kafka 事件來源的錯誤處理控制項
](kafka-retry-configurations.md)
+ [

# 擷取 Amazon MSK 和自我管理的 Apache Kafka 事件來源的捨棄批次
](kafka-on-failure.md)
+ [

# 使用 Kafka 主題做為失敗時的目的地
](kafka-on-failure-destination.md)
+ [

# Kafka 事件來源映射記錄
](esm-logging.md)
+ [

# 對 Kafka 事件來源映射錯誤進行疑難排解
](with-kafka-troubleshoot.md)

# 搭配使用 Lambda 與 Amazon MSK
<a name="with-msk"></a>

[Amazon Managed Streaming for Apache Kafka (Amazon MSK)](https://docs.aws.amazon.com/msk/latest/developerguide/what-is-msk.html) 是一項全受管服務，可讓您建立並執行使用 Apache Kafka 處理串流資料的應用程式。Amazon MSK 簡化了 Kafka 叢集的設定、擴展與管理流程。Amazon MSK 也可讓您更輕鬆地為多個可用區域設定應用程式，並使用 AWS Identity and Access Management (IAM) 確保安全。

本章說明了如何將 Amazon MSK 叢集用作 Lambda 函式的事件來源。將 Amazon MSK 與 Lambda 整合的一般流程包含以下步驟：

1. **[叢集與網路設定](with-msk-cluster-network.md)**：首先，設定 [Amazon MSK 叢集](https://docs.aws.amazon.com/msk/latest/developerguide/what-is-msk.html)。這包括設定允許 Lambda 存取叢集所需的正確聯網組態。

1. **[事件來源映射設定](with-msk-configure.md)**：接著，建立 Lambda 所需的[事件來源映射](invocation-eventsourcemapping.md)資源，將 Amazon MSK 叢集安全地連線至函式。

1. **[函式與許可設定](with-msk-permissions.md)**：最後，確保函式已正確設定，並且其[執行角色](lambda-intro-execution-role.md)具有必要許可。

**注意**  
您現在可以直接從 Lambda 或 Amazon MSK 主控台建立和管理 Amazon MSK 事件來源映射。兩個主控台都提供選項，可自動處理設定必要的 Lambda 執行角色許可，以便更簡化的組態程序。

如需如何設定 Lambda 與 Amazon MSK 叢集整合的範例，請參閱 AWS 《運算部落格》中的[教學課程：使用 Amazon MSK 事件來源映射來調用 Lambda 函數](services-msk-tutorial.md)[使用 Amazon MSK 做為 的事件來源 AWS Lambda](https://aws.amazon.com/blogs/compute/using-amazon-msk-as-an-event-source-for-aws-lambda/)，以及[《Amazon MSK 實驗室》中的 Amazon MSK Lambda 整合](https://amazonmsk-labs.workshop.aws/en/msklambda.html)。

**Topics**
+ [

## 範例事件
](#msk-sample-event)
+ [

# 為 Lambda 設定 Amazon MSK 叢集與 Amazon VPC 網路
](with-msk-cluster-network.md)
+ [

# 設定 Amazon MSK 事件來源映射的 Lambda 許可
](with-msk-permissions.md)
+ [

# 設定 Lambda 的 Amazon MSK 事件來源
](with-msk-configure.md)
+ [

# 教學課程：使用 Amazon MSK 事件來源映射來調用 Lambda 函數
](services-msk-tutorial.md)

## 範例事件
<a name="msk-sample-event"></a>

Lambda 會在調用函數時，在事件參數中傳送訊息批次。事件酬載包含訊息陣列。陣列中的每個項目包含 Amazon MSK 主題和分割區識別符的詳細資訊，以及時間戳記和 base64 編碼的訊息。

```
{
   "eventSource":"aws:kafka",
   "eventSourceArn":"arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2",
   "bootstrapServers":"b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
   "records":{
      "mytopic-0":[
         {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "key":"abcDEFghiJKLmnoPQRstuVWXyz1234==",
            "value":"SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
            "headers":[
               {
                  "headerKey":[
                     104,
                     101,
                     97,
                     100,
                     101,
                     114,
                     86,
                     97,
                     108,
                     117,
                     101
                  ]
               }
            ]
         }
      ]
   }
}
```

# 為 Lambda 設定 Amazon MSK 叢集與 Amazon VPC 網路
<a name="with-msk-cluster-network"></a>

若要將 AWS Lambda 函數連線至 Amazon MSK 叢集，您需要正確設定叢集及其所在的 [Amazon Virtual Private Cloud (VPC)](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html)。本頁介紹了如何設定叢集與 VPC。如果叢集與 VPC 已正確設定，請參閱[設定 Lambda 的 Amazon MSK 事件來源](with-msk-configure.md)，設定事件來源映射。

**Topics**
+ [

## Lambda 與 MSK 整合的網路組態需求概觀
](#msk-network-requirements)
+ [

## 為 MSK 事件來源設定 NAT 閘道
](#msk-nat-gateway)
+ [

## 設定 MSK 事件來源的 AWS PrivateLink 端點
](#msk-vpc-privatelink)

## Lambda 與 MSK 整合的網路組態需求概觀
<a name="msk-network-requirements"></a>

Lambda 與 MSK 整合所需的聯網組態取決於應用程式的網路架構。此整合涉及三種主要資源：Amazon MSK 叢集、Lambda 函式、Lambda 事件來源映射。這些資源各自位於不同的 VPC 內：
+ Amazon MSK 叢集通常位於您管理的 VPC 的私有子網路內。
+ 您的 Lambda 函數位於 Lambda AWS擁有的受管 VPC 中。
+ 您的 Lambda 事件來源映射位於 Lambda AWS擁有的另一個受管 VPC 中，與包含函數的 VPC 分開。

[事件來源映射](invocation-eventsourcemapping.md)是 MSK 叢集與 Lambda 函式之間的媒介資源。事件來源映射有兩個主要任務。首先，其會輪詢 MSK 叢集來取得新訊息。然後，其會使用這些訊息來調用 Lambda 函式。由於這三種資源位於不同的 VPC 內，輪詢與調用操作皆須跨 VPC 網路進行呼叫。

事件來源映射所需的網路組態取決於其是使用[佈建模式](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)還是隨需模式，如下圖所示：

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/MSK-esm-network-overview.png)


在這兩種模式下，Lambda 事件來源映射輪詢 MSK 叢集取得新訊息的方式一致。為了在事件來源映射與 MSK 叢集之間建立連線，Lambda 會在私有子網路內建立 [Hyperplane ENI](configuration-vpc.md#configuration-vpc-enis) (或在可用時重複使用現有介面)，以此建立安全連線。如圖所示，此 Hyperplane ENI 會使用 MSK 叢集的子網路和安全群組組態，而不是 Lambda 函式。

從叢集輪詢訊息之後，Lambda 調用函式的方式在每種模式下有所不同：
+ 在佈建模式下，Lambda 會自動處理事件來源映射 VPC 與函式 VPC 之間的連線。因此，無需任何其他聯網元件，即能成功調用函式。
+ 在隨需模式下，Lambda 事件來源映射會透過客戶自管 VPC 的路徑來調用函式。因此，您需要在 VPC 的公有子網路內設定 [NAT 閘道](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)，或者在 VPC 的私有子網路內設定 [AWS PrivateLink](https://docs.aws.amazon.com/vpc/latest/privatelink/what-is-privatelink.html) 端點，這些端點需提供對 Lambda、[AWS Security Token Service (STS)](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html) 的存取權，並可選擇性提供對 [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 的存取權。正確設定其中一個選項，即可在 VPC 與 Lambda 受管執行時期 VPC 之間建立連線，這是調用函式的必要條件。

NAT 閘道允許私有子網路內的資源存取公有網際網路。使用此組態表示您的流量在叫用 Lambda 函數之前周遊網際網路。 AWS PrivateLink 端點可讓私有子網路安全地連線至 AWS 服務或其他私有 VPC 資源，而不會周遊公有網際網路。有關如何設定這些資源的詳細資訊，請參閱[為 MSK 事件來源設定 NAT 閘道](#msk-nat-gateway)或[設定 MSK 事件來源的 AWS PrivateLink 端點](#msk-vpc-privatelink)。

截至目前，我們皆假設 MSK 叢集位於 VPC 的私有子網路內，這也是常見情況。不過，即使 MSK 叢集位於 VPC 的公有子網路內，您仍需設定 AWS PrivateLink 端點，才能啟用安全連線。下表根據設定 MSK 叢集和 Lambda 事件來源映射的方式，摘要說明了聯網組態要求：


| MSK 叢集位置 (位於客戶自管 VPC 內) | Lambda 事件來源映射擴展模式 | 必要的聯網組態 | 
| --- | --- | --- | 
|  私有子網路  |  隨需模式  |  NAT 閘道 （位於 VPC 的公有子網路中） 或 AWS PrivateLink 端點 （位於 VPC 的私有子網路中），以啟用對 Lambda 的存取 AWS STS，以及選擇性的 Secrets Manager。  | 
|  公有子網路  |  隨需模式  |  AWS PrivateLink 端點 （在 VPC 的公有子網路中），以啟用對 Lambda 的存取 AWS STS，以及選用的 Secrets Manager。  | 
|  私有子網路  |  佈建模式  |  無  | 
|  公有子網路  |  佈建模式  |  無  | 

此外，與 MSK 叢集相關聯的安全群組必須允許正確連接埠的流量。確保您已設定下列安全群組規則：
+ **傳入規則**：允許預設代理程式連接埠上的所有流量。MSK 使用的連接埠取決於叢集上的身分驗證類型：`9098` 用於 IAM 身分驗證、`9096` 用於 SASL/SCRAM，`9094` 用於 TLS。或者，您可使用自我參照安全群組規則，允許來自同一安全群組內其他執行個體的存取。
+ **傳出規則** – 如果您的函數需要與其他 `443` AWS 服務通訊，允許外部目的地連接埠上的所有流量。或者，如果您不需要與其他 AWS 服務通訊，您可以使用自我參考安全群組規則來限制對代理程式的存取。
+ **Amazon VPC 端點傳入規則**：若您使用 Amazon VPC 端點，與該端點相關聯的安全群組必須允許來自叢集安全群組 `443` 連接埠的傳入流量。

## 為 MSK 事件來源設定 NAT 閘道
<a name="msk-nat-gateway"></a>

您可以設定 NAT 閘道，允許事件來源映射從叢集輪詢訊息，並透過 VPC 的路徑調用函式。僅在事件來源映射使用隨需模式，且叢集位於 VPC 的私有子網路內時才需要此操作。如果叢集位於 VPC 的公有子網路內，或者事件來源映射使用佈建模式，則無需設定 NAT 閘道。

[NAT 閘道](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)允許私有子網路內的資源存取公有網際網路。如需與 Lambda 建立私有連線，請改為參閱[設定 MSK 事件來源的 AWS PrivateLink 端點](#msk-vpc-privatelink)。

設定 NAT 閘道之後，必須設定正確的路由表。這將允許來自私有子網路的流量透過 NAT 閘道路由至公有網際網路。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/MSK-NAT-Gateway.png)


下列步驟將引導您使用主控台設定 NAT 閘道。視需要針對每個可用區域 (AZ) 重複這些步驟。

**設定 NAT 閘道和正確路由 (主控台)**

1. 請遵循[建立 NAT 閘道](https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-working-with.html)中的步驟，同時注意下列事項：
   + NAT 閘道應始終位於公有子網路內。建立具有[公有連線](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)的 NAT 閘道。
   + 如果 MSK 叢集跨多個可用區域複寫，請為每個可用區域建立一個 NAT 閘道。例如，在每個可用區域中，VPC 應該有一個包含叢集的私有子網路，以及一個包含 NAT 閘道的公有子網路。對於具有三個可用區域的設定，您將擁有三個私有子網路、三個公有子網路及三個 NAT 閘道。

1. 建立 NAT 閘道之後，開啟 [Amazon VPC 主控台](https://console.aws.amazon.com/vpc/)，然後在左側功能表中選擇**路由表**。

1. 選擇 **Create route table** (建立路由表)。

1. 將此路由表與包含 MSK 叢集的 VPC 建立關聯。或者，輸入路由表的名稱。

1. 選擇 **Create route table** (建立路由表)。

1. 選擇剛剛建立的路由表。

1. 在**子網路關聯**索引標籤中，選擇**編輯子網路關聯**。
   + 將此路由表與包含 MSK 叢集的私有子網路建立關聯。

1. 選擇 **Edit routes** (編輯路由)。

1. 選擇**新增路由**：

   1. 對於 **Destination (目的地)**，請選擇 `0.0.0.0/0`。

   1. 在**目標**欄位中，選擇 **NAT 閘道**。

   1. 在搜尋方塊中，選擇在步驟 1 中建立的 NAT 閘道。這應該是與包含 MSK 叢集的私有子網路 (您在步驟 6 中與此路由表相關聯的私有子網路) 位於同一可用區域中的 NAT 閘道。

1. 選擇**儲存變更**。

## 設定 MSK 事件來源的 AWS PrivateLink 端點
<a name="msk-vpc-privatelink"></a>

您可以將 AWS PrivateLink 端點設定為從叢集輪詢訊息，並透過 VPC 透過路徑叫用函數。這些端點應允許 MSK 叢集存取下列服務：
+ Lambda 服務
+ [AWS Security Token Service (STS)](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html)
+ (選用) [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 服務。若叢集身分驗證所需的秘密儲存在 Secrets Manager 中，則此為必要項目。

僅在事件來源映射使用隨需模式時，才需要設定 PrivateLink 端點。如果事件來源映射使用佈建模式，Lambda 會代為建立必要連線。

PrivateLink 端點允許安全的私有存取 AWS 服務 AWS PrivateLink。或者，若要設定 NAT 閘道以讓 MSK 叢集存取公有網際網路，請參閱[為 MSK 事件來源設定 NAT 閘道](#msk-nat-gateway)。

設定 VPC 端點之後，MSK 叢集應可直接且透過私有方式存取 Lambda、STS，以及選擇性地存取 Secrets Manager。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/MSK-PrivateLink-Endpoints.png)


下列步驟將引導您使用主控台設定 PrivateLink 端點。視需要針對每個端點 (Lambda、STS、Secrets Manager) 重複這些步驟。

**設定 VPC PrivateLink 端點 (主控台)**

1. 開啟 [Amazon VPC 主控台](https://console.aws.amazon.com/vpc/)，然後在左側功能表中選擇**端點**。

1. 選擇**建立端點**。

1. 或者，輸入端點的名稱。

1. 在**類型**欄位中，選擇 **AWS 服務**。

1. 在**服務**欄位中，開始輸入服務的名稱。例如，若要建立連線至 Lambda 的端點，請在搜尋方塊中輸入 `lambda`。

1. 在結果中，您應能看到目前區域的服務端點。例如，在美國東部 (維吉尼亞北部) 區域，您應該會看到 `com.amazonaws.us-east-2.lambda`。選取該服務。

1. 在**網路設定**欄位中，選取包含 MSK 叢集的 VPC。

1. 在**子網路**欄位中，選取 MSK 叢集所在的可用區域。
   + 對於每個可用區域，在**子網路 ID** 欄位中，選擇包含 MSK 叢集的私有子網路。

1. 在**安全群組**欄位中，選取與 MSK 叢集相關聯的安全群組。

1. 選擇**建立端點**。

根據預設，Amazon VPC 端點具有開放的 IAM 政策，允許廣泛存取資源。最佳實務是限制這些政策，以使用該端點執行所需的動作。例如，對於 Secrets Manager 端點，您可以修改其政策，使其僅允許函式的執行角色存取秘密。

**Example VPC 端點政策：Secrets Manager 端點**  

```
{
    "Statement": [
        {
            "Action": "secretsmanager:GetSecretValue",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws::iam::123456789012:role/my-role"
                ]
            },
            "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
        }
    ]
}
```

對於 AWS STS 和 Lambda 端點，您可以將呼叫委託人限制為 Lambda 服務委託人。但是，請確定在這些政策使用 `"Resource": "*"`。

**Example VPC 端點政策 – AWS STS 端點**  

```
{
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "lambda.amazonaws.com"
                ]
            },
            "Resource": "*"
        }
    ]
}
```

**Example VPC 端點政策：Lambda 端點**  

```
{
    "Statement": [
        {
            "Action": "lambda:InvokeFunction",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "lambda.amazonaws.com"
                ]
            },
            "Resource": "*"
        }
    ]
}
```

# 設定 Amazon MSK 事件來源映射的 Lambda 許可
<a name="with-msk-permissions"></a>

若要存取 Amazon MSK 叢集，函式和事件來源映射需要執行各種 Amazon MSK API 動作的許可。將這些許可新增至函式的[執行角色](lambda-intro-execution-role.md)。如果使用者需要存取權，請將必要許可新增至使用者或角色的身分政策。

[AWSLambdaMSKExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaMSKExecutionRole.html) 受管政策包含 Amazon MSK Lambda 事件來源映射所需的最低許可。若要簡化許可程序，您可以：
+ 將 [AWSLambdaMSKExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaMSKExecutionRole.html) 受管政策連接至您的執行角色。
+ 讓 Lambda 主控台為您產生許可。當您[在主控台中建立 Amazon MSK 事件來源映射](msk-esm-create.md#msk-console)時，Lambda 會評估您的執行角色，並在缺少任何許可時提醒您。選擇**產生許可**以自動更新您的執行角色。如果您手動建立或修改執行角色政策，或者政策連接到多個角色，則此功能不適用。請注意，使用[失敗時目的地](kafka-on-failure.md)或[AWS Glue 結構描述登錄](services-consume-kafka-events.md)檔等進階功能時，執行角色可能仍需要額外的許可。

**Topics**
+ [

## 所需的許可
](#msk-required-permissions)
+ [

## 可選的許可。
](#msk-optional-permissions)

## 所需的許可
<a name="msk-required-permissions"></a>

您的 Lambda 函數執行角色必須具有下列 Amazon MSK 事件來源映射的必要許可。這些許可包含在 [AWSLambdaMSKExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaMSKExecutionRole.html) 受管政策中。

### CloudWatch Logs 許可
<a name="msk-basic-permissions"></a>

下列許可允許 Lambda 在 Amazon CloudWatch Logs 中建立和存放日誌。
+ [logs:CreateLogGroup](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
+ [logs:CreateLogStream](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html)
+ [日誌：PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)

### MSK 叢集許可
<a name="msk-cluster-permissions"></a>

下列許可允許 Lambda 代表您存取您的 Amazon MSK 叢集：
+ [kafka:DescribeCluster](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn.html)
+ [kafka:DescribeClusterV2](https://docs.aws.amazon.com/MSK/2.0/APIReference/v2-clusters-clusterarn.html)
+ [kafka:GetBootstrapBrokers](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn-bootstrap-brokers.html)

我們建議您使用 [kafka：DescribeClusterV2](https://docs.aws.amazon.com/MSK/2.0/APIReference/v2-clusters-clusterarn.html)，而非 [kafka：DescribeCluster](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn.html)。v2 許可適用於佈建和無伺服器 Amazon MSK 叢集。您只需要政策中的其中一個許可。

### VPC 許可
<a name="msk-vpc-permissions"></a>

下列許可允許 Lambda 在連線至 Amazon MSK 叢集時建立和管理網路介面：
+ [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
+ [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
+ [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
+ [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
+ [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
+ [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)

## 可選的許可。
<a name="msk-optional-permissions"></a>

 您的 Lambda 函數可能需要許可，才能：
+ 存取跨帳戶 Amazon MSK 叢集。對於跨帳戶事件來源映射，您需要執行角色中的 [kafka：DescribeVpcConnection](https://docs.aws.amazon.com/msk/1.0/apireference/vpc-connection-arn.html)。建立跨帳戶事件來源映射的 IAM 主體需要 [kafka：ListVpcConnections](https://docs.aws.amazon.com/msk/1.0/apireference/vpc-connections.html)。
+ 存取 SCRAM 秘密 (若使用 [SASL/SCRAM 身分驗證](msk-cluster-auth.md#msk-sasl-scram))。此舉可讓函式透過使用者名稱與密碼連線至 Kafka。
+ 描述 Secrets Manager 秘密 (若使用 SASL/SCRAM 或 [mTLS 身分驗證](msk-cluster-auth.md#msk-mtls))。此舉可讓函式擷取安全連線所需的憑證或認證。
+ 如果您的 AWS Secrets Manager 秘密是使用 AWS KMS 客戶受管金鑰加密，請存取您的 AWS KMS 客戶受管金鑰。
+ 存取結構描述登錄檔秘密 (若使用的結構描述登錄檔需進行身分驗證)：
  + 對於 AWS Glue 結構描述登錄檔：您的函數需求`glue:GetRegistry`和`glue:GetSchemaVersion`許可。這些許可能夠讓函式查詢並使用儲存在 AWS Glue中的訊息格式規則。
  + 對於使用 `BASIC_AUTH` 或 `CLIENT_CERTIFICATE_TLS_AUTH` 的 [Confluent 結構描述登錄檔](https://docs.confluent.io/platform/current/schema-registry/security/index.html)：函式需要對包含身分驗證憑證的秘密具有 `secretsmanager:GetSecretValue` 許可。這可讓函式擷取存取 Confluent 結構描述登錄檔所需的使用者名稱/密碼或憑證。
  + 對於私有 CA 憑證：函式需要對包含憑證的秘密具有 secretsmanager:GetSecretValue 許可。此舉可讓函式驗證使用自訂憑證的結構描述登錄檔身分。
+ 如果您使用 IAM 身分驗證進行事件來源映射，請從主題存取 Kafka 叢集取用者群組和輪詢訊息。

 這些對應至下列必要許可：
+ [kafka:ListScramSecrets](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn-scram-secrets.html) – 允許列出用於 Kafka 身分驗證的 SCRAM 秘密
+ [secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html) – 允許從 Secrets Manager 擷取秘密
+ [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) - 允許使用 解密加密的資料 AWS KMS
+ [glue：GetRegistry](https://docs.aws.amazon.com/glue/latest/webapi/API_GetRegistry.html) - 允許存取 AWS Glue 結構描述登錄檔
+ [glue：GetSchemaVersion](https://docs.aws.amazon.com/glue/latest/webapi/API_GetSchemaVersion.html) - 啟用從結構描述登錄檔擷取特定 AWS Glue 結構描述版本
+ [kafka-cluster：Connect](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - 准許連線至叢集並進行驗證
+ [kafka-cluster：AlterGroup](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - 准許加入叢集上的群組，相當於 Apache Kafka 的 READ GROUP ACL
+ [kafka-cluster：DescribeGroup](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - 准許描述叢集上的群組，相當於 Apache Kafka 的 DESCRIBE GROUP ACL
+ [kafka-cluster：DescribeTopic](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - 准許描述叢集上的主題，相當於 Apache Kafka 的 DESCRIBE TOPIC ACL
+ [kafka-cluster：ReadData](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - 准許從叢集上的主題讀取資料，相當於 Apache Kafka 的 READ TOPIC ACL

 此外，若想將失敗調用的記錄傳送至失敗時目的地，根據目的地類型，您將需要下列許可：
+ 對於 Amazon SQS 目的地：[sqs:SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) – 允許將訊息傳送至 Amazon SQS 佇列
+ 對於 Amazon SNS 目的地：[sns:Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html) – 允許將訊息發布至 Amazon SNS 主題
+ 對於 Amazon S3 儲存貯體目的地：[s3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 與 [s3：ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucket.html) – 允許在 Amazon S3 儲存貯體中寫入及列出物件

如需疑難排解身分驗證與授權錯誤的相關資訊，請參閱[對 Kafka 事件來源映射錯誤進行疑難排解](with-kafka-troubleshoot.md)。

# 設定 Lambda 的 Amazon MSK 事件來源
<a name="with-msk-configure"></a>

若要將 Amazon MSK 叢集用作 Lambda 函式的事件來源，需要建立將這兩項資源連線的[事件來源映射](invocation-eventsourcemapping.md)。本頁介紹了如何為 Amazon MSK 建立事件來源映射。

本頁假設您已正確設定 MSK 叢集及其所在的 [Amazon Virtual Private Cloud (VPC)](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html)。如需設定叢集或 VPC，請參閱[為 Lambda 設定 Amazon MSK 叢集與 Amazon VPC 網路](with-msk-cluster-network.md)。若要設定錯誤處理的重試行為，請參閱 [設定 Kafka 事件來源的錯誤處理控制項](kafka-retry-configurations.md)。

**Topics**
+ [

## 使用 Amazon MSK 叢集作為事件來源
](#msk-esm-overview)
+ [

# 在 Lambda 中設定 Amazon MSK 叢集身分驗證方法
](msk-cluster-auth.md)
+ [

# 為 Amazon MSK 事件來源建立 Lambda 事件來源映射
](msk-esm-create.md)
+ [

# 在 Lambda 中建立跨帳戶事件來源映射
](msk-cross-account.md)
+ [

# Lambda 中的所有 Amazon MSK 事件來源組態參數
](msk-esm-parameters.md)

## 使用 Amazon MSK 叢集作為事件來源
<a name="msk-esm-overview"></a>

當您將 Apache Kafka 或 Amazon MSK 叢集新增為 Lambda 函數的觸發條件時，該叢集會用作[事件來源](invocation-eventsourcemapping.md)。

Lambda 會根據您指定的[起始位置](kafka-starting-positions.md)，從 Kafka 主題 (您在 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 請求中指定為 `Topics`) 讀取事件資料。處理成功後，您的 Kafka 主題將遞交給 Kafka 叢集。

Lambda 會依序讀取每個 Kafka 主題分割區的訊息。單一 Lambda 承載可以包含來自多個分割區的訊息。有更多記錄可用時，Lambda 會根據您在 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 請求中指定的 BatchSize 值，繼續以批次方式來處理記錄，直到函式追上主題的進度為止。

Lambda 處理每個批次後，會遞交該批次中訊息的偏移量。如果函數針對批次中的任何訊息傳回錯誤，Lambda 會重試整個批次的訊息，直至處理成功或訊息過期。您可以將所有重試嘗試失敗時的記錄傳送至失敗時的目的地，以便稍後處理。

**注意**  
雖然 Lambda 函數的逾時上限通常為 15 分鐘，但 Amazon MSK、自我管理的 Apache Kafka、Amazon DocumentDB 以及 Amazon MQ for ActiveMQ 和 Amazon MQ for RabbitMQ 的事件來源映射只支援 14 分鐘逾時限制上限的函數。

# 在 Lambda 中設定 Amazon MSK 叢集身分驗證方法
<a name="msk-cluster-auth"></a>

Lambda 需要許可才能存取 Amazon MSK 叢集、擷取記錄和執行其他任務。Amazon MSK 支援多種方法向 MSK 叢集進行身分驗證。

**Topics**
+ [

## 未驗證的存取
](#msk-unauthenticated)
+ [

## SASL/SCRAM 身分驗證
](#msk-sasl-scram)
+ [

## 交互 TLS 驗證
](#msk-mtls)
+ [

## IAM 身分驗證
](#msk-iam-auth)
+ [

## Lambda 選擇引導代理程式的方法
](#msk-bootstrap-brokers)

## 未驗證的存取
<a name="msk-unauthenticated"></a>

如果沒有用戶端透過網際網路存取叢集，您可以使用未驗證存取。

## SASL/SCRAM 身分驗證
<a name="msk-sasl-scram"></a>

Lambda 支援 [Simple Authentication and Security Layer/Salted Challenge Response Authentication Mechanism (SASL/SCRAM)](https://docs.aws.amazon.com/msk/latest/developerguide/msk-password-tutorial.html) 身分驗證，並使用 SHA-512 雜湊函式和 Transport Layer Security (TLS) 加密。若要讓 Lambda 連線至叢集，請將身分驗證憑證 (使用者名稱與密碼) 儲存在 Secrets Manager 秘密中，並在設定事件來源映射時參考此秘密。

如需有關使用 Secrets Manager 的詳細資訊，請參閱 *Amazon Managed Streaming for Apache Kafka Developer Guide* 中的 [Sign-in credentials authentication with Secrets Manager](https://docs.aws.amazon.com/msk/latest/developerguide/msk-password.html)。

**注意**  
Amazon MSK 不支援 SASL/PLAIN 身分驗證。

## 交互 TLS 驗證
<a name="msk-mtls"></a>

交互 TLS (mTLS) 可提供用戶端與伺服器之間的雙向身分驗證。用戶端會將憑證傳送至伺服器，供伺服器驗證用戶端。伺服器也會將憑證傳送至用戶端，供用戶端驗證伺服器。

針對 Amazon MSK 與 Lambda 的整合，MSK 叢集充當伺服器，而 Lambda 充當用戶端。
+ 若要讓 Lambda 驗證 MSK 叢集，可以將用戶端憑證設定為 Secrets Manager 中的秘密，並在事件來源映射組態中參考此憑證。客户憑證必須由伺服器信任存放區中的憑證授權機構 (CA) 簽署。
+ MSK 叢集也會將伺服器憑證傳送至 Lambda。伺服器憑證必須由 AWS 信任存放區中的憑證授權機構 (CA) 簽署。

Amazon MSK 不支援自行簽署的伺服器憑證，因為 Amazon MSK 中的所有代理程式都使用由 [Amazon Trust Services CA](https://www.amazontrust.com/repository/) (Lambda 預設信任此機構) 簽署的[公有憑證](https://docs.aws.amazon.com/msk/latest/developerguide/msk-encryption.html)。

### 設定 mTLS 機密
<a name="mtls-auth-secret"></a>

CLIENT\$1CERTIFICATE\$1TLS\$1AUTH 機密必須有憑證欄位和私有金鑰欄位。若為加密的私有金鑰，機密需要私有金鑰密碼。憑證與私有金鑰均必須為 PEM 格式。

**注意**  
Lambda 支援 [PBES1](https://datatracker.ietf.org/doc/html/rfc2898/#section-6.1) (但不支援 PBES2) 私有金鑰加密演算法。

憑證欄位必須包含憑證清單，以用戶端憑證開頭，隨後則是任何中繼憑證，並以根憑證結尾。每個憑證均必須以新的一行開始，結構如下：

```
-----BEGIN CERTIFICATE-----  
        <certificate contents>
-----END CERTIFICATE-----
```

Secrets Manager 支援高達 65,536 個位元組的機密，此空間足以容納長憑證鏈。

私有金鑰必須為 [PKCS \$18](https://datatracker.ietf.org/doc/html/rfc5208) 格式，結構如下：

```
-----BEGIN PRIVATE KEY-----  
         <private key contents>
-----END PRIVATE KEY-----
```

對於已加密的私有金鑰，請使用下列結構：

```
-----BEGIN ENCRYPTED PRIVATE KEY-----  
          <private key contents>
-----END ENCRYPTED PRIVATE KEY-----
```

下列範例顯示的是使用了已加密私有金鑰之 mTLS 身分驗證的機密內容。若為加密的私有金鑰，您可以在機密中包含私有金鑰密碼。

```
{
 "privateKeyPassword": "testpassword",
 "certificate": "-----BEGIN CERTIFICATE-----
MIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw
...
j0Lh4/+1HfgyE2KlmII36dg4IMzNjAFEBZiCRoPimO40s1cRqtFHXoal0QQbIlxk
cmUuiAii9R0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb
...
rQoiowbbk5wXCheYSANQIfTZ6weQTgiCHCCbuuMKNVS95FkXm0vqVD/YpXKwA/no
c8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==
-----END CERTIFICATE-----",
 "privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFKzBVBgkqhkiG9w0BBQ0wSDAnBgkqhkiG9w0BBQwwGgQUiAFcK5hT/X7Kjmgp
...
QrSekqF+kWzmB6nAfSzgO9IaoAaytLvNgGTckWeUkWn/V0Ck+LdGUXzAC4RxZnoQ
zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==
-----END ENCRYPTED PRIVATE KEY-----"
}
```

如需有關適用於 Amazon MSK 的 mTLS 詳細資訊，以及如何產生用戶端憑證的說明，請參閱 *Amazon Managed Streaming for Apache Kafka Developer Guide* 中的 [Mutual TLS client authentication for Amazon MSK](https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html)。

## IAM 身分驗證
<a name="msk-iam-auth"></a>

您可以使用 AWS Identity and Access Management (IAM) 驗證連線至 MSK 叢集之用戶端的身分。透過 IAM 身分驗證，Lambda 憑藉函式[執行角色](lambda-intro-execution-role.md)中的許可連線至叢集、擷取記錄，以及執行其他必要動作。如需包含必要許可的政策範例，請參閱 *Amazon Managed Streaming for Apache Kafka Developer Guide* 中的 [ Create authorization policies for the IAM role](https://docs.aws.amazon.com/msk/latest/developerguide/create-iam-access-control-policies.html)。

若 MSK 叢集上的 IAM 身分驗證為作用中，且您未提供秘密，則 Lambda 會自動預設使用 IAM 身分驗證。

如需有關 Amazon MSK 中 IAM 身分驗證的詳細資訊，請參閱 [IAM access control](https://docs.aws.amazon.com/msk/latest/developerguide/iam-access-control.html)。

## Lambda 選擇引導代理程式的方法
<a name="msk-bootstrap-brokers"></a>

Lambda 會依據叢集上可用的身分驗證方法，以及您是否提供了身分驗證密碼，以此選擇[引導代理程式](https://docs.aws.amazon.com/msk/latest/developerguide/msk-get-bootstrap-brokers.html)。若您提供了 MTL 或 SASL/SCRAM 的密碼，則 Lambda 會自動選擇該身分驗證方法。若您未提供密碼，Lambda 會選取叢集上作用中的安全強度最高的身分驗證方法。以下是 Lambda 選擇代理程式的優先順序，身分驗證安全強度依次遞減：
+ mTLS (已提供 mTLS 密碼）
+ SASL/SCRAM (已提供 SASL /SCROM 密碼)
+ SASL IAM (未提供任何密碼，且 IAM 身分驗證在作用中）
+ 未驗證的 TLS (未提供任何密碼，且 IAM 身分驗證未在作用中)
+ 純文字 (未提供任何密碼，且 IAM 身分驗證和未經身分驗證的 TLS 皆未在作用中)

**注意**  
若 Lambda 無法連線至最安全的代理程式類型，Lambda 便不會嘗試連線至其他 (安全強度較弱) 的代理程式類型。若您要讓 Lambda 選擇安全強度較弱較弱的代理程式類型，請停用叢集上所有安全強度較弱更高的身分驗證方法。

# 為 Amazon MSK 事件來源建立 Lambda 事件來源映射
<a name="msk-esm-create"></a>

若要建立事件來源映射，可以使用 Lambda 主控台、[AWS Command Line Interface (CLI)](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 或 [AWS SDK](https://aws.amazon.com/getting-started/tools-sdks/)。

**注意**  
當您建立事件來源映射時，Lambda 會在包含 MSK 叢集的私有子網路內建立 [Hyperplane ENI](configuration-vpc.md#configuration-vpc-enis)，使 Lambda 能建立安全連線。此 Hyperplane ENI 會使用 MSK 叢集的子網路和安全群組組態，而不是 Lambda 函式。

下列主控台步驟會將 Amazon MSK 叢集新增為 Lambda 函式的觸發程序。在此之下，此操作會建立事件來源映射資源。

**將 Amazon MSK 觸發條件新增至 Lambda 函數 （主控台）**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇要新增 Amazon MSK 觸發程序的 Lambda 函式名稱。

1. 在**函數概觀**下，選擇**新增觸發條件**。

1. 在**觸發程序組態**欄位中，選擇 **MSK**。

1. 若要指定 Kafka 叢集詳細資訊，請執行下列動作：

   1. 對於 **MSK cluster (MSK 叢集)**，請選取您的叢集。

   1. 在**主題名稱**欄位中，輸入要從中取用訊息的 Kafka 主題名稱。

   1. (選用) 在**取用者群組 ID** 欄位中，輸入要加入的 Kafka 取用者群組 ID (如適用)。如需詳細資訊，請參閱[Lambda 中可自訂的取用者群組 ID](kafka-consumer-group-id.md)。

1. 在**叢集身分驗證**欄位中，進行必要的組態設定。如需有關叢集身分驗證的詳細資訊，請參閱[在 Lambda 中設定 Amazon MSK 叢集身分驗證方法](msk-cluster-auth.md)。
   + 如果希望 Lambda 在建立連線時對 MSK 叢集執行身分驗證，請開啟**使用身分驗證**。建議進行身分驗證。
   + 如果使用身分驗證，在**身分驗證方法**欄位中，選擇要使用的身分驗證方法。
   + 如果使用身分驗證，在 **Secrets Manager 金鑰**欄位中，選擇包含存取叢集所需身分驗證憑證的 Secrets Manager 金鑰。

1. 在**事件輪詢器組態**欄位中，進行必要的組態設定。
   + 選擇**啟用觸發程序**，在建立完成後立即啟用觸發程序。
   + 選擇是否要為事件來源映射**設定佈建模式**。如需詳細資訊，請參閱[Lambda 中的 Apache Kafka 事件輪詢器擴展模式](kafka-scaling-modes.md)。
     + 如果您設定佈建模式，請輸入**最小值事件輪詢器**的值、**最大值事件輪詢器**的值，以及 PollerGroupName 的選用值，以指定相同事件來源 VPC 內多個 ESMs 的分組。
   + 在**開始位置**欄位中，選擇希望 Lambda 開始從串流讀取的方式。如需詳細資訊，請參閱[Lambda 中的 Apache Kafka 輪詢與串流開始位置](kafka-starting-positions.md)。

1. 在**批次處理**欄位中，進行必要的組態設定。如需有關批次處理的詳細資訊，請參閱[批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)。

   1. 對於 **批次大小**，輸入單一批次中要擷取的訊息數量上限。

   1. 在**批次時段**欄位中，輸入 Lambda 調用函式之前收集記錄所耗費的秒數上限。

1. 在**篩選**欄位中，進行必要的組態設定。如需有關篩選的詳細資訊，請參閱 [從 Amazon MSK 和自我管理的 Apache Kafka 事件來源篩選事件](kafka-filtering.md)。
   + 在**篩選條件**欄位中，新增篩選條件定義，決定是否處理事件。

1. 在**失敗處理**欄位中，進行必要的組態設定。如需有關失敗處理的詳細資訊，請參閱[擷取 Amazon MSK 和自我管理的 Apache Kafka 事件來源的捨棄批次](kafka-on-failure.md)。
   + 在**失敗時目的地**欄位中，指定失敗時目的地的 ARN。

1. 在**標籤**欄位中，輸入要與此事件來源映射建立關聯的標籤。

1. 若要建立觸發條件，請選擇 **新增** 。

您也可以使用 CLI AWS 搭配 [ create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 命令來建立事件來源映射。下列範例建立了事件來源映射，可將 Lambda 函式 `my-msk-function` 映射至 `AWSKafkaTopic` 主題 (從 `LATEST` 訊息開始)。此命令還使用了 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 物件，可指示 Lambda 在連線至叢集時使用 [SASL/SCRAM](msk-cluster-auth.md#msk-sasl-scram) 身分驗證。

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
  --source-access-configurations '[{"Type": "SASL_SCRAM_512_AUTH","URI": "arn:aws:secretsmanager:us-east-1:111122223333:secret:my-secret"}]'
```

如果叢集使用 [mTLS 身分驗證](msk-cluster-auth.md#msk-mtls)，則需包含指定 `CLIENT_CERTIFICATE_TLS_AUTH` 和 Secrets Manager 金鑰 ARN 的 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 物件。如下列命令所示：

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
  --source-access-configurations '[{"Type": "CLIENT_CERTIFICATE_TLS_AUTH","URI": "arn:aws:secretsmanager:us-east-1:111122223333:secret:my-secret"}]'
```

如果叢集使用 [IAM 身分驗證](msk-cluster-auth.md#msk-iam-auth)，則不需要 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 物件。如下列命令所示：

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
```

# 在 Lambda 中建立跨帳戶事件來源映射
<a name="msk-cross-account"></a>

您可以使用[多 VPC 私有連線](https://docs.aws.amazon.com/msk/latest/developerguide/aws-access-mult-vpc.html)，將 Lambda 函數連接到不同 AWS 帳戶中的佈建 MSK 叢集。多 VPC 連線使用 AWS PrivateLink，這會保留 AWS 網路中的所有流量。

**注意**  
您無法為無伺服器 MSK 叢集建立跨帳戶事件來源映射。

若要建立跨帳戶事件來源映射，您必須先[為 MSK 叢集設定多 VPC 連線](https://docs.aws.amazon.com/msk/latest/developerguide/aws-access-mult-vpc.html#mvpc-cluster-owner-action-turn-on)。建立事件來源映射時，請使用受管理的 VPC 連線 ARN 而非叢集 ARN，如下列範例所示。根據 MSK 叢集使用的驗證類型，[CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 操作也會有所不同。

**Example — 為使用 IAM 身分驗證的叢集建立跨帳戶的事件來源映射**  
當叢集使用 [IAM 角色型身分驗證](msk-cluster-auth.md#msk-iam-auth)時，您不需要 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 物件。範例：  

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:vpc-connection/444455556666/my-cluster-name/51jn98b4-0a61-46cc-b0a6-61g9a3d797d5-7 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
```

**Example — 為使用 SASL/SCRAM 身分驗證的叢集建立跨帳戶的事件來源映射**  
如果叢集使用 [SASL/SCRAM 身分驗證](msk-cluster-auth.md#msk-sasl-scram)，則您必須包含指定 `SASL_SCRAM_512_AUTH` 和 Secrets Manager 機密 ARN 的 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html)。  
透過 SASL/SCRAM 身分驗證，有兩種方式可將機密用於跨帳戶 Amazon MSK 事件來源映射：  
+ 在 Lambda 函數帳戶中建立機密，並將其與叢集機密同步。[建立一個輪換](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html)以使兩個機密保持同步。此選項允許您從函數帳戶控制機密。
+ 使用機密必須與 Amazon MSK 叢集相關聯。此機密必須允許 Lambda 函數帳戶的跨帳户存取權。如需詳細資訊，請參閱[不同帳戶中使用者 AWS Secrets Manager 機密的許可](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_examples_cross.html)。

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:vpc-connection/444455556666/my-cluster-name/51jn98b4-0a61-46cc-b0a6-61g9a3d797d5-7 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function \
  --source-access-configurations '[{"Type": "SASL_SCRAM_512_AUTH","URI": "arn:aws:secretsmanager:us-east-1:444455556666:secret:my-secret"}]'
```

**Example — 為使用 mTLS 身分驗證的叢集建立跨帳戶的事件來源映射**  
如果叢集使用 [mTLS 身分驗證](msk-cluster-auth.md#msk-mtls)，則您必須包含指定 `CLIENT_CERTIFICATE_TLS_AUTH` 和 Secrets Manager 機密 ARN 的 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html)。機密可以儲存在叢集帳戶或 Lambda 函數帳戶中。  

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:vpc-connection/444455556666/my-cluster-name/51jn98b4-0a61-46cc-b0a6-61g9a3d797d5-7 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function \
  --source-access-configurations '[{"Type": "CLIENT_CERTIFICATE_TLS_AUTH","URI": "arn:aws:secretsmanager:us-east-1:444455556666:secret:my-secret"}]'
```

# Lambda 中的所有 Amazon MSK 事件來源組態參數
<a name="msk-esm-parameters"></a>

所有 Lambda 事件來源類型都會共用相同的 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 和 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 操作。但是，僅有部分參數適用於 Amazon MSK，如下表所示。


| 參數 | 必要 | 預設 | 備註 | 
| --- | --- | --- | --- | 
|  AmazonManagedKafkaEventSourceConfig  |  N  |  包含預設為一個唯一值的 ConsumerGroupId 欄位。  |  只能在建立時進行設定  | 
|  BatchSize  |  否  |  100  |  上限：10,000  | 
|  DestinationConfig  |  N  |  N/A  |  [擷取 Amazon MSK 和自我管理的 Apache Kafka 事件來源的捨棄批次](kafka-on-failure.md)  | 
|  已啟用  |  N  |  True  |    | 
|  BisectBatchOnFunctionError  |  N  |  False  |  [設定 Kafka 事件來源的錯誤處理控制項](kafka-retry-configurations.md)  | 
|  FunctionResponseTypes  |  N  |  N/A  |  [設定 Kafka 事件來源的錯誤處理控制項](kafka-retry-configurations.md)  | 
|  MaximumRecordAgeInSeconds  |  N  |  -1 （無限）  |  [設定 Kafka 事件來源的錯誤處理控制項](kafka-retry-configurations.md)  | 
|  MaximumRetryAttempts  |  N  |  -1 （無限）  |  [設定 Kafka 事件來源的錯誤處理控制項](kafka-retry-configurations.md)  | 
|  EventSourceArn  |  Y  | N/A |  只能在建立時進行設定  | 
|  FilterCriteria  |  N  |  N/A  |  [控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)  | 
|  FunctionName  |  是  |  N/A  |    | 
|  KMSKeyArn  |  N  |  N/A  |  [篩選條件加密](invocation-eventfiltering.md#filter-criteria-encryption)  | 
|  MaximumBatchingWindowInSeconds  |  N  |  500 毫秒  |  [批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)  | 
|  ProvisionedPollersConfig  |  N  |  `MinimumPollers`：若未指定，預設值為 1。 `MaximumPollers`：若未指定，預設值為 200。 `PollerGroupName`：不適用  |  [佈建模式](kafka-scaling-modes.md#kafka-provisioned-mode)  | 
|  SourceAccessConfigurations  |  N  |  沒有憑證  |  您事件來源的 SASL/SCRAM 或 CLIENT\$1CERTIFICATE\$1TLS\$1AUTH (MutualTLS) 身分驗證憑證。  | 
|  StartingPosition  |  Y  | N/A |  AT\$1TIMESTAMP、TRIM\$1HORIZON 或 LATEST 只能在建立時進行設定  | 
|  StartingPositionTimestamp  |  N  |  N/A  |  StartingPosition 設定為 AT\$1TIMESTAMP 時需要  | 
|  Tags (標籤)  |  N  |  N/A  |  [在事件來源映射上使用標籤](tags-esm.md)  | 
|  主題  |  Y  | N/A |  Kafka 主題名稱 只能在建立時進行設定  | 

**注意**  
當您指定 時`PollerGroupName`，相同 Amazon VPC 中的多個 ESMs 可以共用事件輪詢單元 (EPU) 容量。您可以使用此選項來最佳化 ESMs 的佈建模式成本。ESM 分組的需求：  
ESMs 必須位於相同的 Amazon VPC 內
每個輪詢器群組最多 100 ESMs 
群組中所有 ESMs 的彙總輪詢器上限不能超過 2000
您可以更新 `PollerGroupName`，將 ESM 移至不同的群組，或將 `PollerGroupName`設定為空字串 ("")，從群組中移除 ESM。

# 教學課程：使用 Amazon MSK 事件來源映射來調用 Lambda 函數
<a name="services-msk-tutorial"></a>

在本教學課程中，您將執行下列操作：
+ 在與現有 Amazon MSK 叢集相同的 AWS 帳戶中建立 Lambda 函數。
+ 為 Lambda 設定聯網和身分驗證，以與 Amazon MSK 通訊。
+ 設定 Lambda Amazon MSK 事件來源映射，當主題中出現事件時，該映射會執行您的 Lambda 函數。

完成這些步驟後，當事件傳送至 Amazon MSK 時，您將能夠設定 Lambda 函數，以使用您自己的自訂 Lambda 程式碼自動處理這些事件。

 **您可以使用此功能做些什麼？** 

**範例解決方案：使用 MSK 事件來源映射為您的客戶提供即時分數。**

請考慮以下案例：您的公司託管了一個 Web 應用程式，您的客戶可以在其中檢視即時事件的相關資訊，例如運動遊戲。來自遊戲的資訊更新會透過 Amazon MSK 上的一個 Kafka 主題提供給您的團隊。您想要設計一個使用 MSK 主題更新的解決方案，以便在您所開發的應用程式內為客戶提供即時事件的更新檢視。您已決定採用下列設計方法：您的用戶端應用程式將與 AWS中託管的無伺服器後端通訊。用戶端將使用 Amazon API Gateway WebSocket API，透過 WebSocket 工作階段連線。

在此解決方案中，您需要一個元件來讀取 MSK 事件、執行一些自訂邏輯來準備應用程式層的事件，然後將該資訊轉送至 API Gateway API。您可以使用 實作此元件 AWS Lambda，方法是在 Lambda 函數中提供自訂邏輯，然後使用 AWS Lambda Amazon MSK 事件來源映射呼叫它。

如需使用 Amazon API Gateway WebSocket API 實作解決方案的詳細資訊，請參閱 API Gateway 文件中的 [WebSocket API tutorials](https://docs.aws.amazon.com/apigateway/latest/developerguide/websocket-api-chat-app.html)。

## 先決條件
<a name="w2aad101c23c15c35c19"></a>

具有下列預先設定資源 AWS 的帳戶：

**為了滿足這些先決條件，我們建議您遵循 Amazon MSK 文件中的 [Getting started using Amazon MSK](https://docs.aws.amazon.com//msk/latest/developerguide/getting-started.html)。**
+ Amazon MSK 叢集。請參閱*開始使用 Amazon MSK*中的[建立 Amazon MSK 叢集](https://docs.aws.amazon.com//msk/latest/developerguide/create-cluster.html)。
+ 下列組態：
  + 確定叢集安全設定中**已啟用** **IAM 角色型身分驗證**。這會透過限制您的 Lambda 函數僅存取所需的 Amazon MSK 資源來提高您的安全性。在新的 Amazon MSK 叢集上預設會啟用此功能。
  + 確保您的叢集聯網設定中的**公有存取**已關閉。限制 Amazon MSK 叢集對網際網路的存取，可限制有多少中介機構處理您的資料，藉此提高您的安全性。在新的 Amazon MSK 叢集上預設會啟用此功能。
+ Amazon MSK 叢集中用於此解決方案的 Kafka 主題。請參閱*開始使用 Amazon MSK* 中的[建立主題](https://docs.aws.amazon.com//msk/latest/developerguide/create-topic.html)。
+ Kafka 管理員主機，設定為從 Kafka 叢集擷取資訊，並將 Kafka 事件傳送至您的主題進行測試，例如已安裝 Kafka 管理員 CLI 和 Amazon MSK IAM 程式庫的 Amazon EC2 執行個體。請參閱*開始使用 Amazon MSK* 中的[建立用戶端機器](https://docs.aws.amazon.com//msk/latest/developerguide/create-client-machine.html)。

設定這些資源後，請從 AWS 您的帳戶收集下列資訊，以確認您已準備好繼續。
+ Amazon MSK 叢集的名稱。您可以在 Amazon MSK 主控台中找到此資訊。
+ 叢集 UUID 是 Amazon MSK 叢集 ARN 的一部分，可以在 Amazon MSK 主控台中找到。請執行 Amazon MSK 文件中 [Listing clusters](https://docs.aws.amazon.com/msk/latest/developerguide/msk-list-clusters.html) 中的程序來尋找此資訊。
+ 與您的 Amazon MSK 叢集相關聯的安全群組。您可以在 Amazon MSK 主控台中找到此資訊。在下列步驟中，將這些安全群組稱為 *clusterSecurityGroups*。
+ 包含 Amazon MSK 叢集的 Amazon VPC 的 ID。您可以在 Amazon MSK 主控台中識別與 Amazon MSK 叢集相關聯的子網路，然後在 Amazon VPC 主控台中識別與子網路相關聯的 Amazon VPC，籍此找到此資訊。
+ 解決方案中使用的 Kafka 主題的名稱。您可以從 Kafka 管理員主機使用 Kafka `topics` CLI 呼叫 Amazon MSK 叢集，籍此找到此資訊。如需關於主題 CLI 的詳細資訊，請參閱 Kafka 文件中的 [Adding and removing topics](https://kafka.apache.org/documentation/#basic_ops_add_topic)。
+ Kafka 主題的取用者群組名稱，適合供 Lambda 函數使用。此群組可由 Lambda 自動建立，因此不需要使用 Kafka CLI 建立。如果您需要管理取用者群組，以進一步了解取用者群組 CLI 的詳細資訊，則請參閱 Kafka 文件中的 [Managing Consumer Groups](https://kafka.apache.org/documentation/#basic_ops_consumer_group)。

您 AWS 帳戶中的下列許可：
+ 建立和管理 Lambda 函數的許可。
+ 建立 IAM 政策並與您的 Lambda 函數建立關聯的許可。
+ 在託管 Amazon MSK 叢集的 Amazon VPC 中建立 Amazon VPC 端點和變更聯網組態的許可。

### 安裝 AWS Command Line Interface
<a name="install_aws_cli"></a>

如果您尚未安裝 AWS Command Line Interface，請依照[安裝或更新最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)中的步驟進行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中，使用您偏好的 Shell 和套件管理工具。

**注意**  
在 Windows 中，作業系統的內建終端不支援您常與 Lambda 搭配使用的某些 Bash CLI 命令 (例如 `zip`)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本，請[安裝適用於 Linux 的 Windows 子系統](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。

## 設定供 Lambda 與 Amazon MSK 通訊的網路連線
<a name="w2aad101c23c15c35c21"></a>

 使用 AWS PrivateLink 連接 Lambda 和 Amazon MSK。您可以在 Amazon VPC 主控台中建立介面 Amazon VPC 端點來執行此操作。如需關於聯網組態的詳細資訊，請參閱[為 Lambda 設定 Amazon MSK 叢集與 Amazon VPC 網路](with-msk-cluster-network.md)。

當 Amazon MSK 事件來源映射代表 Lambda 函數執行時，它會擔任 Lambda 函數的執行角色。此 IAM 角色會授權映射存取 IAM 保護的資源，例如您的 Amazon MSK 叢集。雖然元件共用執行角色，但 Amazon MSK 映射和您的 Lambda 函數對各自的任務有不同的連線需求，如下圖所示。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/msk_tut_network.png)


事件來源映射屬於 Amazon MSK 叢集安全群組。在此聯網步驟中，從您的 Amazon MSK 叢集 VPC 建立 Amazon VPC 端點，將事件來源映射連線到 Lambda 和 STS 服務。保護這些端點，接受來自 Amazon MSK 叢集安全群組的流量。然後，調整 Amazon MSK 叢集安全群組，允許事件來源映射與 Amazon MSK 叢集通訊。

 您可以使用 AWS 管理主控台來設定下列步驟。

**若要設定介面 Amazon VPC 端點連線 Lambda 和 Amazon MSK**

1. 為您的介面 Amazon VPC 端點 *endpointSecurityGroup* 建立安全群組，允許 443 上來自 *clusterSecurityGroups* 的傳入 TCP 流量。請遵循 Amazon EC2 文件中的 [Create a security group](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/working-with-security-groups.html#creating-security-group) 中的程序來建立安全群組。然後，遵循 Amazon EC2 文件中的 [Add rules to a security group](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/working-with-security-groups.html#adding-security-group-rule) 中的程序，以新增適當的規則。

   **使用下列資訊建立一個安全群組：**

   在新增傳入規則時，為 *clusterSecurityGroups* 中的每個安全群組建立規則。對於每條規則：
   + 針對**類型**，選取 **HTTPS**。
   + 針對**來源**，選取其中一個 *clusterSecurityGroups*。

1.  建立一個端點，將 Lambda 服務連線至包含 Amazon MSK 叢集的 Amazon VPC。遵循 [Create an interface endpoint](https://docs.aws.amazon.com//vpc/latest/privatelink/create-interface-endpoint.html) 中的程序。

   **使用下列資訊建立一個介面端點：**
   + 針對**服務名稱**，選取 `com.amazonaws.regionName.lambda`，其中 *regionName* 會託管您的 Lambda 函數。
   + 針對 **VPC**，選取包含 Amazon MSK 叢集的 Amazon VPC。
   + 針對**安全群組**，選取先前建立的 *endpointSecurityGroup*。
   + 針對**子網路**，選取託管您的 Amazon MSK 叢集的子網路。
   + 針對**政策**，提供下列政策文件，這會保護端點以供 Lambda 服務主體用於 `lambda:InvokeFunction` 動作。

     ```
     {
         "Statement": [
             {
                 "Action": "lambda:InvokeFunction",
                 "Effect": "Allow",
                 "Principal": {
                     "Service": [
                         "lambda.amazonaws.com"
                     ]
                 },
                 "Resource": "*"
             }
         ]
     }
     ```
   + 確保**啟用 DNS 名稱**保持設定狀態。

1.  建立端點，將 AWS STS 服務連線至包含 Amazon MSK 叢集的 Amazon VPC。遵循 [Create an interface endpoint](https://docs.aws.amazon.com//vpc/latest/privatelink/create-interface-endpoint.html) 中的程序。

   **使用下列資訊建立一個介面端點：**
   + 針對**服務名稱**，選取 AWS STS。
   + 針對 **VPC**，選取包含 Amazon MSK 叢集的 Amazon VPC。
   + 針對**安全群組**，選取 *endpointSecurityGroup*。
   + 針對**子網路**，選取託管您的 Amazon MSK 叢集的子網路。
   + 針對**政策**，提供下列政策文件，這會保護端點以供 Lambda 服務主體用於 `sts:AssumeRole` 動作。

     ```
     {
         "Statement": [
             {
                 "Action": "sts:AssumeRole",
                 "Effect": "Allow",
                 "Principal": {
                     "Service": [
                         "lambda.amazonaws.com"
                     ]
                 },
                 "Resource": "*"
             }
         ]
     }
     ```
   + 確保**啟用 DNS 名稱**保持設定狀態。

1. 對於與您的 Amazon MSK 叢集相關聯的每個安全群組，亦即，在 *clusterSecurityGroups* 中，允許以下項目：
   + 允許 9098 上所有 *clusterSecurityGroups* 的傳入和傳出 TCP 流量，包括其本身以內的 TCP 流量。
   + 允許 443 上的所有傳出 TCP 流量。

   根據預設，安全群組規則允許其中一些流量，因此如果您的叢集連接到單一安全群組，且該群組具有預設規則，則不需要額外的規則。若要調整安全群組規則，請遵循 Amazon EC2 文件中的 [Add rules to a security group](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/working-with-security-groups.html#adding-security-group-rule) 中的程序。

   **使用下列資訊將規則新增至您的安全群組：**
   + 針對連接埠 9098 的每個傳入或傳出規則，提供
     + 針對**類型**，選取**自訂 TCP**。
     + 對於**連接埠範圍**，提供 9098。
     + 針對**來源**，提供其中一個 *clusterSecurityGroups*。
   + 對於連接埠 443 的每條傳入規則，針對**類型**，選取 **HTTPS**。

## 為 Lambda 建立 IAM 角色，以從 Amazon MSK 主題讀取
<a name="w2aad101c23c15c35c23"></a>

識別 Lambda 從 Amazon MSK 主題讀取的身分驗證要求，然後在政策中定義這些要求。建立角色 *lambdaAuthRole*，授權 Lambda 使用這些許可。使用 `kafka-cluster` IAM 動作授權 Amazon MSK 叢集上的動作。然後，授權 Lambda 執行探索和連線至 Amazon MSK 叢集所需的 Amazon MSK `kafka` 和 Amazon EC2 動作，以及 CloudWatch 動作 (以便 Lambda 可以記錄其已完成的動作)。

**若要描述 Lambda 從 Amazon MSK 讀取的身分驗證要求**

1. 撰寫 IAM 政策文件 (JSON 文件) *clusterAuthPolicy*，允許 Lambda 使用您的 Kafka 取用者群組，從 Amazon MSK 叢集中的 Kafka 主題讀取。Lambda 要求在讀取時設定 Kafka 取用者群組。

   修改以下範本以符合您的先決條件：

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "kafka-cluster:Connect",
                   "kafka-cluster:DescribeGroup",
                   "kafka-cluster:AlterGroup",
                   "kafka-cluster:DescribeTopic",
                   "kafka-cluster:ReadData",
                   "kafka-cluster:DescribeClusterDynamicConfiguration"
               ],
               "Resource": [
                   "arn:aws:kafka:us-east-1:111122223333:cluster/mskClusterName/cluster-uuid",
                   "arn:aws:kafka:us-east-1:111122223333:topic/mskClusterName/cluster-uuid/mskTopicName",
                   "arn:aws:kafka:us-east-1:111122223333:group/mskClusterName/cluster-uuid/mskGroupName"
               ]
           }
       ]
   }
   ```

------

   如需詳細資訊，請參閱 [設定 Amazon MSK 事件來源映射的 Lambda 許可](with-msk-permissions.md)。在撰寫政策時：
   + 使用 Amazon MSK 叢集 AWS 帳戶 的 和 取代 *us-east-1* AWS 區域 和 *111122223333*。
   + 對於 *mskClusterName*，請提供 Amazon MSK 叢集的名稱。
   + 對於 *cluster-uuid*，請提供 Amazon MSK 叢集 ARN 中的 UUID。
   + 對於 *mskTopicName*，請提供 Kafka 主題的名稱。
   + 針對 *mskGroupName*，請提供 Kafka 取用者群組的名稱。

1. 識別 Lambda 探索和連線 Amazon MSK 叢集以及記錄這些事件所需的 Amazon MSK、Amazon EC2 和 CloudWatch 許可。

   `AWSLambdaMSKExecutionRole` 受管政策允許定義必要的許可。在下列步驟中使用該政策。

   在生產環境中，評估 `AWSLambdaMSKExecutionRole` 以根據最低權限原則限制執行角色政策，然後為您的角色撰寫取代此受管政策的政策。

如需有關 IAM 政策語言的詳細資訊，請參閱 [IAM 文件](https://docs.aws.amazon.com//iam/)。

現在您已撰寫政策文件，請建立 IAM 政策，以便將其連接至您的角色。您可以使用主控台執行下列程序，以完成此操作。

**若要從政策文件建立 IAM 政策**

1. 登入 AWS 管理主控台 ，並在 https：//[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 開啟 IAM 主控台。

1. 在左側的導覽窗格中，選擇 **Policies (政策)**。

1. 選擇**建立政策**。

1. 在**政策編輯器**中，選擇 **JSON** 選項。

1. 貼上 *clusterAuthPolicy*。

1. 將許可新增至政策後，請選擇**下一步**。

1. 在**檢視與建立**頁面上，為您正在建立的政策輸入**政策名稱**與**描述** (選用)。檢視**此政策中定義的許可**，來查看您的政策所授予的許可。

1. 選擇 **Create policy** (建立政策) 儲存您的新政策。

如需詳細資訊，請參閱 IAM 文件中的 [Creating IAM policies](https://docs.aws.amazon.com//IAM/latest/UserGuide/access_policies_create.html)。

現在您擁有適當的 IAM 政策，請建立一個角色並將這些政策連接至該角色。您可以使用主控台執行下列程序，以完成此操作。

**若要在 IAM 主控台中建立執行角色**

1. 在 IAM 主控台中開啟 [角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇建**立角色**。

1. 在**受信任的實體類型**下，選擇 **AWS  服務**。

1. 在 **使用案例** 下，選擇 **Lambda**。

1. 選擇**下一步**。

1. 選取以下政策：
   + *clusterAuthPolicy*
   + `AWSLambdaMSKExecutionRole`

1. 選擇**下一步**。

1. 針對**角色名稱**，輸入 *lambdaAuthRole*，然後選擇**建立角色**。

如需詳細資訊，請參閱[使用執行角色定義 Lambda 函數許可](lambda-intro-execution-role.md)。

## 建立 Lambda 函數以從您的 Amazon MSK 主題中讀取
<a name="w2aad101c23c15c35c25"></a>

建立設定為使用您的 IAM 角色的 Lambda 函數。您可以使用主控台建立 Lambda 函數。

**若要使用驗證組態建立 Lambda 函數**

1.  開啟 Lambda 主控台，然後從標頭選取**建立函數**。

1. 選取**從頭開始撰寫**。

1. 針對**函數名稱**，提供您選擇的適當名稱。

1. 針對**執行時期**，選擇**最新支援**的 `Node.js` 版本，以使用本教學課程中提供的程式碼。

1. 選擇**變更預設執行角色**。

1. 選取**使用現有角色**。

1. 針對**現有角色**，選取 *lambdaAuthRole*。

在生產環境中，您通常需要將更多政策新增至 Lambda 函數的執行角色，以有意義的方式處理您的 Amazon MSK 事件。如需將政策新增至角色的詳細資訊，請參閱 IAM 文件中的 [Add or remove identity permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#add-policies-console)。

## 建立 Lambda 函數的事件來源映射
<a name="w2aad101c23c15c35c27"></a>

您的 Amazon MSK 事件來源映射為 Lambda 服務提供了在發生適當的 Amazon MSK 事件時調用 Lambda 所需的資訊。您可以使用主控台建立 Amazon MSK 映射。建立 Lambda 觸發條件，然後會自動設定事件來源映射。

**若要建立 Lambda 觸發條件 (和事件來源映射)**

1. 導覽至 Lambda 函數的概觀頁面。

1. 在函數概觀區段中，選擇左下角的**新增觸發條件**。

1. 在**選取來源**下拉式清單中，選取 **Amazon MSK**。

1. 請勿設定**身分驗證**。

1. 針對 **MSK 叢集**，請選取您的叢集名稱。

1. 針對**批次大小**，請輸入 1。此步驟可讓此功能更易於測試，而且不是生產中的理想值。

1. 針對**主題名稱**，請提供 Kafka 主題名稱。

1. 針對**取用者群組 ID**，請提供 Kafka 取用者群組的 ID。

## 更新您的 Lambda 函數以讀取串流資料
<a name="w2aad101c23c15c35c29"></a>

 Lambda 透過事件方法參數提供關於 Kafka 事件的資訊。如需 Amazon MSK 事件的結構範例，請參閱[範例事件](with-msk.md#msk-sample-event)。了解如何解譯 Lambda 轉送的 Amazon MSK 事件之後，您可以變更 Lambda 函數程式碼，以使用它們提供的資訊。

 將下列程式碼提供給 Lambda 函數，以記錄 Lambda Amazon MSK 事件的內容供測試之用：

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 來取用 Amazon MSK 事件。  

```
using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.KafkaEvents;


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace MSKLambda;

public class Function
{
    
    
    /// <param name="input">The event for the Lambda function handler to process.</param>
    /// <param name="context">The ILambdaContext that provides methods for logging and describing the Lambda environment.</param>
    /// <returns></returns>
    public void FunctionHandler(KafkaEvent evnt, ILambdaContext context)
    {

        foreach (var record in evnt.Records)
        {
            Console.WriteLine("Key:" + record.Key); 
            foreach (var eventRecord in record.Value)
            {
                var valueBytes = eventRecord.Value.ToArray();    
                var valueText = Encoding.UTF8.GetString(valueBytes);
                
                Console.WriteLine("Message:" + valueText);
            }
        }
    }
    

}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 Go 搭配 Lambda 來取用 Amazon MSK 事件。  

```
package main

import (
	"encoding/base64"
	"fmt"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(event events.KafkaEvent) {
	for key, records := range event.Records {
		fmt.Println("Key:", key)

		for _, record := range records {
			fmt.Println("Record:", record)

			decodedValue, _ := base64.StdEncoding.DecodeString(record.Value)
			message := string(decodedValue)
			fmt.Println("Message:", message)
		}
	}
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 Java 搭配 Lambda 來取用 Amazon MSK 事件。  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KafkaEvent;
import com.amazonaws.services.lambda.runtime.events.KafkaEvent.KafkaEventRecord;

import java.util.Base64;
import java.util.Map;

public class Example implements RequestHandler<KafkaEvent, Void> {

    @Override
    public Void handleRequest(KafkaEvent event, Context context) {
        for (Map.Entry<String, java.util.List<KafkaEventRecord>> entry : event.getRecords().entrySet()) {
            String key = entry.getKey();
            System.out.println("Key: " + key);

            for (KafkaEventRecord record : entry.getValue()) {
                System.out.println("Record: " + record);

                byte[] value = Base64.getDecoder().decode(record.getValue());
                String message = new String(value);
                System.out.println("Message: " + message);
            }
        }

        return null;
    }
}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 來取用 Amazon MSK 事件。  

```
exports.handler = async (event) => {
    // Iterate through keys
    for (let key in event.records) {
      console.log('Key: ', key)
      // Iterate through records
      event.records[key].map((record) => {
        console.log('Record: ', record)
        // Decode base64
        const msg = Buffer.from(record.value, 'base64').toString()
        console.log('Message:', msg)
      }) 
    }
}
```
搭配 Lambda 使用 TypeScript 來取用 Amazon MSK 事件。  

```
import { MSKEvent, Context } from "aws-lambda";
import { Buffer } from "buffer";
import { Logger } from "@aws-lambda-powertools/logger";

const logger = new Logger({
  logLevel: "INFO",
  serviceName: "msk-handler-sample",
});

export const handler = async (
  event: MSKEvent,
  context: Context
): Promise<void> => {
  for (const [topic, topicRecords] of Object.entries(event.records)) {
    logger.info(`Processing key: ${topic}`);

    // Process each record in the partition
    for (const record of topicRecords) {
      try {
        // Decode the message value from base64
        const decodedMessage = Buffer.from(record.value, 'base64').toString();

        logger.info({
          message: decodedMessage
        });
      }
      catch (error) {
        logger.error('Error processing event', { error });
        throw error;
      }
    };
  }
}
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 來取用 Amazon MSK 事件。  

```
<?php
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Kafka\KafkaEvent;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handle(mixed $event, Context $context): void
    {
        $kafkaEvent = new KafkaEvent($event);
        $this->logger->info("Processing records");
        $records = $kafkaEvent->getRecords();

        foreach ($records as $record) {
            try {
                $key = $record->getKey();
                $this->logger->info("Key: $key");

                $values = $record->getValue();
                $this->logger->info(json_encode($values));

                foreach ($values as $value) {
                    $this->logger->info("Value: $value");
                }
                
            } catch (Exception $e) {
                $this->logger->error($e->getMessage());
            }
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 Python 搭配 Lambda 來取用 Amazon MSK 事件。  

```
import base64

def lambda_handler(event, context):
    # Iterate through keys
    for key in event['records']:
        print('Key:', key)
        # Iterate through records
        for record in event['records'][key]:
            print('Record:', record)
            # Decode base64
            msg = base64.b64decode(record['value']).decode('utf-8')
            print('Message:', msg)
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 來取用 Amazon MSK 事件。  

```
require 'base64'

def lambda_handler(event:, context:)
  # Iterate through keys
  event['records'].each do |key, records|
    puts "Key: #{key}"

    # Iterate through records
    records.each do |record|
      puts "Record: #{record}"

      # Decode base64
      msg = Base64.decode64(record['value'])
      puts "Message: #{msg}"
    end
  end
end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 取用 Amazon MSK 事件。  

```
use aws_lambda_events::event::kafka::KafkaEvent;
use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
use base64::prelude::*;
use serde_json::{Value};
use tracing::{info};

/// Pre-Requisites:
/// 1. Install Cargo Lambda - see https://www.cargo-lambda.info/guide/getting-started.html
/// 2. Add packages tracing, tracing-subscriber, serde_json, base64
///
/// This is the main body for the function.
/// Write your code inside it.
/// There are some code example in the following URLs:
/// - https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/examples
/// - https://github.com/aws-samples/serverless-rust-demo/

async fn function_handler(event: LambdaEvent<KafkaEvent>) -> Result<Value, Error> {

    let payload = event.payload.records;

    for (_name, records) in payload.iter() {

        for record in records {

         let record_text = record.value.as_ref().ok_or("Value is None")?;
         info!("Record: {}", &record_text);

         // perform Base64 decoding
         let record_bytes = BASE64_STANDARD.decode(record_text)?;
         let message = std::str::from_utf8(&record_bytes)?;
         
         info!("Message: {}", message);
        }

    }

    Ok(().into())
}

#[tokio::main]
async fn main() -> Result<(), Error> {

    // required to enable CloudWatch error logging by the runtime
    tracing::init_default_subscriber();
    info!("Setup CW subscriber!");

    run(service_fn(function_handler)).await
}
```

------

您可以使用主控台將函數程式碼提供給 Lambda。

**若要使用主控台程式碼編輯器更新函數程式碼**

1. 開啟 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)，然後選取您的函數。

1. 選取**程式碼**索引標籤。

1. 在**程式碼來源**窗格中，選取您的原始程式碼檔案，然後在整合式程式碼編輯器中加以編輯。

1. 在 **DEPLOY** 區段中，選擇**部署**以更新函數的程式碼：  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## 測試您的 Lambda 函數，確認其已連線至您的 Amazon MSK 主題
<a name="w2aad101c23c15c35c31"></a>

您現在可以透過檢查 CloudWatch 事件日誌，驗證您的 Lambda 是否正在被事件來源調用。

**若要驗證您的 Lambda 函數是否正在被調用**

1. 使用您的 Kafka 管理員主機，透過 `kafka-console-producer` CLI 產生 Kafka 事件。如需詳細資訊，請參閱 Kafka 文件中的 [Write some events into the topic](https://kafka.apache.org/documentation/#quickstart_send)。傳送足夠的事件，以填滿由批次大小定義的批次，用於上一個步驟中定義的事件來源映射，否則 Lambda 會等待調用更多資訊。

1. 如果您的函數執行，Lambda 會將發生的情況寫入 CloudWatch。在主控台中，導覽至您的 Lambda 函數詳情頁面。

1. 選取 **Configuration** (組態) 索引標籤。

1. 從側邊列，選取**監控和操作工具**。

1. 在**記錄組態**下，識別 **CloudWatch 日誌群組**。日誌群組應以 `/aws/lambda` 開頭。選擇日誌群組連結。

1. 在 CloudWatch 主控台中，檢查**日誌事件**，了解 Lambda 已傳送至日誌串流的日誌事件。識別是否有日誌事件包含來自 Kafka 事件的訊息，如下圖所示。如果有，您已成功使用 Lambda 事件來源映射將 Lambda 函數連線至 Amazon MSK。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/msk_tut_log.png)

# 搭配使用 Lambda 與自我管理 Apache Kafka
<a name="with-kafka"></a>

本主題說明如何搭配使用 Lambda 與自我管理 Kafka 叢集。在 AWS 術語中，自我管理叢集包含非AWS 託管的 Kafka 叢集。例如，您可以透過雲端提供者 (例如 [Confluent Cloud](https://www.confluent.io/confluent-cloud/) 或 [Redpanda](https://www.redpanda.com/)) 託管 Kafka 叢集。

本章說明了如何將自我管理的 Apache Kafka 叢集用作 Lambda 函式的事件來源。將自我管理的 Apache Kafka 與 Lambda 整合的一般流程包含以下步驟：

1. **[叢集與網路設定](with-kafka-cluster-network.md)**：首先，使用正確的聯網組態設定自我管理的 Apache Kafka 叢集，允許 Lambda 存取叢集。

1. **[事件來源映射設定](with-kafka-configure.md)**：接著，建立 Lambda 所需的[事件來源映射](invocation-eventsourcemapping.md)資源，將 Apache Kafka 叢集安全地連線至函式。

1. **[函式與許可設定](with-kafka-permissions.md)**：最後，確保函式已正確設定，並且其[執行角色](lambda-intro-execution-role.md)具有必要許可。

Apache Kafka 作為事件來源時，其運作方式類似於使用 Amazon Simple Queue Service (Amazon SQS) 或 Amazon Kinesis。Lambda 會在內部輪詢事件來源中的新訊息，然後同步調用目標 Lambda 函數。Lambda 會批次讀取訊息，並將這些訊息作為事件酬載提供給函數。最大批次大小可進行設定 (預設為 100 則訊息)。如需詳細資訊，請參閱[批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)。

若要最佳化自我管理 Apache Kafka 事件來源映射的輸送量，請設定佈建模式。在佈建模式中，可以定義配置給事件來源映射的事件輪詢器數量下限和上限。這可以提高事件來源映射處理意外訊息尖峰的能力。如需詳細資訊，請參閱[佈建模式](kafka-scaling-modes.md#kafka-provisioned-mode)。

**警告**  
Lambda 事件來源映射至少會處理每個事件一次，而且可能會重複處理記錄。為避免與重複事件相關的潛在問題，強烈建議您讓函數程式碼具有等冪性。若要進一步了解，請參閱 AWS 知識中心中的[如何使 Lambda 函數具有等冪性](https://repost.aws/knowledge-center/lambda-function-idempotent)。

對於基於 Kafka 的事件來源，Lambda 支援處理控制參數，例如批次間隔和批次大小。如需詳細資訊，請參閱[批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)。

如需如何使用自我管理的 Kafka 作為事件來源的範例，請參閱 AWS 運算部落格上的[使用自我託管的 Apache Kafka 作為 的事件來源 AWS Lambda](https://aws.amazon.com/blogs/compute/using-self-hosted-apache-kafka-as-an-event-source-for-aws-lambda/)。

**Topics**
+ [

## 範例事件
](#smaa-sample-event)
+ [

# 為 Lambda 設定自我管理的 Apache Kafka 叢集與網路
](with-kafka-cluster-network.md)
+ [

# 設定 Lambda 執行角色許可
](with-kafka-permissions.md)
+ [

# 為 Lambda 設定自我管理的 Apache Kafka 事件來源
](with-kafka-configure.md)

## 範例事件
<a name="smaa-sample-event"></a>

Lambda 會在調用 Lambda 函數時，在事件參數中傳送訊息批次。事件酬載包含訊息陣列。陣列中的每個項目包含 Kafka 主題和 Kafka 分割區識別符的詳細資訊，以及時間戳記和 base64 編碼的訊息。

```
{
   "eventSource": "SelfManagedKafka",
   "bootstrapServers":"b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
   "records":{
      "mytopic-0":[
         {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "key":"abcDEFghiJKLmnoPQRstuVWXyz1234==",
            "value":"SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
            "headers":[
               {
                  "headerKey":[
                     104,
                     101,
                     97,
                     100,
                     101,
                     114,
                     86,
                     97,
                     108,
                     117,
                     101
                  ]
               }
            ]
         }
      ]
   }
}
```

# 為 Lambda 設定自我管理的 Apache Kafka 叢集與網路
<a name="with-kafka-cluster-network"></a>

若要將 Lambda 函式連線至自我管理的 Apache Kafka 叢集，需要正確設定叢集及其所在的網路。本頁介紹了如何設定叢集與網路。如果叢集與網路已正確設定，請參閱[為 Lambda 設定自我管理的 Apache Kafka 事件來源](with-kafka-configure.md)，設定事件來源映射。

**Topics**
+ [

## 自我管理的 Apache Kafka 叢集設定
](#kafka-cluster-setup)
+ [

## 設定網路安全
](#services-kafka-vpc-config)

## 自我管理的 Apache Kafka 叢集設定
<a name="kafka-cluster-setup"></a>

您可以透過雲端提供者 (例如 [Confluent Cloud](https://www.confluent.io/confluent-cloud/) 或 [Redpanda](https://www.redpanda.com/)) 託管自我管理的 Apache Kafka 叢集，也可以在自訂的基礎結構上執行該叢集。確保叢集已正確設定，並且可從 Lambda 事件來源映射所要連線的網路進行存取。

## 設定網路安全
<a name="services-kafka-vpc-config"></a>

若要透過事件來源映射授予 Lambda 對自我管理的 Apache Kafka 的完整存取權，您的叢集必須使用公有端點 (公有 IP 位址)，或者您必須提供建立叢集之 Amazon VPC 的存取權。

當您將自我管理的 Apache Kafka 與 Lambda 搭配使用時，請建立 [AWS PrivateLink VPC 端點](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html)，為您的函數提供 Amazon VPC 中資源的存取權。

**注意**  
具有事件來源映射的函數需要使用 AWS PrivateLink VPC 端點，該映射使用事件輪詢器的預設 (隨需) 模式。如果您的事件來源映射使用[佈建模式](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)，則不需要設定 AWS PrivateLink VPC 端點。

建立端點以提供對下列資源的存取權：
+  Lambda：為 Lambda 服務主體建立端點。
+  AWS STS：為 AWS STS 建立端點，以便服務主體代表您擔任角色。
+  Secrets Manager：如果您的叢集使用 Secrets Manager 來儲存憑證，則請為 Secrets Manager 建立端點。

或者，在 Amazon VPC 中的每個公有子網路上設定一個 NAT 閘道。如需更多詳細資訊，請參閱 [啟用 VPC 連線的 Lambda 函數的網際網路存取](configuration-vpc-internet.md)。

當您為自我管理的 Apache Kafka 建立事件來源映射時，Lambda 會檢查是否已存在彈性網絡介面 (ENI)，適用於為您的 Amazon VPC 設定的子網路和安全群組。如果 Lambda 找到現有的 ENI，它會嘗試重複使用它們。否則，Lambda 會建立新的 ENI 以連線至事件來源並調用您的函數。

**注意**  
Lambda 函數一律會在 Lambda 服務所擁有的 VPC 內執行。函數的 VPC 組態不會影響事件來源映射。只有事件來源的聯網組態會決定 Lambda 如何連線至您的事件來源。

為包含叢集的 Amazon VPC 設定安全群組。根據預設，自我管理的 Apache Kafka 會使用下列連接埠：`9092`。
+ 傳入規則：允許與事件來源相關聯之安全群組的預設代理程式連接埠上的所有流量。或者，您可使用自我參照安全群組規則，允許來自同一安全群組內其他執行個體的存取。
+ 傳出規則：如果函式需要與 AWS 服務通訊，則允許外部目的地連接埠 `443` 上的所有流量。或者，如果不需要與其他 AWS 服務通訊，您也可以使用自我參照安全群組規則來限制代理程式的存取權。
+ Amazon VPC 端點傳入規則：如果您使用的是 Amazon VPC 端點，與您的 Amazon VPC 端點相關聯的安全群組必須允許來自叢集安全群組的連接埠 `443` 上的傳入流量。

如果您的叢集使用身分驗證，則您也可以限制 Secrets Manager 端點的端點政策。若要呼叫 Secrets Manager API，Lambda 會使用您的函數角色，而不是 Lambda 服務主體。

**Example VPC 端點政策 — Secrets Manager 端點**  

```
{
      "Statement": [
          {
              "Action": "secretsmanager:GetSecretValue",
              "Effect": "Allow",
              "Principal": {
                  "AWS": [
                      "arn:aws::iam::123456789012:role/my-role"
                  ]
              },
              "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
          }
      ]
  }
```

當您使用 Amazon VPC 端點時，AWS 會使用端點的彈性網絡介面 (ENI) 來路由您的 API 呼叫，以調用您的函數。Lambda 服務主體需要在使用這些 ENI 的任何角色和函數上呼叫 `lambda:InvokeFunction`。

根據預設，Amazon VPC 端點具有開放的 IAM 政策，允許廣泛存取資源。最佳實務是限制這些政策，以使用該端點執行所需的動作。為了確保事件來源映射能夠調用 Lambda 函數，VPC 端點政策必須允許 Lambda 服務主體呼叫 `sts:AssumeRole` 和 `lambda:InvokeFunction`。限制您的 VPC 端點政策以僅允許源自您組織內部的 API 呼叫，可阻止事件來源映射正常運作，因此在這些政策中需要 `"Resource": "*"`。

下列範例 VPC 端點政策展示了如何授予 Lambda 服務主體對 AWS STS 和 Lambda 端點的必要存取權。

**Example VPC 端點政策 – AWS STS 端點**  

```
{
      "Statement": [
          {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
    }
```

**Example VPC 端點政策 – Lambda 端點**  

```
{
      "Statement": [
          {
              "Action": "lambda:InvokeFunction",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
  }
```

# 設定 Lambda 執行角色許可
<a name="with-kafka-permissions"></a>

除了[存取自我管理的 Kafka 叢集](kafka-cluster-auth.md)之外，Lambda 函式還需要執行各種 API 動作的許可。您可以將這些許可新增到函數的[執行角色](lambda-intro-execution-role.md)。如果您的使用者需要存取任何 API 動作，請將必要的許可新增至 AWS Identity and Access Management (IAM) 使用者或角色的身分政策。

**Topics**
+ [

## 必要的 Lambda 函數許可
](#smaa-api-actions-required)
+ [

## 選用 Lambda 函數許可
](#smaa-api-actions-optional)
+ [

## 將許可新增至您的執行角色
](#smaa-permissions-add-policy)
+ [

## 使用 IAM 政策授予使用者存取權
](#smaa-permissions-add-users)

## 必要的 Lambda 函數許可
<a name="smaa-api-actions-required"></a>

若要在 Amazon CloudWatch Logs 中建立日誌並存放在日誌群組中，您的 Lambda 函數在其執行角色中必須具有下列許可：
+ [logs:CreateLogGroup](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
+ [logs:CreateLogStream](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html)
+ [日誌：PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)

## 選用 Lambda 函數許可
<a name="smaa-api-actions-optional"></a>

您的 Lambda 函數可能需要許可，才能：
+ 描述您 Secrets Manager 機密。
+ 存取您的 AWS Key Management Service (AWS KMS) 客戶受管金鑰。
+ 存取 Amazon VPC。
+ 將失敗調用的記錄傳送到目的地。

### Secrets Manager 和 AWS KMS 許可
<a name="smaa-api-actions-secrets"></a>

根據您為 Kafka 代理程式設定的存取控制類型，您的 Lambda 函數可能需要存取 Secrets Manager 秘密或解密 AWS KMS 客戶受管金鑰的許可。若要連線至這些資源，函數的執行角色必須具有下列許可：
+ [secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)
+ [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)

### VPC 許可
<a name="smaa-api-actions-vpc"></a>

如果只有某個 VPC 內的使用者可以存取自我管理 Apache Kafka 叢集，則您的 Lambda 函數必須具有存取 Amazon VPC 資源的許可。這些資源包括您的 VPC、子網路、安全群組和網路界面。若要連線至這些資源，函數的執行角色必須具有下列許可：
+ [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
+ [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
+ [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
+ [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
+ [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
+ [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)

## 將許可新增至您的執行角色
<a name="smaa-permissions-add-policy"></a>

若要存取自我管理 Apache Kafka 叢集使用的其他 AWS 服務，Lambda 會使用您在 Lambda 函數[執行角色](lambda-intro-execution-role.md)中定義的許可政策。

根據預設，Lambda 不允許針對自我管理 Apache Kafka 叢集執行必要或選用的動作。您必須在 [IAM 信任政策](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_update-role-trust-policy.html)中為您的執行角色建立並定義這些動作。此範例會示範如何建立允許 Lambda 存取 Amazon VPC 資源的政策。

------
#### [ JSON ]

****  

```
{
        "Version":"2012-10-17",		 	 	 
        "Statement":[
           {
              "Effect":"Allow",
              "Action":[
                 "ec2:CreateNetworkInterface",
                 "ec2:DescribeNetworkInterfaces",
                 "ec2:DescribeVpcs",
                 "ec2:DeleteNetworkInterface",
                 "ec2:DescribeSubnets",
                 "ec2:DescribeSecurityGroups"
              ],
              "Resource":"*"
           }
        ]
     }
```

------

## 使用 IAM 政策授予使用者存取權
<a name="smaa-permissions-add-users"></a>

根據預設，使用者和角色沒有執行[事件來源 API 操作](invocation-eventsourcemapping.md#event-source-mapping-api)的許可。若要將存取權授予組織或帳戶中的使用者，您可能需要建立或更新身分型政策。如需詳細資訊，請參閱《*IAM 使用者指南*》中的[使用政策控制對 AWS 資源的存取](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_controlling.html)。

如需疑難排解身分驗證與授權錯誤的相關資訊，請參閱[對 Kafka 事件來源映射錯誤進行疑難排解](with-kafka-troubleshoot.md)。

# 為 Lambda 設定自我管理的 Apache Kafka 事件來源
<a name="with-kafka-configure"></a>

若要將自我管理的 Apache Kafka 叢集用作 Lambda 函式的事件來源，需要建立將這兩項資源連線的[事件來源映射](invocation-eventsourcemapping.md)。本頁介紹了如何為自我管理的 Apache Kafka 建立事件來源映射。

本頁假設您已正確設定 Kafka 叢集及其所在的網路。如需設定叢集或網路，請參閱[為 Lambda 設定自我管理的 Apache Kafka 叢集與網路](with-kafka-cluster-network.md)。

**Topics**
+ [

## 將自我管理的 Apache Kafka 叢集用作事件來源
](#kafka-esm-overview)
+ [

# 在 Lambda 中設定叢集身分驗證方法
](kafka-cluster-auth.md)
+ [

# 為自我管理的 Apache Kafka 事件來源建立 Lambda 事件來源映射
](kafka-esm-create.md)
+ [

# Lambda 中所有自我管理的 Apache Kafka 事件來源組態參數
](kafka-esm-parameters.md)

## 將自我管理的 Apache Kafka 叢集用作事件來源
<a name="kafka-esm-overview"></a>

當您將 Apache Kafka 或 Amazon MSK 叢集新增為 Lambda 函數的觸發條件時，該叢集會用作[事件來源](invocation-eventsourcemapping.md)。

Lambda 會根據您指定的[起始位置](kafka-starting-positions.md)，從 Kafka 主題 (您在 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 請求中指定為 `Topics`) 讀取事件資料。處理成功後，您的 Kafka 主題將遞交給 Kafka 叢集。

Lambda 會依序讀取每個 Kafka 主題分割區的訊息。單一 Lambda 承載可以包含來自多個分割區的訊息。有更多記錄可用時，Lambda 會根據您在 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 請求中指定的 BatchSize 值，繼續以批次方式來處理記錄，直到函式追上主題的進度為止。

Lambda 處理每個批次後，會遞交該批次中訊息的偏移量。如果函數針對批次中的任何訊息傳回錯誤，Lambda 會重試整個批次的訊息，直至處理成功或訊息過期。您可以將所有重試嘗試失敗時的記錄傳送至失敗時的目的地，以便稍後處理。

**注意**  
雖然 Lambda 函數的逾時上限通常為 15 分鐘，但 Amazon MSK、自我管理的 Apache Kafka、Amazon DocumentDB 以及 Amazon MQ for ActiveMQ 和 Amazon MQ for RabbitMQ 的事件來源映射只支援 14 分鐘逾時限制上限的函數。

# 在 Lambda 中設定叢集身分驗證方法
<a name="kafka-cluster-auth"></a>

Lambda 支持多種方法來進行您自我管理 Apache Kafka 叢集的身分驗證。請確保您已設定 Kafka 叢集使用其中一種支援的身分驗證方法。如需有關 Kafka 安全性的詳細資訊，請參閱 Kafka 文件的「[安全性](http://kafka.apache.org/documentation.html#security)」一節。

## SASL/SCRAM 身分驗證
<a name="smaa-auth-sasl"></a>

Lambda 支援 Simple Authentication and Security Layer/Salted Challenge Response Authentication Mechanism (SASL/SCRAM) 身分驗證與 Transport Layer Security (TLS) 加密 (`SASL_SSL`)。Lambda 會傳送加密的憑證，以便向叢集進行身分驗證。Lambda 不支援含純文字的 SASL/SCRAM (`SASL_PLAINTEXT`)。如需 SASL/SCRAM 身分驗證的詳細資訊，請參閱 [RFC 5802](https://tools.ietf.org/html/rfc5802)。

Lambda 也支援 SASL/PLAIN 身分驗證。由於這套機制使用純文字憑證，與伺服器的連線必須使用 TLS 加密，以確保憑證受到保護。

若使用 SASL 身分驗證，您需將登入憑證儲存為 AWS Secrets Manager中的秘密。如需使用 Secrets Manager 的詳細資訊，請參閱*AWS Secrets Manager 《 使用者指南*》中的[建立 AWS Secrets Manager 秘密](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。

**重要**  
若要使用 Secrets Manager 進行身分驗證，秘密必須與 Lambda 函數存放在相同的 AWS 區域中。

## 交互 TLS 驗證
<a name="smaa-auth-mtls"></a>

相互 TLS (mTLS) 可提供用戶端與伺服器之間的雙向身分驗證。用戶端會將憑證傳送至伺服器以供伺服器驗證用戶端，而伺服器會將憑證傳送至用戶端以供用戶端驗證伺服器。

在自我管理 Apache Kafka 中，Lambda 會以用戶端的身分運作。您可以設定用戶端憑證 (做為 Secrets Manager 中的機密) 來驗證 Lambda 與 Kafka 代理程式。用戶端憑證必須由伺服器信任存放區中的憑證授權機構簽署。

Kafka 叢集會傳送伺服器憑證到 Lambda 來驗證 Kafka 代理程式與 Lambda。伺服器憑證可以是公有憑證授權機構憑證或私有憑證授權機構/自行簽署的憑證。公有憑證授權機構憑證必須由 Lambda 信任存放區中的憑證授權機構 (CA) 簽署。若為私有憑證授權機構/自行簽署的憑證，您可以設定伺服器根憑證授權機構憑證 (做為 Secrets Manager 中的機密)。Lambda 使用根憑證來驗證 Kafka 代理程式。

如需有關 mTLS 的詳細資訊，請參閱[將 Amazon MSK 的相互 TLS 身分驗證作為事件來源](https://aws.amazon.com/blogs/compute/introducing-mutual-tls-authentication-for-amazon-msk-as-an-event-source)。

## 設定用戶端憑證機密
<a name="smaa-auth-secret"></a>

CLIENT\$1CERTIFICATE\$1TLS\$1AUTH 機密必須有憑證欄位和私有金鑰欄位。若為加密的私有金鑰，機密需要私有金鑰密碼。憑證與私有金鑰均必須為 PEM 格式。

**注意**  
Lambda 支援 [PBES1](https://datatracker.ietf.org/doc/html/rfc2898/#section-6.1) (但不支援 PBES2) 私有金鑰加密演算法。

憑證欄位必須包含憑證清單，以用戶端憑證開頭，隨後則是任何中繼憑證，並以根憑證結尾。每個憑證均必須以新的一行開始，結構如下：

```
-----BEGIN CERTIFICATE-----  
            <certificate contents>
-----END CERTIFICATE-----
```

Secrets Manager 支援高達 65,536 個位元組的機密，此空間足以容納長憑證鏈。

私有金鑰必須為 [PKCS \$18](https://datatracker.ietf.org/doc/html/rfc5208) 格式，結構如下：

```
-----BEGIN PRIVATE KEY-----  
             <private key contents>
-----END PRIVATE KEY-----
```

對於已加密的私有金鑰，請使用下列結構：

```
-----BEGIN ENCRYPTED PRIVATE KEY-----  
              <private key contents>
-----END ENCRYPTED PRIVATE KEY-----
```

下列範例顯示的是使用了已加密私有金鑰之 mTLS 身分驗證的機密內容。若為加密的私有金鑰，請在機密中包含私有金鑰密碼。

```
{"privateKeyPassword":"testpassword",
"certificate":"-----BEGIN CERTIFICATE-----
MIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw
...
j0Lh4/+1HfgyE2KlmII36dg4IMzNjAFEBZiCRoPimO40s1cRqtFHXoal0QQbIlxk
cmUuiAii9R0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb
...
rQoiowbbk5wXCheYSANQIfTZ6weQTgiCHCCbuuMKNVS95FkXm0vqVD/YpXKwA/no
c8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==
-----END CERTIFICATE-----",
"privateKey":"-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFKzBVBgkqhkiG9w0BBQ0wSDAnBgkqhkiG9w0BBQwwGgQUiAFcK5hT/X7Kjmgp
...
QrSekqF+kWzmB6nAfSzgO9IaoAaytLvNgGTckWeUkWn/V0Ck+LdGUXzAC4RxZnoQ
zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==
-----END ENCRYPTED PRIVATE KEY-----"
}
```

## 設定伺服器根憑證授權機構憑證機密
<a name="smaa-auth-ca-cert"></a>

如果您的 Kafka 代理程式使用 TLS 加密與私有憑證授權機構簽署的憑證，則建立此機密。您可以使用 TLS 加密以供 VPC、SASL/SCRAM、SASL/PLAIN 或 mTLS 身分驗證之用。

伺服器根憑證授權機構憑證機密必須有包含 Kafka 代理程式根憑證授權機構憑證 (格式為 PEM) 的欄位。下列範例說明機密的結構。

```
{"certificate":"-----BEGIN CERTIFICATE-----
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dG...
-----END CERTIFICATE-----"
}
```

# 為自我管理的 Apache Kafka 事件來源建立 Lambda 事件來源映射
<a name="kafka-esm-create"></a>

若要建立事件來源映射，可以使用 Lambda 主控台、[AWS Command Line Interface (CLI)](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 或 [AWS SDK](https://aws.amazon.com/getting-started/tools-sdks/)。

下列主控台步驟會將自我管理的 Apache Kafka 叢集新增為 Lambda 函式的觸發程序。在此之下，此操作會建立事件來源映射資源。

## 先決條件
<a name="kafka-esm-prereqs"></a>
+ 自我管理 Apache Kafka 叢集。Lambda 支援 Apache Kafka 版本 0.10.1.0 及更高版本。
+ 具有許可的[執行角色](lambda-intro-execution-role.md)，可存取自我管理的 Kafka 叢集使用 AWS 的資源。

## 新增自我管理 Kafka 叢集 (主控台)
<a name="kafka-esm-console"></a>

按照下列步驟，將您的 Apache Kafka 叢集和 Kafka 主題新增為 Lambda 函數的觸發條件。

**將 Apache Kafka 觸發條件新增至您的 Lambda 函數 (主控台)**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇 Lambda 函數的名稱。

1. 在**函數概觀**下，選擇**新增觸發條件**。

1. 在 **Trigger configuration (觸發條件)** 下，執行下列動作：

   1. 選擇 **Apache Kafka** 觸發條件類型。

   1. 對於 **Bootstrap 伺服器**，輸入叢集中 Kafka 代理程式的主機和連接埠對地址，然後選擇 **新增**。針對叢集中的每個 Kafka 代理程式重複此操作。

   1. 對於 **Topic name (主題名稱)**，輸入用於在叢集中存儲記錄之 Kafka 主題的名稱。

   1. 如果您設定佈建模式，請輸入**最小值事件輪詢器**的值、**最大值事件輪詢器**的值，以及 PollerGroupName 的選用值，以指定相同事件來源 VPC 內多個 ESMs 的分組。

   1. (選用) 對於 **批次大小**，輸入單一批次中接收的最大記錄數。

   1. 對於 **Batch window** (批次時段)，輸入 Lambda 調用函數之前收集記錄所花費的最長秒數。

   1. (選用) 對於**取用者群組 ID** ，輸入要加入的 Kafka 取用者群組 ID。

   1. (選用) 在**開始位置**欄位中，選擇**最新**，可從最新記錄開始讀取串流；選擇**水平修剪**，可從最早的可用記錄開始；選擇**在時間戳記**，可指定開始讀取的時間戳記。

   1. (選用) 若為 **VPC**，請為您的 Kafka 叢集選擇 Amazon VPC。然後，選擇 **VPC 子網路** 和 **VPC 安全群組** 。

      如果只有您的 VPC 內的使用者會存取代理程式，則必須要有此設定。

      

   1. (選用) 對於 **身分驗證** ，選擇 **新增** ，然後執行下列動作：

      1. 選擇您叢集中 Kafka 代理程式的存取或身分驗證協定。
         + 如果您的 Kafka 代理程式使用 SASL/PLAIN 身分驗證，請選擇 **BASIC\$1AUTH**。
         + 如果您的代理程式使用 SASL/SCRAM 身分驗證，請選擇其中一種 **SASL\$1SCRAM** 通訊協定。
         + 如果您要設定 mTLS 身分驗證，請選擇 **CLIENT\$1CERTIFICATE\$1TLS\$1AUTH** 通訊協定。

      1. 若為 SASL/SCRAM 或 mTLS 身分驗證，請選擇包含 Kafka 叢集憑證的 Secrets Manager 機密金鑰。

   1. (選用) 若為 **加密** ，如果您的 Kafka 代理程式使用私有憑證授權機構簽署的憑證，請選擇包含 Kafka 代理程式用於 TLS 加密的根憑證授權機構憑證的 Secrets Manager 機密。

      此設定適用於 SASL/SCRAM 或 SASL/PLAIN 的 TLS 加密，也適用於 mTLS 身分驗證。

   1. 若要建立處於停用狀態的觸發條件以進行測試 (建議做法)，請取消勾選 **啟用觸發條件** 。或者，若要立即啟用觸發條件，請選取 **啟用觸發條件**。

1. 若要建立觸發條件，請選擇 **新增** 。

## 新增自我管理 Kafka 叢集 (AWS CLI)
<a name="kafka-esm-cli"></a>

使用下列範例 AWS CLI 命令來建立和檢視 Lambda 函數的自我管理 Apache Kafka 觸發條件。

### 使用 SASL/SCRAM
<a name="kafka-esm-cli-create"></a>

如果 Kafka 使用者透過網際網路存取您的 Kafka 代理程式，請指定針對 SASL/SCRAM 身分驗證建立的 Secrets Manager 機密。下列範例使用 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) AWS CLI 命令，將名為 的 Lambda 函數映射`my-kafka-function`至名為 的 Kafka 主題`AWSKafkaTopic`。

```
aws lambda create-event-source-mapping \ 
  --topics AWSKafkaTopic \
  --source-access-configuration Type=SASL_SCRAM_512_AUTH,URI=arn:aws:secretsmanager:us-east-1:111122223333:secret:MyBrokerSecretName \
  --function-name arn:aws:lambda:us-east-1:111122223333:function:my-kafka-function \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc3.xyz.com:9092", "abc2.xyz.com:9092"]}}'
```

### 使用 VPC
<a name="kafka-esm-cli-create-vpc"></a>

如果只有您 VPC 內的 Kafka 使用者可存取您的 Kafka 代理程式，則必須指定您的 VPC、子網路和 VPC 安全群組。下列範例使用 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) AWS CLI 命令，將名為 的 Lambda 函數映射`my-kafka-function`至名為 的 Kafka 主題`AWSKafkaTopic`。

```
aws lambda create-event-source-mapping \ 
  --topics AWSKafkaTopic \
  --source-access-configuration '[{"Type": "VPC_SUBNET", "URI": "subnet:subnet-0011001100"}, {"Type": "VPC_SUBNET", "URI": "subnet:subnet-0022002200"}, {"Type": "VPC_SECURITY_GROUP", "URI": "security_group:sg-0123456789"}]' \
  --function-name arn:aws:lambda:us-east-1:111122223333:function:my-kafka-function \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc3.xyz.com:9092", "abc2.xyz.com:9092"]}}'
```

### 使用 檢視狀態 AWS CLI
<a name="kafka-esm-cli-view"></a>

下列範例使用 [get-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) AWS CLI 命令來描述您建立的事件來源映射狀態。

```
aws lambda get-event-source-mapping
              --uuid dh38738e-992b-343a-1077-3478934hjkfd7
```

# Lambda 中所有自我管理的 Apache Kafka 事件來源組態參數
<a name="kafka-esm-parameters"></a>

所有 Lambda 事件來源類型都會共用相同的 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 和 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 操作。不過，僅有部分參數適用於自我管理的 Apache Kafka，如下表所示。


| 參數 | 必要 | 預設 | 備註 | 
| --- | --- | --- | --- | 
|  BatchSize  |  否  |  100  |  上限：10,000  | 
|  DestinationConfig  |  N  |  N/A  |  [擷取 Amazon MSK 和自我管理的 Apache Kafka 事件來源的捨棄批次](kafka-on-failure.md)  | 
|  已啟用  |  N  |  True  |  | 
|  FilterCriteria  |  N  |  N/A  |  [控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)  | 
|  FunctionName  |  是  |  N/A  |    | 
|  KMSKeyArn  |  N  |  N/A  |  [篩選條件加密](invocation-eventfiltering.md#filter-criteria-encryption)  | 
|  MaximumBatchingWindowInSeconds  |  N  |  500 毫秒  |  [批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)  | 
|  ProvisionedPollersConfig  |  N  |  `MinimumPollers`：若未指定，預設值為 1。 `MaximumPollers`：若未指定，預設值為 200。 `PollerGroupName`：不適用  |  [佈建模式](kafka-scaling-modes.md#kafka-provisioned-mode)  | 
|  SelfManagedEventSource  |  Y  | N/A |  Kafka 代理程式清單。只能在建立時進行設定  | 
|  SelfManagedKafkaEventSourceConfig  |  N  |  包含預設為一個唯一值的 ConsumerGroupId 欄位。  |  只能在建立時進行設定  | 
|  SourceAccessConfigurations  |  N  |  沒有憑證  |  叢集的 VPC 資訊或身分驗證憑證   對於 SASL\$1PLAIN，設定為 BASIC\$1AUTH  | 
|  StartingPosition  |  Y  |  N/A  |  AT\$1TIMESTAMP、TRIM\$1HORIZON 或 LATEST 只能在建立時進行設定  | 
|  StartingPositionTimestamp  |  N  |  N/A  |  StartingPosition 設定為 AT\$1TIMESTAMP 時需要  | 
|  Tags (標籤)  |  N  |  N/A  |  [在事件來源映射上使用標籤](tags-esm.md)  | 
|  主題  |  Y  |  N/A  |  主題名稱 只能在建立時進行設定  | 

**注意**  
當您指定 時`PollerGroupName`，相同 Amazon VPC 中的多個 ESMs 可以共用事件輪詢單元 (EPU) 容量。您可以使用此選項來最佳化 ESM 的佈建模式成本。ESM 分組的需求：  
ESMs 必須位於相同的 Amazon VPC 內
每個輪詢器群組最多 100 ESMs 
群組中所有 ESMs 的彙總輪詢器上限不能超過 2000
您可以更新 `PollerGroupName`，將 ESM 移至不同的群組，或將 `PollerGroupName`設定為空字串 ("")，從群組中移除 ESM。

# Lambda 中的 Apache Kafka 事件輪詢器擴展模式
<a name="kafka-scaling-modes"></a>

對於 Amazon MSK 和自我管理的 Apache Kafka 事件來源映射，可從以下兩種事件輪詢器擴展模式中任擇其一：
+ [隨需模式 (預設)](#kafka-default-mode)
+ [佈建模式](#kafka-provisioned-mode)

## 隨需模式 (預設)
<a name="kafka-default-mode"></a>

當您最初建立 Kafka 事件來源時，Lambda 會配置預設數量的事件輪詢器來處理 Kafka 主題中的所有分割區。Lambda 會根據訊息負載自動增加或減少[事件輪詢器](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)數量。

每 1 分鐘，Lambda 會評估主題中所有分割區的偏移延遲。如果偏移延遲太高，則表示分割區接收訊息的速度比 Lambda 處理訊息的速度更快。如有必要，Lambda 會新增或移除主題的事件輪詢器。此新增或移除事件輪詢器的自動擴展程序會在評估後三分鐘內發生。

如果您的目標 Lambda 函數遭限流，則 Lambda 會減少事件輪詢器的數量。此動作可透過減少事件輪詢器可擷取和傳送至函數的訊息數量，減少函數的工作負載。

## 佈建模式
<a name="kafka-provisioned-mode"></a>

對於您需要微調事件來源映射輸送量的工作負載，可以使用佈建模式。在佈建模式中，可以定義佈建的事件輪詢器數量的下限和上限。這些佈建的事件輪詢器專用於您的事件來源映射，並且可以透過回應性自動擴展處理意外的訊息尖峰。我們建議您針對效能需求嚴格的 Kafka 工作負載使用佈建模式。

在 Lambda 中，事件輪詢器是具有不同事件來源類型之輸送量功能的運算單位。對於 Amazon MSK 和自我管理的 Apache Kafka，每個事件輪詢器最多可以處理 5 MB/秒的輸送量或最多 5 個並行調用。例如，如果您的事件來源產生平均承載 1 MB，且函數的平均持續時間為 1 秒，則單一 Kafka 事件輪詢器可以支援 5 MB/秒輸送量和 5 個並行 Lambda 調用 （假設沒有承載轉換）。對於 Amazon SQS，每個事件輪詢器最多可以處理每秒 1 MB 的輸送量或最多 10 個並行調用。使用佈建模式會根據您的事件輪詢器用量產生額外費用。如需定價詳細資訊，請參閱 [AWS Lambda 定價](https://aws.amazon.com/lambda/pricing/)。

**注意**  
使用佈建模式時，您不需要建立 AWS PrivateLink VPC 端點，也不需要在網路組態中授予相關聯的許可。

在佈建模式中，事件輪詢器數目下限 (`MinimumPollers`) 的接受值範圍介於 1 到 200 之間，包括 1 和 200 在內。事件輪詢器數目上限 (`MaximumPollers`) 的接受值範圍介於 1 到 2,000 之間，包括 1 和 2,000 在內。`MaximumPollers` 必須大於或等於 `MinimumPollers`。此外，為了在分割區內維持有序處理，Lambda 將 `MaximumPollers` 限制為不超過主題中的分割區數量。

如需選擇適當的事件輪詢器數量下限值和上限值的詳細資訊，請參閱[最佳實務](#kafka-provisioned-mode-bp)。

您可以使用主控台或 Lambda API，為 Kafka 事件來源映射設定佈建模式。

**為現有事件來源映射設定佈建模式 (主控台)**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇具有要設定佈建模式之事件來源映射的函式。

1. 選擇**組態**，然後選擇**觸發條件**。

1. 選擇要設定佈建模式的事件來源映射，然後選擇**編輯**。

1. 在**佈建模式**欄位中，選取**設定**。
   + 針對**事件輪詢器下限**，輸入介於 1 到 200 之間的值。如果您沒有指定值，則 Lambda 會選擇預設值 1。
   + 針對**事件輪詢器上限**，輸入介於 1 到 2,000 之間的值。此值必須大於或等於**事件輪詢器下限**值。如果您沒有指定值，則 Lambda 會選擇預設值 200。

1. 選擇**儲存**。

您可以使用 [EventSourceMappingConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_EventSourceMappingConfiguration.html) 中的 [ProvisionedPollerConfig](https://docs.aws.amazon.com/lambda/latest/api/API_ProvisionedPollerConfig.html) 物件，以程式設計方式設定佈建模式。例如，下列 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) CLI 命令會將 `MinimumPollers` 值設定為 5，將 `MaximumPollers` 值設定為 100。

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{"MinimumPollers": 5, "MaximumPollers": 100}'
```

設定佈建模式後，可以透過監控 `ProvisionedPollers` 指標來觀察工作負載的事件輪詢器使用情況。如需詳細資訊，請參閱[事件來源映射指標](monitoring-metrics-types.md#event-source-mapping-metrics)。

若要停用佈建模式並返回預設 (隨需) 模式，您可以使用下列 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) CLI 命令：

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{}'
```

## 進階錯誤處理和效能功能
<a name="services-kafka-advanced-features"></a>

對於已啟用佈建模式的 Kafka 事件來源映射，您可以設定其他功能來改善錯誤處理和效能：
+ [重試組態](kafka-retry-configurations.md) – 控制 Lambda 如何處理失敗的記錄，以及重試次數上限、記錄存留期限制、批次分割和部分批次回應。
+ [Kafka 失敗的目的地](kafka-on-failure-destination.md) – 將失敗的記錄傳送至 Kafka 主題，以供日後處理或分析。

## 使用佈建模式時的最佳實務和考量
<a name="kafka-provisioned-mode-bp"></a>

事件來源映射的事件輪詢器上限和下限的最佳組態取決於應用程式的效能需求。我們建議您從預設的事件輪詢器下限開始，以基準化效能設定檔。根據觀察到的訊息處理模式和所需的效能設定檔來調整您的組態。

對於具有尖峰流量和嚴格效能需求的工作負載，請增加事件輪詢器下限，以處理訊息的突然激增。若要判斷所需的事件輪詢器下限，請考慮工作負載的每秒訊息數和平均承載大小，並使用單一事件輪詢器的輸送容量 (至多 5 MBps) 做為參考。

為了在分割區內維持有序處理，Lambda 將事件輪詢器的上限限制為主題中的分割區數量。此外，事件來源映射可以擴展到的事件輪詢器上限取決於函數的並行設定。

啟用佈建模式時，請更新您的網路設定以移除 AWS PrivateLink VPC 端點和相關聯的許可。

## 佈建模式的成本最佳化
<a name="kafka-cost-optimization"></a>

### 佈建模式定價
<a name="kafka-provisioned-pricing"></a>

佈建模式會根據佈建的最低事件輪詢器，以及在自動擴展期間使用的事件輪詢器來收費。使用稱為事件輪詢單位 (EPU) 的計費單位來計算費用。您支付使用的 EPUs數量和持續時間，以 Event-Poller-Unit-hours 為單位。您可以將佈建模式與效能敏感應用程式的單一 ESM 搭配使用，也可以將相同 VPC 中的多個 ESMs 分組，以共用 EPU 容量和成本。我們將深入了解可協助您最佳化佈建模式成本的兩項功能。如需定價詳細資訊，請參閱 [AWS Lambda 定價](https://aws.amazon.com/lambda/pricing/)。

### 增強的 EPU 使用率
<a name="kafka-enhanced-epu-utilization"></a>

每個 EPU 最多支援 20 MB/s 的事件輪詢輸送量容量，並支援預設 10 個事件輪詢器。當您透過設定最低和最高輪詢器為 Kafka ESM 建立佈建模式時，它會根據每個 EPUs 的預設 10 個事件輪詢器，使用最低輪詢器編號來佈建 EPU。不過，每個事件輪詢器可以獨立擴展，以支援高達 5 MB/s 的輸送量容量，這可能需要特定 EPU 上較低的事件輪詢器密度，並且可以觸發 EPUs 的擴展。EPU 上配置的事件輪詢器數量取決於每個事件輪詢器耗用的運算容量。這種增強型 EPU 使用率的方法可讓具有不同輸送量需求的事件輪詢器有效地利用 EPU 容量，從而降低所有 ESMs 的成本。

### ESM 分組
<a name="kafka-esm-grouping-cost"></a>

若要進一步最佳化佈建模式成本，您可以將多個 Kafka ESMs 分組以共用 EPU 容量。透過 ESM 分組和增強的 EPU 使用率，相較於在單一 ESM 模式下執行，您可以降低低輸送量工作負載的佈建模式成本高達 90%。所有需要少於 1 個 EPU 容量ESMs ESM 都將受益於 ESM 分組。這類 ESMs通常只需要幾個最低事件輪詢器，即可支援其輸送量需求。此功能可讓您針對所有 Kafka 工作負載採用佈建模式，並受益於結構描述驗證、Avro/Protobuf 事件篩選、低延遲調用和僅在佈建模式下可用的增強型錯誤處理等功能。

當您為相同 Amazon VPC 中的多個 ESMs 設定具有相同值的`PollerGroupName`參數時，這些 ESMs 會共用 EPU 資源，而不是每個需要專用 EPU 容量。每個輪詢器群組最多可以分組 100 ESMs，且群組中所有 ESMs 的彙總輪詢器上限不能超過 2000 個。

#### 設定 ESM 分組 （主控台）
<a name="kafka-esm-grouping-console-cost"></a>

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函數。

1. 選擇**組態**，然後**觸發條件**。

1. 建立新的 Kafka 事件來源映射或編輯現有的事件來源映射時，請選取**佈建模式下****的設定**。

1. 針對**事件輪詢器下限**，輸入介於 1 到 200 之間的值。

1. 針對**事件輪詢器上限**，輸入介於 1 到 2,000 之間的值。

1. 針對**輪詢器群組名稱**，輸入群組的識別符。針對您要分組的其他 ESMs 使用相同的名稱。

1. 選擇**儲存**。

#### 設定 ESM 分組 (AWS CLI)
<a name="kafka-esm-grouping-cli-cost"></a>

下列範例會使用名為 的輪詢器群組建立 ESM`production-app-group`：

```
aws lambda create-event-source-mapping \
  --function-name myFunction1 \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/MyCluster/abcd1234 \
  --topics topic1 \
  --starting-position LATEST \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": "production-app-group"
  }'
```

若要將另一個 ESM 新增至相同的群組 （共用 EPU 容量），請使用相同的 PollerGroupName：

```
aws lambda create-event-source-mapping \
  --function-name myFunction2 \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/MyCluster/abcd1234 \
  --topics topic2 \
  --starting-position LATEST \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": "production-app-group"
  }'
```

**注意**  
您可以更新 `PollerGroupName`，將 ESM 移至不同的群組，或傳遞 的空字串 ("")，從群組中移除 ESM`PollerGroupName`：

```
# Move ESM to a different group
aws lambda update-event-source-mapping \
  --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": "new-group-name"
  }'

# Remove ESM from group (use dedicated resources)
aws lambda update-event-source-mapping \
  --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": ""
  }'
```

#### 分組策略考量事項
<a name="kafka-grouping-strategy-considerations"></a>
+ **應用程式界限** – 屬於相同應用程式或服務的群組 ESMs，以實現更好的成本分配和管理。考慮使用命名慣例，例如 `app-name-environment`（例如 `order-processor-prod`)。
+ **流量模式** – 避免將具有高輸送量和尖峰流量模式ESMs 分組，因為這可能會導致資源爭用。
+ **爆量半徑** – 如果共用基礎設施遇到問題，請考慮影響。相同群組中的所有 ESMs都會受到共用資源限制的影響。對於關鍵任務工作負載，您可能想要使用不同的群組或專用 ESMs。

#### 成本最佳化範例
<a name="kafka-cost-optimization-example"></a>

假設您擁有 10 ESMs，每個 ESM 設定了 1 個事件輪詢器，輸送量低於 2 MB/s：

**沒有分組：**
+ 每個 ESM 都需要自己的 EPU
+ 所需的 EPUs 總數：10
+ 每個 EPU 的成本：美國東部 （維吉尼亞北部） 每小時 0.185 美元
+ 每月 EPU 成本 (720 小時）：10 × 720 × \$10.185 = \$11，332

**使用分組：**
+ 所有 10 ESMs 共用 EPU 容量
+ 10 個事件輪詢器適合 1 個 EPU （每個 EPU 支援有新的 10 個輪詢器）
+ 所需的 EPUs 總數：1
+ 每月 EPU 成本 (720 小時）：1 × 720 × \$10.185 = \$1133.20
+ **節省成本：90% **（每月節省 1，198.80 美元）

# Lambda 中的 Apache Kafka 輪詢與串流開始位置
<a name="kafka-starting-positions"></a>

[StartingPosition 參數](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPosition)會告知 Lambda 何時開始從 Amazon MSK 或自我管理的 Apache Kafka 串流中讀取訊息。有三種選項可供選擇：
+ **最新**：Lambda 將從 Kafka 主題中最新一筆記錄之後開始讀取。
+ **水平修剪**：Lambda 將從 Kafka 主題中最後一筆未修剪的記錄開始讀取。這也是主題中最舊的記錄。
+ **在時間戳記**：Lambda 將從由時間戳記 (以 Unix 時間秒為單位) 定義的位置開始讀取。使用 [StartingPositionTimestamp 參數](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPositionTimestamp)來指定時間戳記。

在建立或更新事件來源映射期間，串流輪詢最終會一致：
+ 在建立事件來源映射期間，從串流開始輪詢事件可能需要幾分鐘時間。
+ 在更新事件來源映射期間，從串流停止並重新開始輪詢事件最多可能需要 90 秒。

這種行為表示，如果您將 `LATEST` 指定為串流的開始位置，事件來源映射可能會在建立或更新期間遺漏事件。為確保不會遺漏任何事件，需指定 `TRIM_HORIZON` 或 `AT_TIMESTAMP`。

# Lambda 中可自訂的取用者群組 ID
<a name="kafka-consumer-group-id"></a>

將 Amazon MSK 或自我管理的 Apache Kafka 設定為事件來源時，可指定[取用者群組](https://developer.confluent.io/learn-more/kafka-on-the-go/consumer-groups/) ID。此取用者群組 ID 是您希望 Lambda 函數加入之 Kafka 取用者群組的現有識別符。您可以使用此功能將任何進行中的 Kafka 記錄處理設定從其他取用者無縫遷移至 Lambda。

Kafka 會將訊息分發給取用者群組中的所有取用者。若您指定的取用者群組 ID 已有其他作用中取用者，Lambda 將僅能從 Kafka 主題接收部分訊息。如果您希望 Lambda 處理主題中的所有訊息，請關閉該取用者群組中的任何其他取用者。

此外，如果您指定取用者群組 ID，且 Kafka 找到具有相同 ID 的有效現有取用者群組，則 Lambda 會忽略用於事件來源映射的 [StartingPosition](kafka-starting-positions.md)。相反的，Lambda 會根據取用者群組的承諾偏移量開始處理記錄。如果您指定取用者群組 ID，但 Kafka 找不到現有的取用者群組，則 Lambda 會使用指定的 `StartingPosition` 來設定事件來源。

您指定的取用者群組 ID 在所有 Kafka 事件來源中必須是唯一的。使用指定的取用者群組 ID 建立 Kafka 事件來源映射之後，您就無法更新此值。

# 從 Amazon MSK 和自我管理的 Apache Kafka 事件來源篩選事件
<a name="kafka-filtering"></a>

您可以使用事件篩選來控制 Lambda 將哪些記錄從串流或佇列中傳送至函數。如需事件篩選運作方式的一般資訊，請參閱[控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)。

**注意**  
Amazon MSK 和自我管理的 Apache Kafka 事件來源映射，僅支援依據 `value` 鍵進行篩選。

**Topics**
+ [

## Kafka 事件篩選基礎知識
](#filtering-kafka)

## Kafka 事件篩選基礎知識
<a name="filtering-kafka"></a>

假設生產者正在將訊息寫入 Kafka 叢集中的某個主題，其格式可能為有效的 JSON 或純文字字串。範例記錄如下所示，訊息在 `value` 欄位中會轉換為 Base64 編碼字串。

```
{
    "mytopic-0":[
        {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "value":"SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
            "headers":[]
        }
    ]
}
```

假設 Apache Kafka 生產者正在以下列 JSON 格式將訊息寫入到您的主題。

```
{
    "device_ID": "AB1234",
    "session":{
        "start_time": "yyyy-mm-ddThh:mm:ss",
        "duration": 162
    }
}
```

您可以使用 `value` 索引鍵來篩選記錄。假設您只想篩選 `device_ID` 以字母 AB 開頭的記錄。`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"value\" : { \"device_ID\" : [ { \"prefix\": \"AB\" } ] } }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "value": {
        "device_ID": [ { "prefix": "AB" } ]
      }
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "value" : { "device_ID" : [ { "prefix":  "AB" } ] } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:kafka:us-east-2:123456789012:cluster/my-cluster/b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : { \"device_ID\" : [ { \"prefix\":  \"AB\" } ] } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : { \"device_ID\" : [ { \"prefix\":  \"AB\" } ] } }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "value" : { "device_ID" : [ { "prefix":  "AB" } ] } }'
```

------

使用 Kafka 時，您也可以篩選純文字字串格式的訊息記錄。假設您想忽略字串為「錯誤」的訊息。`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"value\" : [ { \"anything-but\": [ \"error\" ] } ] }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "value": [
        {
        "anything-but": [ "error" ]
        }
    ]
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "value" : [ { "anything-but": [ "error" ] } ] }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:kafka:us-east-2:123456789012:cluster/my-cluster/b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : [ { \"anything-but\": [ \"error\" ] } ] }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : [ { \"anything-but\": [ \"error\" ] } ] }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "value" : [ { "anything-but": [ "error" ] } ] }'
```

------

Kafka 訊息必須是 UTF-8 編碼的字串，其格式可為純文字字串或 JSON。這是因為 Lambda 會在套用篩選條件之前，將 Kafka 位元組陣列解碼成 UTF-8。如果您的訊息使用其他編碼方式 (例如 UTF-16 或 ASCII)，或者訊息格式與 `FilterCriteria` 格式不相符，則 Lambda 只會處理中繼資料篩選條件。下表摘要說明特定行為：


| 傳入訊息 格式 | 訊息屬性的篩選條件模式格式 | 產生的動作 | 
| --- | --- | --- | 
|  純文字的字串  |  純文字的字串  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 
|  純文字的字串  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  純文字的字串  |  有效的 JSON  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  純文字的字串  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  有效的 JSON  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 
|  非 UTF-8 編碼字串  |  JSON、純字串或沒有模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 

# 在 Lambda 中將結構描述登錄檔與 Kafka 事件來源搭配使用
<a name="services-consume-kafka-events"></a>

 結構描述登錄檔可協助您定義並管理資料串流結構描述。結構描述定義資料記錄的結構和格式。在 Kafka 事件來源映射的情境中，您可以設定結構描述登錄檔，在 Kafka 訊息送達 Lambda 函式之前，依據預先定義的結構描述驗證其結構與格式。這會將資料治理層新增至應用程式，讓您能夠有效管理資料格式、確保結構描述合規，並透過事件篩選來最佳化成本。

 此功能適用於所有程式設計語言，但請考慮以下要點：
+ Powertools for Lambda 提供 Java、Python 及 TypeScript 的專屬支援，不僅能維護與現有 Kafka 開發模式的一致性，更可讓您直接存取業務物件，無需自訂反序列化程式碼
+ 此功能僅適用於採用佈建模式的事件來源映射。結構描述登錄檔不支援隨需模式下的事件來源映射。如果您使用佈建模式且已設定結構描述登錄檔，將無法變更為隨需模式，除非您先移除結構描述登錄檔組態。如需詳細資訊，請參閱[佈建模式](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)
+ 每個事件來源映射 (ESM) 僅能設定一個結構描述登錄檔。將結構描述登錄檔與 Kafka 事件來源搭配使用，可能會增加 Lambda 事件輪詢單元 (EPU) 用量，此單元為佈建模式的一個定價維度。

**Topics**
+ [

## 結構描述登錄檔選項
](#services-consume-kafka-events-options)
+ [

## Lambda 如何對 Kafka 訊息執行結構描述驗證
](#services-consume-kafka-events-how)
+ [

## 設定 Kafka 結構描述登錄檔
](#services-consume-kafka-events-config)
+ [

## Avro 與 Protobuf 的篩選
](#services-consume-kafka-events-filtering)
+ [

## 承載格式與反序列化行為
](#services-consume-kafka-events-payload)
+ [

## 在 Lambda 函式中處理反序列化資料
](#services-consume-kafka-events-payload-examples)
+ [

## 結構描述登錄檔的身分驗證方法
](#services-consume-kafka-events-auth)
+ [

## 結構描述登錄檔問題的錯誤處理與疑難排解
](#services-consume-kafka-events-troubleshooting)

## 結構描述登錄檔選項
<a name="services-consume-kafka-events-options"></a>

 Lambda 支援下列結構描述登錄檔選項：
+ [AWS Glue 結構描述登錄檔](https://docs.aws.amazon.com/glue/latest/dg/schema-registry.html)
+ [Confluent Cloud 結構描述登錄檔](https://docs.confluent.io/platform/current/schema-registry/index.html)
+ [自我管理的 Confluent 結構描述登錄檔](https://docs.confluent.io/platform/current/schema-registry/index.html)

 結構描述登錄檔支援驗證採用下列資料格式的訊息：
+ Apache Avro
+ 通訊協定緩衝區 (Protobuf)
+ JSON 結構描述 (JSON-SE)

 若要使用結構描述登錄檔，請先確保事件來源映射處於佈建模式。當您使用結構描述登錄檔時，Lambda 會將結構描述的相關中繼資料新增至承載。如需詳細資訊，請參閱[承載格式與反序列化行為](#services-consume-kafka-events-payload)。

## Lambda 如何對 Kafka 訊息執行結構描述驗證
<a name="services-consume-kafka-events-how"></a>

 當您設定結構描述登錄檔時，Lambda 會為每個 Kafka 訊息執行下列步驟：

1. Lambda 會從叢集輪詢 Kafka 記錄。

1. Lambda 會根據結構描述登錄檔中的特定結構描述，驗證記錄中選定的訊息屬性。
   + 如果在登錄檔中找不到與訊息相關聯的結構描述，Lambda 會將訊息傳送至 DLQ，並標示原因代碼 `SCHEMA_NOT_FOUND`。

1. 為了驗證訊息，Lambda 會依據結構描述登錄檔組態對訊息進行反序列化。如果設定了事件篩選，Lambda 會接著根據設定的篩選條件執行篩選。
   + 如果反序列化失敗，Lambda 會將訊息傳送至 DLQ，並標示原因代碼 `DESERIALIZATION_ERROR`。如果未設定 DLQ，Lambda 會捨棄訊息。

1. 如果訊息透過結構描述登錄檔進行驗證，且未依篩選條件篩選出，Lambda 將會使用該訊息調用函式。

 此功能旨在驗證已使用與結構描述登錄檔整合的 Kafka 用戶端所產生的訊息。建議將 Kafka 生產者設定為與結構描述登錄檔搭配使用，以便建立格式正確的訊息。

## 設定 Kafka 結構描述登錄檔
<a name="services-consume-kafka-events-config"></a>

 下列主控台步驟會將 Kafka 結構描述登錄檔組態新增至事件來源映射。

**將 Kafka 結構描述登錄檔組態新增至事件來源映射 (主控台)**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇 **Configuration (組態)**。

1. 選擇**觸發程序**。

1. 選取要為其設定結構描述登錄檔的 Kafka 事件來源映射，然後選擇**編輯**。

1. 在**事件輪詢器組態**欄位中，選擇**設定結構描述登錄檔**。事件來源映射必須處於佈建模式，方可查看此選項。

1. 對於**結構描述登錄 URI**，輸入 AWS Glue 結構描述登錄檔的 ARN，或 Confluent Cloud 結構描述登錄檔的 HTTPS URL 或自我管理的 Confluent 結構描述登錄檔。

1. 下列組態步驟會告知 Lambda 如何存取結構描述登錄檔。如需詳細資訊，請參閱[結構描述登錄檔的身分驗證方法](#services-consume-kafka-events-auth)。
   + 在**存取組態類型**欄位中，選擇 Lambda 用於存取結構描述登錄檔的身分驗證類型。
   + 在**存取組態 URI** 欄位中，輸入 Secrets Manager 秘密的 ARN，向結構描述登錄檔進行身分驗證 (如適用)。確保函式的[執行角色](with-msk-permissions.md)包含正確的許可。

1. 僅當結構描述登錄檔由私有憑證認證機構 (CA) 或未納入 Lambda 信任存放區的憑證認證機構 (CA) 簽署時，**加密**欄位才適用。如適用，請提供私密金鑰，其中應包含結構描述登錄檔用於 TLS 加密的私有 CA 憑證。

1. 在**事件記錄格式**欄位中，選擇希望 Lambda 在完成結構描述驗證後將記錄交付給函式的方式。如需詳細資訊，請參閱[承載格式範例](#services-consume-kafka-events-payload)。
   + 如果選擇 **JSON**，Lambda 會以標準 JSON 格式傳送您在下方「結構描述驗證屬性」中選取的屬性。對於您未選取的屬性，Lambda 會依原狀傳送這些屬性。
   + 如果選擇 **SOURCE**，Lambda 會以原始來源格式傳送您在下方「結構描述驗證屬性」中選取的屬性。

1. 在**結構描述驗證屬性**欄位中，選取您希望 Lambda 使用結構描述登錄檔進行驗證與反序列化的訊息屬性。必須至少選取 **KEY** 或 **VALUE** 其中一項。若您選擇 JSON 作為事件記錄格式，Lambda 還會在將選定的訊息屬性傳送至函式之前，對其進行反序列化。如需詳細資訊，請參閱[承載格式與反序列化行為](#services-consume-kafka-events-payload)。

1. 選擇**儲存**。

 您也可以使用 Lambda API 來建立或更新帶有結構描述登錄檔組態的事件來源映射。下列範例示範如何使用 設定 AWS Glue 或 Confluent 結構描述登錄檔 AWS CLI，其對應至 API 參考中的 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) 和 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) API 操作： *AWS Lambda *

**重要**  
如果您使用 AWS CLI 或 `update-event-source-mapping` API 更新任何結構描述登錄檔組態欄位，則必須更新結構描述登錄檔組態的所有欄位。

------
#### [ Create Event Source Mapping ]

```
aws lambda create-event-source-mapping \
  --function-name my-schema-validator-function \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/a1b2c3d4-5678-90ab-cdef-11111EXAMPLE \
  --topics my-kafka-topic \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=1 \
  --amazon-managed-kafka-event-source-mapping '{
      "SchemaRegistryConfig" : {
          "SchemaRegistryURI": "https://abcd-ef123.us-west-2.aws.confluent.cloud",
          "AccessConfigs": [{
              "Type": "BASIC_AUTH", 
              "URI": "arn:aws:secretsmanager:us-east-1:123456789012:secret:secretName"
          }],
          "EventRecordFormat": "JSON",
          "SchemaValidationConfigs": [
          { 
              "Attribute": "KEY" 
          },
          { 
              "Attribute": "VALUE" 
          }]
      }
  }'
```

------
#### [ Update AWS Glue Schema Registry ]

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {
            "SchemaRegistryURI": "arn:aws:glue:us-east-1:123456789012:registry/registryName",
            "EventRecordFormat": "JSON",
            "SchemaValidationConfigs": [
            { 
                "Attribute": "KEY" 
            },
            { 
                "Attribute": "VALUE" 
            }]
        }
    }'
```

------
#### [ Update Confluent Schema Registry with Authentication ]

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {
            "SchemaRegistryURI": "https://abcd-ef123.us-west-2.aws.confluent.cloud",
            "AccessConfigs": [{
                "Type": "BASIC_AUTH", 
                "URI": "arn:aws:secretsmanager:us-east-1:123456789012:secret:secretName"
            }],
            "EventRecordFormat": "JSON",
            "SchemaValidationConfigs": [
            { 
                "Attribute": "KEY" 
            },
            { 
                "Attribute": "VALUE" 
            }]
        }
    }'
```

------
#### [ Update Confluent Schema Registry without Authentication ]

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {
            "SchemaRegistryURI": "https://abcd-ef123.us-west-2.aws.confluent.cloud",
            "EventRecordFormat": "JSON",
            "SchemaValidationConfigs": [
            { 
                "Attribute": "KEY" 
            },
            { 
                "Attribute": "VALUE" 
            }]
        }
    }'
```

------
#### [ Remove Schema Registry Configuration ]

若要從事件來源映射中移除結構描述登錄檔組態，可以使用 *AWS Lambda API Reference* 中的 CLI 命令 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)。

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {}
    }'
```

------

## Avro 與 Protobuf 的篩選
<a name="services-consume-kafka-events-filtering"></a>

 將 Avro 或 Protobuf 格式與結構描述登錄檔搭配使用時，即可將事件篩選功能套用至 Lambda 函式。篩選模式會在結構描述驗證後，套用至資料反序列化後的傳統 JSON 表示法。例如，使用定義產品詳細資訊 (包含價格) 的 Avro 結構描述，您可以根據價格值篩選訊息：

**注意**  
 當 Avro 進行反序列化時，會轉換為標準 JSON 格式，也意味著無法直接轉換回 Avro 物件。如需轉換為 Avro 物件，請改用 SOURCE 格式。  
 在 Protobuf 反序列化過程中，產生 JSON 的欄位名稱與結構描述中定義的欄位名稱相符，而非如 Protobuf 常規作法般為駝峰式大小寫。在建立篩選模式時，請記住這一點。

```
aws lambda create-event-source-mapping \
    --function-name myAvroFunction \
    --topics myAvroTopic \
    --starting-position TRIM_HORIZON \
    --kafka-bootstrap-servers '["broker1:9092", "broker2:9092"]' \
    --schema-registry-config '{
        "SchemaRegistryURI": "arn:aws:glue:us-east-1:123456789012:registry/myAvroRegistry",
        "EventRecordFormat": "JSON",
        "SchemaValidationConfigs": [
            { 
                "Attribute": "VALUE" 
            }
        ]
    }' \
    --filter-criteria '{
        "Filters": [
            {
                "Pattern": "{ \"value\" : { \"field_1\" : [\"value1\"], \"field_2\" : [\"value2\"] } }"
            }
        ]
    }'
```

 在此範例中，篩選模式會分析 `value` 物件，將 `field_1` 中符合 `"value1"`、`field_2` 中符合 `"value2"` 的訊息進行比對。在 Lambda 將訊息從 Avro 格式轉換為 JSON 格式之後，篩選條件會針對反序列化後的資料進行評估。

 如需有關事件篩選的詳細資訊，請參閱 [Lambda 事件篩選](invocation-eventfiltering.md)。

## 承載格式與反序列化行為
<a name="services-consume-kafka-events-payload"></a>

 使用結構描述登錄檔時，Lambda 會以類似於[常規事件承載](with-msk.md#msk-sample-event)的格式將最終承載傳送至函式，但會包含部分額外欄位。這些額外欄位取決於 `SchemaValidationConfigs` 參數。對於您選取進行驗證的每個屬性 (鍵或值)，Lambda 會將相應的結構描述中繼資料新增至承載。

**注意**  
必須將 [aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events) 更新至 3.16.0 版或更新版本，才能使用結構描述中繼資料欄位。

 例如，若驗證 `value` 欄位，Lambda 會將名為 `valueSchemaMetadata` 的欄位新增至承載。同理，如果驗證 `key` 欄位，Lambda 會新增名為 `keySchemaMetadata` 的欄位。此中繼資料包含資料格式與驗證所用結構描述 ID 的相關資訊：

```
"valueSchemaMetadata": {
    "dataFormat": "AVRO",
    "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
```

 `EventRecordFormat` 參數可以設定為 `JSON` 或 `SOURCE`，這決定了 Lambda 在將經過結構描述驗證的資料傳送至函式之前的處理方式。每個選項都提供不同的處理功能：
+ `JSON`：Lambda 將經過驗證的屬性反序列化為標準 JSON 格式，便於資料在原生 JSON 支援的語言中直接使用。若無需保留原始二進位格式或無需使用產生的類別，此格式尤其適用。
+ `SOURCE`：Lambda 會將資料的原始二進位格式保留為 Base64 編碼字串，允許直接轉換為 Avro 或 Protobuf 物件。當使用強型別語言或需要保持 Avro 或 Protobuf 結構描述的完整功能時，此格式至關重要。

基於上述格式特性與語言專屬考量，建議採用下列格式：


**依據程式設計語言建議的格式**  

| Language | Avro | Protobuf | JSON | 
| --- | --- | --- | --- | 
| Java | SOURCE | SOURCE | SOURCE | 
| Python | JSON | JSON | JSON | 
| NodeJS | JSON | JSON | JSON | 
| .NET | SOURCE | SOURCE | SOURCE | 
| 其他 | JSON | JSON | JSON | 

下列各節詳細介紹了這些格式，也為每種格式提供了承載範例。

### JSON format (JSON 格式)
<a name="services-consume-kafka-events-payload-json"></a>

 若選擇 `JSON` 作為 `EventRecordFormat`，Lambda 會驗證並反序列化您在 `SchemaValidationConfigs` 欄位中選取的訊息屬性 (`key` 及/或 `value` 屬性)。Lambda 會將這些選定的屬性，以其標準 JSON 表述的 Base64 編碼字串形式，傳遞至您的函式中。

**注意**  
 當 Avro 進行反序列化時，會轉換為標準 JSON 格式，也意味著無法直接轉換回 Avro 物件。如需轉換為 Avro 物件，請改用 SOURCE 格式。  
 在 Protobuf 反序列化過程中，產生 JSON 的欄位名稱與結構描述中定義的欄位名稱相符，而非如 Protobuf 常規作法般為駝峰式大小寫。在建立篩選模式時，請記住這一點。

 下列承載範例假設您選擇 `JSON` 作為 `EventRecordFormat`，同時選擇 `key` 與 `value` 屬性作為 `SchemaValidationConfigs`：

```
{
   "eventSource":"aws:kafka",
   "eventSourceArn":"arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111-1",
   "bootstrapServers":"b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
   "records":{
      "mytopic-0":[
         {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "key":"abcDEFghiJKLmnoPQRstuVWXyz1234==", //Base64 encoded string of JSON
            "keySchemaMetadata": {
                "dataFormat": "AVRO",
                "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
            },
            "value":"abcDEFghiJKLmnoPQRstuVWXyz1234", //Base64 encoded string of JSON
            "valueSchemaMetadata": {
                "dataFormat": "AVRO",
                "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
            },
            "headers":[
               {
                  "headerKey":[
                     104,
                     101,
                     97,
                     100,
                     101,
                     114,
                     86,
                     97,
                     108,
                     117,
                     101
                  ]
               }
            ]
         }
      ]
   }
}
```

 在此範例中：
+ `key` 與 `value` 經反序列化後，皆以其 JSON 表述的 Base64 編碼字串形式呈現。
+ Lambda 會包含 `keySchemaMetadata` 與 `valueSchemaMetadata` 中兩種屬性的結構描述中繼資料。
+ 函式可以解碼 `key` 和 `value` 字串，以存取反序列化後的 JSON 資料。

 對於非強型別語言，例如 Python 或 Node.js，建議採用 JSON 格式。這些語言原生支援將 JSON 轉換為物件。

### 來源格式
<a name="services-consume-kafka-events-payload-source"></a>

 如果您選擇 `SOURCE` 作為 `EventRecordFormat`，Lambda 仍然會根據結構描述登錄檔驗證記錄，但會將原始二進位資料傳送至函式，而不進行反序列化。此二進位資料會以原始位元組資料的 Base64 編碼字串形式傳送，並移除生產者附加的中繼資料。因此，您可在函式程式碼中，將原始二進位資料直接轉換為 Avro 與 Protobuf 物件。我們建議將 Powertools 用於 AWS Lambda，這會還原序列化原始二進位資料，並直接為您提供 Avro 和 Protobuf 物件。

 例如，若設定 Lambda 來驗證 `key` 與 `value` 屬性，但採用 `SOURCE` 格式，函式會收到如下承載：

```
{
    "eventSource": "aws:kafka",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111-1",
    "bootstrapServers": "b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
    "records": {
        "mytopic-0": [
            {
                "topic": "mytopic",
                "partition": 0,
                "offset": 15,
                "timestamp": 1545084650987,
                "timestampType": "CREATE_TIME",
                "key": "abcDEFghiJKLmnoPQRstuVWXyz1234==", // Base64 encoded string of Original byte data, producer-appended metadata removed
                "keySchemaMetadata": {
                    "dataFormat": "AVRO",
                    "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
                },
                "value": "abcDEFghiJKLmnoPQRstuVWXyz1234==", // Base64 encoded string of Original byte data, producer-appended metadata removed
                "valueSchemaMetadata": {
                    "dataFormat": "AVRO",
                    "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
                },
                "headers": [
                    {
                        "headerKey": [
                            104,
                            101,
                            97,
                            100,
                            101,
                            114,
                            86,
                            97,
                            108,
                            117,
                            101
                        ]
                    }
                ]
            }
        ]
    }
}
```

 在此範例中：
+ `key` 和 `value` 都包含原始二進位資料作為 Base64 編碼字串。
+ 函式需要使用適當的程式庫來處理反序列化。

 若您使用 Avro 產生的物件或 Protobuf 產生的物件 (特別是在 Java 函式中)，則建議將 `EventRecordFormat` 設定為 `SOURCE`。這是因為 Java 屬於強型別語言，需針對 Avro 與 Protobuf 格式使用特定的反序列化。在函式程式碼中，您可以使用偏好的 Avro 或 Protobuf 程式庫將資料反序列化。

## 在 Lambda 函式中處理反序列化資料
<a name="services-consume-kafka-events-payload-examples"></a>

Powertools for AWS Lambda 可協助您根據您使用的格式，將函數程式碼中的 Kafka 記錄還原序列化。此公用程式透過處理資料轉換並提供即用型物件，簡化了 Kafka 記錄的處理流程。

 若要在函數 AWS Lambda 中使用 Powertools for ，您需要在建置 Lambda 函數時新增 Powertools AWS Lambda 做為 layer 或包含它做為相依性。如需設定說明和詳細資訊，請參閱 Powertools for AWS Lambda documentation for your preferred language：
+ [Powertools for AWS Lambda (Java)](https://docs.powertools.aws.dev/lambda/java/latest/utilities/kafka/)
+ [Powertools for AWS Lambda (Python)](https://docs.powertools.aws.dev/lambda/python/latest/utilities/kafka/)
+ [Powertools for AWS Lambda (TypeScript)](https://docs.powertools.aws.dev/lambda/typescript/latest/features/kafka/)
+ [Powertools for AWS Lambda (.NET)](https://docs.powertools.aws.dev/lambda/dotnet/utilities/kafka/)

**注意**  
使用結構描述登錄檔整合時，可選擇 `SOURCE` 或 `JSON` 格式。每個選項都支援不同的序列化格式，如下所示：  


| 格式 | 支援 | 
| --- | --- | 
|  SOURCE  |  Avro 與 Protobuf (透過 Lambda 結構描述登錄檔整合)  | 
|  JSON  |  JSON 資料  | 

 使用 `SOURCE`或 `JSON` 格式時，您可以使用 Powertools for AWS 協助還原序列化函數程式碼中的資料。以下是如何處理不同資料格式的範例：

------
#### [ AVRO ]

Java 範例：

```
package org.demo.kafka;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.demo.kafka.avro.AvroProduct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.lambda.powertools.kafka.Deserialization;
import software.amazon.lambda.powertools.kafka.DeserializationType;
import software.amazon.lambda.powertools.logging.Logging;

public class AvroDeserializationFunction implements RequestHandler<ConsumerRecords<String, AvroProduct>, String> {

    private static final Logger LOGGER = LoggerFactory.getLogger(AvroDeserializationFunction.class);

    @Override
    @Logging
    @Deserialization(type = DeserializationType.KAFKA_AVRO)
    public String handleRequest(ConsumerRecords<String, AvroProduct> records, Context context) {
        for (ConsumerRecord<String, AvroProduct> consumerRecord : records) {
            LOGGER.info("ConsumerRecord: {}", consumerRecord);

            AvroProduct product = consumerRecord.value();
            LOGGER.info("AvroProduct: {}", product);

            String key = consumerRecord.key();
            LOGGER.info("Key: {}", key);
        }

        return "OK";
    }

}
```

Python 範例：

```
from aws_lambda_powertools.utilities.kafka_consumer.kafka_consumer import kafka_consumer
from aws_lambda_powertools.utilities.kafka_consumer.schema_config import SchemaConfig
from aws_lambda_powertools.utilities.kafka_consumer.consumer_records import ConsumerRecords

from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools import Logger

logger = Logger(service="kafkaConsumerPowertools")

value_schema_str = open("customer_profile.avsc", "r").read()

schema_config = SchemaConfig(
value_schema_type="AVRO",
value_schema=value_schema_str)

@kafka_consumer(schema_config=schema_config)
def lambda_handler(event: ConsumerRecords, context:LambdaContext):

  for record in event.records:
      value = record.value
      logger.info(f"Received value: {value}")
```

TypeScript 範例：

```
import { kafkaConsumer } from '@aws-lambda-powertools/kafka';

import type { ConsumerRecords } from '@aws-lambda-powertools/kafka/types';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda';

const logger = new Logger();

type Value = {
    id: number;
    name: string;
    price: number;
};

const schema = '{   
    "type": "record",   
    "name": "Product",   
    "fields": [     
        { "name": "id", "type": "int" },     
        { "name": "name", "type": "string" },     
        { "name": "price", "type": "double" }   
    ] 
}';

export const handler = kafkaConsumer<string, Value>(
    (event: ConsumerRecords<string, Value>, _context: Context) => {
        for (const record of event.records) {
            logger.info(Processing record with key: ${record.key});
            logger.info(Record value: ${JSON.stringify(record.value)});
            // You can add more processing logic here
        }
    },
    {
        value: {
            type: 'avro',
            schema: schema,
        },
    }
);
```

.NET 範例：

```
using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Kafka;
using AWS.Lambda.Powertools.Kafka.Avro;
using AWS.Lambda.Powertools.Logging;
using Com.Example;

// Assembly attribute to enable the Lambda function's Kafka event to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(PowertoolsKafkaAvroSerializer))]

namespace ProtoBufClassLibrary;

public class Function
{
    public string FunctionHandler(ConsumerRecords<string, CustomerProfile> records, ILambdaContext context)
    {
        foreach (var record in records)
        {
            Logger.LogInformation("Processing messagem from topic: {topic}", record.Topic);
            Logger.LogInformation("Partition: {partition}, Offset: {offset}", record.Partition, record.Offset);
            Logger.LogInformation("Produced at: {timestamp}", record.Timestamp);
            
            foreach (var header in record.Headers.DecodedValues())
            {
                Logger.LogInformation($"{header.Key}: {header.Value}");
            }
            
            Logger.LogInformation("Processing order for: {fullName}", record.Value.FullName);
        }
    
        return "Processed " + records.Count() + " records";
    }
}
```

------
#### [ PROTOBUF ]

Java 範例：

```
package org.demo.kafka;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.demo.kafka.protobuf.ProtobufProduct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.lambda.powertools.kafka.Deserialization;
import software.amazon.lambda.powertools.kafka.DeserializationType;
import software.amazon.lambda.powertools.logging.Logging;

public class ProtobufDeserializationFunction
        implements RequestHandler<ConsumerRecords<String, ProtobufProduct>, String> {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProtobufDeserializationFunction.class);

    @Override
    @Logging
    @Deserialization(type = DeserializationType.KAFKA_PROTOBUF)
    public String handleRequest(ConsumerRecords<String, ProtobufProduct> records, Context context) {
        for (ConsumerRecord<String, ProtobufProduct> consumerRecord : records) {
            LOGGER.info("ConsumerRecord: {}", consumerRecord);

            ProtobufProduct product = consumerRecord.value();
            LOGGER.info("ProtobufProduct: {}", product);

            String key = consumerRecord.key();
            LOGGER.info("Key: {}", key);
        }

        return "OK";
    }

}
```

Python 範例：

```
from aws_lambda_powertools.utilities.kafka_consumer.kafka_consumer import kafka_consumer

from aws_lambda_powertools.utilities.kafka_consumer.schema_config import SchemaConfig
from aws_lambda_powertools.utilities.kafka_consumer.consumer_records import ConsumerRecords

from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools import Logger

from user_pb2 import User # protobuf generated class

logger = Logger(service="kafkaConsumerPowertools")

schema_config = SchemaConfig(
value_schema_type="PROTOBUF",
value_schema=User)

@kafka_consumer(schema_config=schema_config)
def lambda_handler(event: ConsumerRecords, context:LambdaContext):

  for record in event.records:
      value = record.value
      logger.info(f"Received value: {value}")
```

TypeScript 範例：

```
import { kafkaConsumer } from '@aws-lambda-powertools/kafka';
import type { ConsumerRecords } from '@aws-lambda-powertools/kafka/types';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda';
import { Product } from './product.generated.js';

const logger = new Logger();

type Value = {
    id: number;
    name: string;
    price: number;
};

export const handler = kafkaConsumer<string, Value>(
    (event: ConsumerRecords<string, Value>, _context: Context) => {
        for (const record of event.records) {
            logger.info(Processing record with key: ${record.key});
            logger.info(Record value: ${JSON.stringify(record.value)});
        }
    },
    {
        value: {
            type: 'protobuf',
            schema: Product,
        },
    }
);
```

.NET 範例：

```
using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Kafka;
using AWS.Lambda.Powertools.Kafka.Protobuf;
using AWS.Lambda.Powertools.Logging;
using Com.Example;

// Assembly attribute to enable the Lambda function's Kafka event to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(PowertoolsKafkaProtobufSerializer))]

namespace ProtoBufClassLibrary;

public class Function
{
    public string FunctionHandler(ConsumerRecords<string, CustomerProfile> records, ILambdaContext context)
    {
        foreach (var record in records)
        {
            Logger.LogInformation("Processing messagem from topic: {topic}", record.Topic);
            Logger.LogInformation("Partition: {partition}, Offset: {offset}", record.Partition, record.Offset);
            Logger.LogInformation("Produced at: {timestamp}", record.Timestamp);
            
            foreach (var header in record.Headers.DecodedValues())
            {
                Logger.LogInformation($"{header.Key}: {header.Value}");
            }
            
            Logger.LogInformation("Processing order for: {fullName}", record.Value.FullName);
        }
    
        return "Processed " + records.Count() + " records";
    }
}
```

------
#### [ JSON ]

Java 範例：

```
package org.demo.kafka;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.lambda.powertools.kafka.Deserialization;
import software.amazon.lambda.powertools.kafka.DeserializationType;
import software.amazon.lambda.powertools.logging.Logging;

public class JsonDeserializationFunction implements RequestHandler<ConsumerRecords<String, Product>, String> {

    private static final Logger LOGGER = LoggerFactory.getLogger(JsonDeserializationFunction.class);

    @Override
    @Logging
    @Deserialization(type = DeserializationType.KAFKA_JSON)
    public String handleRequest(ConsumerRecords<String, Product> consumerRecords, Context context) {
        for (ConsumerRecord<String, Product> consumerRecord : consumerRecords) {
            LOGGER.info("ConsumerRecord: {}", consumerRecord);

            Product product = consumerRecord.value();
            LOGGER.info("Product: {}", product);

            String key = consumerRecord.key();
            LOGGER.info("Key: {}", key);
        }

        return "OK";
    }
}
```

Python 範例：

```
from aws_lambda_powertools.utilities.kafka_consumer.kafka_consumer import kafka_consumer

from aws_lambda_powertools.utilities.kafka_consumer.schema_config import SchemaConfig
from aws_lambda_powertools.utilities.kafka_consumer.consumer_records import ConsumerRecords

from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools import Logger

logger = Logger(service="kafkaConsumerPowertools")

schema_config = SchemaConfig(value_schema_type="JSON")

@kafka_consumer(schema_config=schema_config)
def lambda_handler(event: ConsumerRecords, context:LambdaContext):

  for record in event.records:
      value = record.value
      logger.info(f"Received value: {value}")
```

TypeScript 範例：

```
import { kafkaConsumer } from '@aws-lambda-powertools/kafka';
import type { ConsumerRecords } from '@aws-lambda-powertools/kafka/types';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda';

const logger = new Logger();

type Value = {
    id: number;
    name: string;
    price: number;
};

export const handler = kafkaConsumer<string, Value>(
    (event: ConsumerRecords<string, Value>, _context: Context) => {
        for (const record of event.records) {
            logger.info(Processing record with key: ${record.key});
            logger.info(Record value: ${JSON.stringify(record.value)});
            // You can add more processing logic here
        }
    },
    {
        value: {
            type: 'json',
        },
    }
);
```

.NET 範例：

```
using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Kafka;
using AWS.Lambda.Powertools.Kafka.Json;
using AWS.Lambda.Powertools.Logging;
using Com.Example;

// Assembly attribute to enable the Lambda function's Kafka event to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(PowertoolsKafkaJsonSerializer))]

namespace JsonClassLibrary;

public class Function
{
    public string FunctionHandler(ConsumerRecords<string, CustomerProfile> records, ILambdaContext context)
    {
        foreach (var record in records)
        {
            Logger.LogInformation("Processing messagem from topic: {topic}", record.Topic);
            Logger.LogInformation("Partition: {partition}, Offset: {offset}", record.Partition, record.Offset);
            Logger.LogInformation("Produced at: {timestamp}", record.Timestamp);
            
            foreach (var header in record.Headers.DecodedValues())
            {
                Logger.LogInformation($"{header.Key}: {header.Value}");
            }
            
            Logger.LogInformation("Processing order for: {fullName}", record.Value.FullName);
        }
    
        return "Processed " + records.Count() + " records";
    }
}
```

------

## 結構描述登錄檔的身分驗證方法
<a name="services-consume-kafka-events-auth"></a>

 若要使用結構描述登錄檔，Lambda 需要能夠對其進行安全存取。如果您使用 AWS Glue 結構描述登錄檔，Lambda 依賴 IAM 身分驗證。這表示函數的[執行角色](lambda-intro-execution-role.md)必須具有下列許可，才能存取 AWS Glue 登錄檔：
+ *AWS Glue Web API Reference* 中的 [GetRegistry](https://docs.aws.amazon.com/glue/latest/webapi/API_GetRegistry.html)
+ *AWS Glue Web API Reference* 中的 [GetSchemaVersion](https://docs.aws.amazon.com/glue/latest/webapi/API_GetSchemaVersion.html)

必要 IAM 政策範例：

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "glue:GetRegistry",
                "glue:GetSchemaVersion"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

------

**注意**  
 對於 AWS Glue 結構描述登錄檔，如果您`AccessConfigs`提供 AWS Glue 登錄檔，Lambda 將傳回驗證例外狀況。

若您使用 Confluent 結構描述登錄檔，可為 [KafkaSchemaRegistryAccessConfig](https://docs.aws.amazon.com/lambda/latest/api/API_KafkaSchemaRegistryAccessConfig) 物件的 `Type` 參數選擇以下三種身分驗證方法中一種：
+ **BASIC\$1AUTH**：Lambda 會透過使用者名稱與密碼，或 API 金鑰與 API 秘密身分驗證方式存取登錄庫。如果選擇此選項，請在 URI 欄位中提供包含憑證的 Secrets Manager ARN。
+ **CLIENT\$1CERTIFICATE\$1TLS\$1AUTH**：Lambda 透過用戶端憑證進行雙向 TLS 身分驗證。若要使用此選項，Lambda 需要同時存取憑證和私有金鑰。在 URI 欄位中提供包含這些憑證的 Secrets Manager ARN。
+ **NO\$1AUTH**：公有 CA 憑證必須由位於 Lambda 信任存放區中的憑證認證機構 (CA) 簽署。對於私有 CA/自我簽署憑證，您需要設定伺服器根 CA 憑證。若要使用此選項，請省略 `AccessConfigs` 參數。

 此外，如果 Lambda 需要存取私有 CA 憑證來驗證結構描述登錄檔的 TLS 憑證，請選擇 `SERVER_ROOT_CA_CERT` 作為 `Type`，並在 URI 欄位中提供憑證對應的 Secrets Manager ARN。

**注意**  
 若要在主控台中設定 `SERVER_ROOT_CA_CERT` 選項，需要在**加密**欄位中提供包含該憑證的秘密 ARN。

 結構描述登錄檔的驗證組態，需獨立於 Kafka 叢集的任何驗證設定。即使兩者採用相似的驗證方法，仍須分別進行設定。

## 結構描述登錄檔問題的錯誤處理與疑難排解
<a name="services-consume-kafka-events-troubleshooting"></a>

在將結構描述登錄檔與 Amazon MSK 事件來源搭配使用時，可能會遭遇各種錯誤。本節提供了常見問題及其解決方法的指導。

### 組態錯誤
<a name="consume-kafka-events-troubleshooting-configuration-errors"></a>

這些錯誤通常發生在設定結構描述登錄檔組態時。

需要佈建模式  
**錯誤訊息**：`SchemaRegistryConfig is only available for Provisioned Mode. To configure Schema Registry, please enable Provisioned Mode by specifying MinimumPollers in ProvisionedPollerConfig.`  
**解決方案：**透過在 `ProvisionedPollerConfig` 中設定 `MinimumPollers` 參數，為事件來源映射啟用佈建模式。

無效的結構描述登錄檔 URL  
**錯誤訊息**：`Malformed SchemaRegistryURI provided. Please provide a valid URI or ARN. For example, https://schema-registry.example.com:8081 or arn:aws:glue:us-east-1:123456789012:registry/ExampleRegistry.`  
**解決方案：**為 Confluent 結構描述登錄檔提供有效的 HTTPS URL，或為 AWS Glue 結構描述登錄檔提供有效的 ARN。

無效或缺少事件記錄格式  
**錯誤訊息**：`EventRecordFormat is a required field for SchemaRegistryConfig. Please provide one of supported format types: SOURCE, JSON.`  
**解決方案：**在結構描述登錄檔組態中，將 SOURCE 或 JSON 指定為 EventRecordFormat。

重複驗證屬性  
**錯誤訊息**：`Duplicate KEY/VALUE Attribute in SchemaValidationConfigs. SchemaValidationConfigs must contain at most one KEY/VALUE Attribute.`  
**解決方案：**從 SchemaValidationConfigs 中移除重複的 KEY 或 VALUE 屬性。每種屬性類型只能出現一次。

缺少驗證組態  
**錯誤訊息**：`SchemaValidationConfigs is a required field for SchemaRegistryConfig.`  
**解決方案：**將 SchemaValidationConfigs 新增至組態，指定至少一個驗證屬性 (KEY 或 VALUE)。

### 存取與許可錯誤
<a name="consume-kafka-events-troubleshooting-access-errors"></a>

當 Lambda 陰許可或身分驗證問題而無法存取結構描述登錄檔時，就會發生這些錯誤。

AWS Glue 結構描述登錄檔存取遭拒  
**錯誤訊息**：`Cannot access Glue Schema with provided role. Please ensure the provided role can perform the GetRegistry and GetSchemaVersion Actions on your schema.`  
**解決方案：**將必要許可 (`glue:GetRegistry` 與 `glue:GetSchemaVersion`) 新增至函式的執行角色。

Confluent 結構描述登錄檔存取遭拒  
**錯誤訊息**：`Cannot access Confluent Schema with the provided access configuration.`  
**解決方案：**確認身分驗證憑證 (儲存於 Secrets Manager 中) 是否正確，以及是否具有存取結構描述登錄檔的必要許可。

跨帳戶 AWS Glue 結構描述登錄檔  
**錯誤訊息**：`Cross-account Glue Schema Registry ARN not supported.`  
**解決方案：**使用與 Lambda 函數位於相同 AWS 帳戶的 AWS Glue 結構描述登錄檔。

跨區域 AWS Glue 結構描述登錄檔  
**錯誤訊息**：`Cross-region Glue Schema Registry ARN not supported.`  
**解決方案：**使用與 Lambda 函數位於相同區域的 AWS Glue 結構描述登錄檔。

秘密存取問題  
**錯誤訊息**：`Lambda received InvalidRequestException from Secrets Manager.`  
**解決方法：**確認函數的執行角色具有存取秘密的許可，而且如果從其他帳戶存取 ，則不會使用預設 AWS KMS 金鑰加密秘密。

### 連線錯誤
<a name="consume-kafka-events-troubleshooting-connection-errors"></a>

當 Lambda 無法與結構描述登錄檔建立連線時，就會發生這些錯誤。

VPC 連線問題  
**錯誤訊息**：`Cannot connect to your Schema Registry. Your Kafka cluster's VPC must be able to connect to the schema registry. You can provide access by configuring AWS PrivateLink or a NAT Gateway or VPC Peering between Kafka Cluster VPC and the schema registry VPC.`  
**解決方案：**設定您的 VPC 聯網，以允許使用 AWS PrivateLink NAT Gateway 或 VPC 對等互連連線至結構描述登錄檔。

TLS 交握失敗  
**錯誤訊息**：`Unable to establish TLS handshake with the schema registry. Please provide correct CA-certificate or client certificate using Secrets Manager to access your schema registry.`  
**解決方案：**確認 CA 憑證與用戶端憑證 (適用於 mTLS) 是否正確，是否在 Secrets Manager 中正確設定。

限流  
**錯誤訊息**：`Receiving throttling errors when accessing the schema registry. Please increase API TPS limits for your schema registry.`  
**解決方案：**提高結構描述登錄檔的 API 速率限制，或降低應用程式的請求速率。

自我管理結構描述登錄檔錯誤  
**錯誤訊息**：`Lambda received an internal server an unexpected error from the provided self-managed schema registry.`  
**解決方案：**檢查自我管理結構描述登錄檔伺服器的運作狀態與組態。

# Kafka 事件來源的低延遲處理
<a name="with-kafka-low-latency"></a>

AWS Lambda 對於需要低於 100 毫秒一致end-to-end延遲的應用程式，原生支援低延遲事件處理。本頁提供了啟用低延遲工作流程的組態詳細資訊和建議。

## 啟用低延遲處理
<a name="enable-low-latency"></a>

為實現 Kafka 事件來源映射的低延遲處理，需進行以下基礎組態設定：
+ 啟用佈建模式。如需詳細資訊，請參閱[佈建模式](kafka-scaling-modes.md#kafka-provisioned-mode)。
+ 將事件來源映射的 `MaximumBatchingWindowInSeconds` 參數設定為 0。如需詳細資訊，請參閱[批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)。

## 微調低延遲 Kafka ESM
<a name="recommendations-low-latency"></a>

參考下列建議，最佳化 Kafka 事件來源映射來達成低延遲目標：

### 佈建模式組態
<a name="recommendations-pollers"></a>

在 Kafka 事件來源映射的佈建模式下，Lambda 允許透過設定稱為**事件輪詢器**的資源數量下限與上限，實現對事件來源映射輸送量的微調。事件輪詢器 (或**輪詢器**) 代表在佈建模式下支援事件來源映射的運算資源，並且會配置高達 5 MB/s 的輸送量。每個事件輪詢器最多支援 5 個並行 Lambda 調用。

若要判斷應用程式的最佳輪詢器組態，建議考量尖峰擷取速率與處理需求。我們來看一個簡化範例：

在批次大小為 20 筆記錄且目標函式平均持續時間為 50 毫秒的情況下，每個輪詢器在 5 MB/s 的限制下每秒可處理 2,000 筆記錄。其計算方式為：(20 筆記錄 × 1000 毫秒/50 毫秒) × 5 個並行 Lambda 調用。因此，如果所需的尖峰擷取速率為每秒 20,000 筆記錄，將至少需要 10 個事件輪詢器。

**注意**  
建議將額外的事件輪詢器佈建為緩衝區，避免持續以容量上限運作。

佈建模式會在設定的**事件輪詢器**下限與上限範圍內，根據流量模式自動擴展事件輪詢器。這可能會觸發重新平衡，進而引入額外的延遲。將**事件輪詢器**下限與上限設定為相同的值，即可停用自動擴展。

### 其他考量
<a name="additional-considerations-low-latency"></a>

其他考量事項包括：
+ 調用 Lambda 目標函式時產生的冷啟動可能會增加端對端延遲。若要降低此風險，建議在事件來源映射的目標函式上啟用[佈建並行](provisioned-concurrency.md)或 [SnapStart](snapstart.md)。此外，最佳化函式的記憶體配置，確保一致且最佳的執行效能。
+ 當 `MaximumBatchingWindowInSeconds` 設定為 0 時，Lambda 會立即處理任何可用的記錄，而不會等待累積到完整的批次大小。例如，若批次大小設定為 1,000 筆記錄，但只有 100 筆記錄可用，Lambda 會立即處理這 100 筆記錄，而不是等待累積到完整的 1,000 筆記錄。

**重要**  
低延遲處理的最佳組態會因特定工作負載而存在顯著差異。強烈建議使用實際工作負載測試不同的組態，判斷適合使用案例的最佳設定。

# 設定 Kafka 事件來源的錯誤處理控制項
<a name="kafka-retry-configurations"></a>

您可以設定 Lambda 如何處理 Kafka 事件來源映射的錯誤和重試。這些組態可協助您控制 Lambda 如何處理失敗的記錄和管理重試行為。

## 可用的重試組態
<a name="kafka-retry-options"></a>

下列重試組態適用於 Amazon MSK 和自我管理 Kafka 事件來源：
+ **重試次數上限** – 當函數傳回錯誤時，Lambda 重試次數上限。這不會計入初始調用嘗試。預設值為 -1 （無限）。當您同時設定無限次重試和[失敗時的目的地](kafka-on-failure-destination.md)時，Lambda 會自動套用最多 10 次重試嘗試。
+ **記錄存留期上限** – Lambda 傳送給函數的記錄存留期上限。預設值為 -1 （無限）。
+ **錯誤時分割批次** – 當函數傳回錯誤時，請將批次分割為兩個較小的批次，並個別重試。這有助於隔離有問題的記錄。
+ **部分批次回應** – 允許函數傳回批次中哪些記錄處理失敗的資訊，因此 Lambda 只能重試失敗的記錄。

## 設定錯誤處理控制 （主控台）
<a name="kafka-retry-console"></a>

您可以在 Lambda 主控台中建立或更新 Kafka 事件來源映射時設定重試行為。

**設定 Kafka 事件來源的重試行為 （主控台）**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您的函數名稱。

1. 執行以下任意一項：
   + 若要新增新的 Kafka 觸發條件，請在**函數概觀**下，選擇**新增觸發條件**。
   + 若要修改現有的 Kafka 觸發條件，請選擇觸發條件，然後選擇**編輯**。

1. 在**事件輪詢器組態**下，選取佈建模式以設定錯誤處理控制項：

   1. 對於**重試嘗試**，輸入重試嘗試次數上限 (0-10000，或無限輸入 -1)。

   1. 針對**記錄存留期上限**，以秒為單位輸入存留期上限 (60-604800，無限輸入 -1)。

   1. 若要在發生錯誤時啟用批次分割，請選取**錯誤時分割批次**。

   1. 若要啟用部分批次回應，請選取 **ReportBatchItemFailures**。

1. 選擇**新增**或**儲存**。

## 設定重試行為 (AWS CLI)
<a name="kafka-retry-cli"></a>

使用下列 AWS CLI 命令來設定 Kafka 事件來源映射的重試行為。

### 使用重試組態建立事件來源映射
<a name="kafka-retry-cli-create"></a>

下列範例會使用錯誤處理控制項建立自我管理的 Kafka 事件來源映射：

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics my-kafka-topic \
  --source-access-configuration Type=SASL_SCRAM_512_AUTH,URI=arn:aws:secretsmanager:us-east-1:111122223333:secret:MyBrokerSecretName \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc.xyz.com:9092"]}}' \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=1 \
  --maximum-retry-attempts 3 \
  --maximum-record-age-in-seconds 3600 \
  --bisect-batch-on-function-error \
  --function-response-types "ReportBatchItemFailures"
```

對於 Amazon MSK 事件來源：

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSMSKKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function \
  --source-access-configurations '[{"Type": "SASL_SCRAM_512_AUTH","URI": "arn:aws:secretsmanager:us-east-1:111122223333:secret:my-secret"}]' \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=1 \
  --maximum-retry-attempts 3 \
  --maximum-record-age-in-seconds 3600 \
  --bisect-batch-on-function-error \
  --function-response-types "ReportBatchItemFailures"
```

### 更新重試組態
<a name="kafka-retry-cli-update"></a>

使用 `update-event-source-mapping`命令來修改現有事件來源映射的重試組態：

```
aws lambda update-event-source-mapping \
  --uuid 12345678-1234-1234-1234-123456789012 \
  --maximum-retry-attempts 5 \
  --maximum-record-age-in-seconds 7200 \
  --bisect-batch-on-function-error \
  --function-response-types "ReportBatchItemFailures"
```

## PartialBatchResponse
<a name="kafka-partial-batch-response"></a>

部分批次回應也稱為 ReportBatchItemFailures，是 Lambda 與 Kafka 來源整合時處理錯誤的重要功能。如果沒有此功能，當批次中其中一個項目發生錯誤時，會導致重新處理該批次中的所有訊息。啟用並實作部分批次回應後，處理常式只會傳回失敗訊息的識別符，讓 Lambda 只重試這些特定項目。這可讓您更好地控制包含失敗訊息的批次處理方式。

若要報告批次錯誤，您將使用此 JSON 結構描述：

```
{
  "batchItemFailures": [
    {
      "itemIdentifier": {
        "partition": "topic-partition_number",
        "offset": 100
      }
    },
    ...
  ]
}
```

**重要**  
如果您傳回空的有效 JSON 或 null，事件來源映射會將批次視為已成功處理。傳回的任何無效 topic-partition\$1number 或位移若不存在於調用事件中，將視為失敗，並重試整個批次。

下列程式碼範例示範如何為從 Kafka 來源接收事件的 Lambda 函數實作部分批次回應。此函數會在回應中報告批次項目失敗，指示 Lambda 稍後重試這些訊息。

以下是顯示此方法的 Python Lambda 處理常式實作：

```
import base64
from typing import Any, Dict, List

def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, List[Dict[str, Dict[str, Any]]]]:
    failures: List[Dict[str, Dict[str, Any]]] = []
    records_dict = event.get("records", {})
    
    for topic_partition, records_list in records_dict.items():
        for record in records_list:
            topic = record.get("topic")
            partition = record.get("partition")
            offset = record.get("offset")
            value_b64 = record.get("value")
            
            try:
                data = base64.b64decode(value_b64).decode("utf-8")
                process_message(data)
            except Exception as exc:
                print(f"Failed to process record topic={topic} partition={partition} offset={offset}: {exc}")
                item_identifier: Dict[str, Any] = {
                    "partition": f"{topic}-{partition}",
                    "offset": int(offset) if offset is not None else None,
                }
                failures.append({"itemIdentifier": item_identifier})
    
    return {"batchItemFailures": failures}

def process_message(data: str) -> None:
    # Your business logic for a single message
    pass
```

以下是 Node.js 版本：

```
const { Buffer } = require("buffer");

const handler = async (event) => {
  const failures = [];
  
  for (let topicPartition in event.records) {
    const records = event.records[topicPartition];
    
    for (const record of records) {
      const topic = record.topic;
      const partition = record.partition;
      const offset = record.offset;
      const valueBase64 = record.value;
      const data = Buffer.from(valueBase64, "base64").toString("utf8");
      
      try {
        await processMessage(data);
      } catch (error) {
        console.error("Failed to process record", { topic, partition, offset, error });
        const itemIdentifier = {
          "partition": `${topic}-${partition}`,
          "offset": Number(offset),
        };
        failures.push({ itemIdentifier });
      }
    }
  }
  
  return { batchItemFailures: failures };
};

async function processMessage(payload) {
  // Your business logic for a single message
}

module.exports = { handler };
```

# 擷取 Amazon MSK 和自我管理的 Apache Kafka 事件來源的捨棄批次
<a name="kafka-on-failure"></a>

若要保留失敗的事件來源映射調用記錄，請將目標地新增到函數的事件來源映射中。傳送至該目的地的每筆記錄都是包含失敗調用之中繼資料的 JSON 文件。對於 Amazon S3 目的地，Lambda 還會將整個調用記錄與中繼資料一起傳送。您可以設定任何 Amazon SNS 主題、Amazon SQS 佇列、Amazon S3 儲存貯體或 Kafka 做為目的地。

透過 Amazon S3 目的地，您可以使用 [Amazon S3 事件通知](https://docs.aws.amazon.com/)功能，在物件上傳至您的目的地 S3 儲存貯體時接收通知。您也可以設定 S3 事件通知來調用另一個 Lambda 函數，以對失敗的批次執行自動處理。

執行角色必須具有目的地的許可：
+ **對於 SQS 目的地：**[sqs：SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)
+ **對於 SNS 目的地：**[sns：Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html)
+ **對於 S3 目的地：**[s3：PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 和 [s3：ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/ListObjectsV2.html)
+ **對於 Kafka 目的地：**[kafka-cluster：WriteData](https://docs.aws.amazon.com/msk/latest/developerguide/kafka-actions.html)

您可以將 Kafka 主題設定為 Kafka 事件來源映射的失敗時目的地。當 Lambda 在耗盡重試嘗試後或記錄超過最長存留期後無法處理記錄時，Lambda 會將失敗的記錄傳送至指定的 Kafka 主題，以供稍後處理。請參閱[使用 Kafka 主題做為失敗時的目的地](kafka-on-failure-destination.md)。

必須在 Kafka 叢集 VPC 內為失敗時目的地服務部署 VPC 端點。

此外，如果您在目的地上設定 KMS 金鑰，則視目的地類型而定，Lambda 需要下列許可：
+ 如果您已針對 S3 目的地使用自己的 KMS 金鑰啟用加密，則需要 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)。如果 KMS 金鑰和 S3 儲存貯體目的地與 Lambda 函數和執行角色位於不同的帳戶中，請將 KMS 金鑰設定為信任執行角色以允許 kms:GenerateDataKey。
+ 如果您已針對 SQS 目的地使用自己的 KMS 金鑰啟用加密，則需要 [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) 和 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)。如果 KMS 金鑰和 SQS 佇列目的地與 Lambda 函數和執行角色位於不同的帳戶中，請將 KMS 金鑰設定為信任執行角色，以允許 kms:Decrypt、kms:GenerateDataKey、[kms:DescribeKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html) 以及 [kms:ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html)。
+ 如果您已針對 SNS 目的地使用自己的 KMS 金鑰啟用加密，則需要 [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) 和 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)。如果 KMS 金鑰和 SNS 主題目的地與 Lambda 函數和執行角色位於不同的帳戶中，請將 KMS 金鑰設定為信任執行角色，以允許 kms:Decrypt、kms:GenerateDataKey、[kms:DescribeKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html) 以及 [kms:ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html)。

## 設定 Kafka 事件來源映射的失敗時目的地
<a name="kafka-onfailure-destination"></a>

若要使用主控台設定失敗時的目的地，請依照下列步驟執行：

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇一個函數。

1. 在**函數概觀下**，選擇**新增目的地**。

1. 針對**來源**，請選擇**事件來源映射調用**。

1. 對於**事件來源映射**，請選擇針對此函數設定的事件來源。

1. 對於**條件**，選取**失敗時**。對於事件來源映射調用，這是唯一可接受的條件。

1. 對於**目標類型**，請選擇 Lambda 將調用記錄傳送至的目標類型。

1. 對於**目的地**，請選擇一個資源。

1. 選擇**儲存**。

您也可以使用 AWS CLI設定失敗時的目的地。例如，下列 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 命令會將具有 SQS 失敗時的目的地的事件來源映射新增至 `MyFunction`：

```
aws lambda create-event-source-mapping \
--function-name "MyFunction" \
--event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sqs:us-east-1:123456789012:dest-queue"}}'
```

下列 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 命令會將 S3 失敗時的目的地新增至與輸入 `uuid` 相關聯的事件來源：

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": "arn:aws:s3:::dest-bucket"}}'
```

若要移除目的地，請提供空白字串作為 `destination-config` 參數的引數：

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": ""}}'
```

### Amazon S3 目的地的安全最佳實務
<a name="kafka-s3-destination-security"></a>

刪除已設定為目的地的 S3 儲存貯體而不從函數的組態中移除目的地，可能會產生安全風險。如果其他使用者知道目的地儲存貯體的名稱，他們可以在其 AWS 帳戶中重新建立儲存貯體。失敗調用的記錄會被傳送到其儲存貯體，可能公開來自您函數的資料。

**警告**  
為了確保無法將來自函數的調用記錄傳送到另一個 中的 S3 儲存貯體 AWS 帳戶，請將條件新增至函數的執行角色，以限制您帳戶中儲存貯體的`s3:PutObject`許可。

下列範例顯示的 IAM 政策，將函數的 `s3:PutObject` 許可限制為帳戶中的儲存貯體。此政策也為 Lambda 提供了使用 S3 儲存貯體做為目的地所需的 `s3:ListBucket` 許可。

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "S3BucketResourceAccountWrite",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::*/*",
                "arn:aws:s3:::*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:ResourceAccount": "111122223333"
                }
            }
        }
    ]
}
```

若要使用 AWS 管理主控台 或 將許可政策新增至函數的執行角色 AWS CLI，請參閱下列程序中的指示：

------
#### [ Console ]

**若要將許可政策新增至函數的執行角色 (主控台)**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選取您要修改其執行角色的 Lambda 函數。

1. 在**組態**索引標籤中，選擇**許可**。

1. 在**執行角色**索引標籤中，選取函數的**角色名稱**，以開啟角色的 IAM 主控台頁面。

1. 透過下列步驟將許可政策新增至角色：

   1. 在**許可政策**窗格中，選擇**新增許可** ，然後選取**建立內嵌政策**。

   1. 在**政策編輯器**中，選取 **JSON**。

   1. 將您要新增的政策貼入編輯器 (取代現有的 JSON)，然後選擇**下一步**。

   1. 在**政策詳細資訊**下，輸入**政策名稱**。

   1. 選擇**建立政策**。

------
#### [ AWS CLI ]

**若要將許可政策新增至函數的執行角色 (CLI)**

1. 建立具有所需許可的 JSON 政策文件，並將其儲存在本機目錄中。

1. 使用 IAM `put-role-policy` CLI 命令，將許可新增至函數的執行角色。從您儲存 JSON 政策文件的目錄執行下列命令，並將角色名稱、政策名稱和政策文件取代為您自己的值。

   ```
   aws iam put-role-policy \
   --role-name my_lambda_role \
   --policy-name LambdaS3DestinationPolicy \
   --policy-document file://my_policy.json
   ```

------

### SNS 和 SQS 調用記錄範例
<a name="kafka-sns-sqs-destinations"></a>

下列範例顯示 Lambda 針對失敗的 Kafka 事件來源調用而傳送至 SNS 主題或 SQS 佇列目的地。`recordsInfo` 之下的每個索引鍵都包含 Kafka 主題和分割區，以連字號分隔。例如，對於金鑰 `"Topic-0"`，`Topic` 是 Kafka 主題，並且 `0` 是分區。對於每個主題和分區，您可以使用偏移和時間戳記資料來查找原始調用記錄。

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted" | "MaximumPayloadSizeExceeded",
        "approximateInvokeCount": 1
    },
    "responseContext": { // null if record is MaximumPayloadSizeExceeded
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KafkaBatchInfo": {
        "batchSize": 500,
        "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2",
        "bootstrapServers": "...",
        "payloadSize": 2039086, // In bytes
        "recordsInfo": {
            "Topic-0": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            },
            "Topic-1": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            }
        }
    }
}
```

### S3 目的地調用記錄範例
<a name="kafka-s3-destinations"></a>

對於 S3 的目的地，Lambda 會將整個調用記錄與中繼資料一起傳送至目的地。下列範例顯示 Lambda 針對失敗的 Kafka 事件來源調用而傳送至 S3 儲存貯體目的地。除了上一個 SQS 和 SNS 目的地範例中的所有欄位之外，此 `payload` 欄位還包含原始調用記錄做為逸出 JSON 字串。

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted" | "MaximumPayloadSizeExceeded",
        "approximateInvokeCount": 1
    },
    "responseContext": { // null if record is MaximumPayloadSizeExceeded
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KafkaBatchInfo": {
        "batchSize": 500,
        "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2",
        "bootstrapServers": "...",
        "payloadSize": 2039086, // In bytes
        "recordsInfo": {
            "Topic-0": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            },
            "Topic-1": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            }
        }
    },
    "payload": "<Whole Event>" // Only available in S3
}
```

**提示**  
建議您在目的地儲存貯體上啟用 S3 版本控制。

# 使用 Kafka 主題做為失敗時的目的地
<a name="kafka-on-failure-destination"></a>

您可以將 Kafka 主題設定為 Kafka 事件來源映射的失敗時目的地。當 Lambda 在耗盡重試嘗試後或記錄超過最長存留期後無法處理記錄時，Lambda 會將失敗的記錄傳送至指定的 Kafka 主題，以供稍後處理。當您同時設定[無限次重試](kafka-retry-configurations.md)和失敗時的目的地時，Lambda 會自動套用最多 10 次重試嘗試。

## Kafka 失敗時目的地的運作方式
<a name="kafka-ofd-overview"></a>

當您將 Kafka 主題設定為失敗時的目的地時，Lambda 會充當 Kafka 生產者，並將失敗的記錄寫入目的地主題。這會在 Kafka 基礎設施內建立無效字母主題 (DLT) 模式。
+ **相同的叢集需求** – 目的地主題必須與來源主題存在於相同的 Kafka 叢集中。
+ **實際記錄內容** – Kafka 目的地會收到實際失敗的記錄以及失敗中繼資料。
+ **防止遞迴** – Lambda 透過封鎖來源和目的地主題相同的組態來防止無限迴圈。

## 設定 Kafka 失敗時的目的地
<a name="kafka-ofd-configure"></a>

您可以在建立或更新 Kafka 事件來源映射時，將 Kafka 主題設定為失敗時的目的地。

### 設定 Kafka 目的地 （主控台）
<a name="kafka-ofd-console"></a>

**將 Kafka 主題設定為失敗時的目的地 （主控台）**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您的函數名稱。

1. 執行以下任意一項：
   + 若要新增新的 Kafka 觸發條件，請在**函數概觀**下，選擇**新增觸發條件**。
   + 若要修改現有的 Kafka 觸發條件，請選擇觸發條件，然後選擇**編輯**。

1. 在**其他設定**下，針對**失敗目的地**，選擇 **Kafka 主題**。

1. 針對**主題名稱**，輸入您要傳送失敗記錄的 Kafka 主題名稱。

1. 選擇**新增**或**儲存**。

### 設定 Kafka 目的地 (AWS CLI)
<a name="kafka-ofd-cli"></a>

使用 `kafka://`字首將 Kafka 主題指定為失敗時的目的地。

#### 使用 Kafka 目的地建立事件來源映射
<a name="kafka-ofd-cli-create"></a>

下列範例會建立 Amazon MSK 事件來源映射，並以 Kafka 主題做為失敗時的目的地：

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123 \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --destination-config '{"OnFailure":{"Destination":"kafka://failed-records-topic"}}'
```

對於自我管理的 Kafka，請使用相同的語法：

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc.xyz.com:9092"]}}' \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --destination-config '{"OnFailure":{"Destination":"kafka://failed-records-topic"}}'
```

#### 更新 Kafka 目的地
<a name="kafka-ofd-cli-update"></a>

使用 `update-event-source-mapping`命令來新增或修改 Kafka 目的地：

```
aws lambda update-event-source-mapping \
  --uuid 12345678-1234-1234-1234-123456789012 \
  --destination-config '{"OnFailure":{"Destination":"kafka://failed-records-topic"}}'
```

## Kafka 目的地的記錄格式
<a name="kafka-ofd-record-format"></a>

當 Lambda 將失敗的記錄傳送到 Kafka 主題時，每個訊息都會包含有關失敗和實際記錄內容的中繼資料。

### 失敗中繼資料
<a name="kafka-ofd-metadata"></a>

中繼資料包含記錄失敗原因的相關資訊，以及原始批次的詳細資訊：

```
{
  "requestContext": {
    "requestId": "e4b46cbf-b738-xmpl-8880-a18cdf61200e",
    "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:my-function:$LATEST",
    "condition": "RetriesExhausted",
    "approximateInvokeCount": 3
  },
  "responseContext": {
    "statusCode": 200,
    "executedVersion": "$LATEST",
    "functionError": "Unhandled"
  },
  "version": "1.0",
  "timestamp": "2019-11-14T18:16:05.568Z",
  "KafkaBatchInfo": {
    "batchSize": 1,
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123",
    "bootstrapServers": "b-1.mycluster.abc123.kafka.us-east-1.amazonaws.com:9098",
    "payloadSize": 1162,
    "recordInfo": {
      "offset": "49601189658422359378836298521827638475320189012309704722",
      "timestamp": "2019-11-14T18:16:04.835Z"
    }
  },
  "payload": {
    "bootstrapServers": "b-1.mycluster.abc123.kafka.us-east-1.amazonaws.com:9098",
    "eventSource": "aws:kafka",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123",
    "records": {
      "my-topic-0": [
        {
          "headers": [],
          "key": "dGVzdC1rZXk=",
          "offset": 100,
          "partition": 0,
          "timestamp": 1749116692330,
          "timestampType": "CREATE_TIME",
          "topic": "my-topic",
          "value": "dGVzdC12YWx1ZQ=="
        }
      ]
    }
  }
}
```

### 分割區索引鍵行為
<a name="kafka-ofd-partitioning"></a>

在產生目的地主題時，Lambda 會使用原始記錄中的相同分割區索引鍵。如果原始記錄沒有金鑰，Lambda 會在目的地主題中的所有可用分割區中使用 Kafka 的預設循環配置分割。

## 要求與限制
<a name="kafka-ofd-requirements"></a>
+ **需要佈建模式** – Kafka 故障時目的地僅適用於啟用佈建模式的事件來源映射。
+ **僅限相同叢集** – 目的地主題必須與來源主題存在於相同的 Kafka 叢集中。
+ **主題許可** – 您的事件來源映射必須具有目的地主題的寫入許可。範例：

  ```
  {
      "Version": "2012-10-17",		 	 	 
      "Statement": [
          {
              "Sid": "ClusterPermissions",
              "Effect": "Allow",
              "Action": [
                  "kafka-cluster:Connect",
                  "kafka-cluster:DescribeCluster",
                  "kafka-cluster:DescribeTopic",
                  "kafka-cluster:WriteData",
                  "kafka-cluster:ReadData"
              ],
              "Resource": [
                  "arn:aws:kafka:*:*:cluster/*"
              ]
          },
          {
              "Sid": "TopicPermissions",
              "Effect": "Allow",
              "Action": [
                  "kafka-cluster:DescribeTopic",
                  "kafka-cluster:WriteData",
                  "kafka-cluster:ReadData"
              ],
              "Resource": [
                  "arn:aws:kafka:*:*:topic/*/*"
              ]
          },
          {
              "Effect": "Allow",
              "Action": [
                  "kafka:DescribeCluster",
                  "kafka:GetBootstrapBrokers",
                  "kafka:Produce"
              ],
              "Resource": "arn:aws:kafka:*:*:cluster/*"
          },
          {
              "Effect": "Allow",
              "Action": [
                  "ec2:CreateNetworkInterface",
                  "ec2:DescribeNetworkInterfaces",
                  "ec2:DeleteNetworkInterface",
                  "ec2:DescribeSubnets",
                  "ec2:DescribeSecurityGroups"
              ],
              "Resource": "*"
          }
      ]
  }
  ```
+ **無遞迴** – 目的地主題名稱不能與來源主題名稱相同。

# Kafka 事件來源映射記錄
<a name="esm-logging"></a>

您可以設定 Kafka 事件來源映射的系統層級記錄，以啟用和篩選 Lambda 事件輪詢器傳送至 CloudWatch 的系統日誌。

此功能僅適用於 Kafka 事件來源映射，以及[佈建模式](https://docs.aws.amazon.com/lambda/latest/dg/kafka-scaling-modes.html#kafka-provisioned-mode)。

對於使用記錄組態的事件來源映射，您也可以立即從主控台 **Lambda** > **其他資源** > **事件來源映射**頁面的**監控**索引標籤中，從預先建置的日誌查詢檢查系統日誌。

## 記錄的運作方式
<a name="esm-logging-overview"></a>

當您在事件來源映射中設定日誌層級的記錄組態時，Lambda 事件輪詢器會傳送對應的日誌 （事件來源映射系統日誌）。

事件來源映射會與您的 Lambda 函數重複使用相同的[日誌目的地](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-logs.html#configuring-log-destinations)。請確定 Lambda 函數的執行角色具有必要的記錄許可。

事件來源映射將擁有自己的日誌串流，其中日期和事件來源映射 UUID 作為日誌串流名稱，例如 `2020/01/01/12345678-1234-1234-1234-12345678901`。

對於事件來源映射系統日誌，您可以選擇下列日誌層級。


| 日誌層級 | Usage | 
| --- | --- | 
| DEBUG (大多數詳細資訊) | 事件來源處理進度的詳細資訊 | 
| INFO | 有關事件來源映射正常操作的訊息 | 
| WARN (最少詳細資訊) | 有關可能導致意外行為之潛在警告和錯誤的訊息 | 

當您選取日誌層級時，Lambda 事件輪詢器會在該層級和更低層級傳送日誌。例如，如果您將事件來源映射系統日誌層級設定為 INFO，事件輪詢器不會在 DEBUG 層級傳送日誌輸出。

## 設定 記錄
<a name="esm-logging-configure"></a>

您可以在建立或更新 Kafka 事件來源映射時設定記錄設定。

### 設定記錄 （主控台）
<a name="esm-logging-console"></a>

**設定記錄 （主控台）**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您的函數名稱。

1. 執行以下任意一項：
   + 若要新增新的 Kafka 觸發條件，請在**函數概觀**下，選擇**新增觸發條件**。
   + 若要修改現有的 Kafka 觸發條件，請選擇觸發條件，然後選擇**編輯**。

1. 在**事件輪詢器組態**下，針對**佈建模式**，啟用**設定**核取方塊。此時會顯示**日誌層級**設定。

1.  按一下**日誌層級**下拉式清單，並選取事件來源映射的層級。

1. 選擇底部的**新增**或**儲存**，以建立或更新事件來源映射。

### 設定記錄 (AWS CLI)
<a name="esm-logging-cli"></a>

#### 使用 記錄建立事件來源映射
<a name="esm-logging-cli-create"></a>

下列範例會使用記錄組態建立 Amazon MSK 事件來源映射：

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123 \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --logging-config '{"SystemLogLevel":"DEBUG"}'
```

對於自我管理的 Kafka，請使用相同的語法：

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc.xyz.com:9092"]}}' \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --logging-config '{"SystemLogLevel":"DEBUG"}'
```

#### 更新記錄組態
<a name="esm-logging-cli-update"></a>

使用 `update-event-source-mapping`命令來新增或修改記錄組態：

```
aws lambda update-event-source-mapping \
  --uuid 12345678-1234-1234-1234-123456789012 \
  --logging-config '{"SystemLogLevel":"WARN"}'
```

## Kafka 事件來源映射系統日誌的記錄格式
<a name="esm-logging-record-format"></a>

當 Lambda 事件輪詢器傳送日誌時，每個日誌項目都包含一般事件來源映射中繼資料，以及事件特定內容。

### WARN 日誌記錄
<a name="esm-logging-warn-record"></a>

WARN 記錄包含來自事件輪詢器的錯誤或警告，並在事件發生時發出。例如：

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1546347650000,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:12345678-1234-1234-1234-123456789012",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/tests-cluster/87654321-4321-4321-4321-876543221-s1",
    "eventProcessorId": "12345678-1234-1234-1234-123456789012/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Timeout expired while fetching topic metadata",
        "errorCode": "org.apache.kafka.common.errors.TimeoutException"
    }
}
```

### INFO 日誌記錄
<a name="esm-logging-info-record"></a>

INFO 記錄包含每個事件輪詢器中的 Kafka 取用者用戶端組態，並在建立或變更取用者時發出。例如：

```
{
    "eventType": "POLLER_STATUS_EVENT",
    "timestamp": 1546347660000,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:12345678-1234-1234-1234-123456789012",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/tests-cluster/87654321-4321-4321-4321-876543221-s1",
    "eventProcessorId": "12345678-1234-1234-1234-123456789012/0",
    "logLevel": "INFO",
    "kafkaEventSourceConnection": {
        "brokerEndpoints": "boot-abcd1234.c2.kafka-serverless.us-east-1.amazonaws.com:9098",
        "consumerId": "12345678-1234-1234-1234-123456789012-0",
        "topics": [
            "test"
        ],
        "consumerGroupId": "12345678-1234-1234-1234-123456789012",
        "securityProtocol": "SASL_SSL",
        "saslMechanism": "AWS_MSK_IAM",
        "totalPartitionCount": 2,
        "assignedPartitionCount": 2,
        "partitionsAssignmentGeneration": 5,
        "assignedPartitions": [
            "test-0",
            "test-1"
        ],
        "networkConfig": {
            "ipAddresses": [
                "10.100.141.1"
            ],
            "subnetCidrBlock": "10.100.128.0/20",
            "securityGroups": [
                "sg-abcdefabcdefabcdef"
            ]
        }
    }
}
```

### DEBUG 日誌記錄
<a name="esm-logging-debug-record"></a>

DEBUG 日誌包含事件來源映射處理中的 Kafka 偏移相關資訊，並且每分鐘發出偏移資訊。例如：

```
{
    "eventType": "KAFKA_STATUS_EVENT",
    "timestamp": 1546347670000,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:12345678-1234-1234-1234-123456789012",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/tests-cluster/87654321-4321-4321-4321-876543221-s1",
    "eventProcessorId": "12345678-1234-1234-1234-123456789012/0",
    "logLevel": "DEBUG",
    "kafkaPartitionOffsets": {
        "partition": "test-1",
        "endOffset": 5004,
        "consumedOffset": 5003,
        "processedOffset": 5003,
        "committedOffset": 5004
    }
}
```

# 對 Kafka 事件來源映射錯誤進行疑難排解
<a name="with-kafka-troubleshoot"></a>

下列主題針對您在將 Amazon MSK 或自我管理的 Apache Kafka 與 Lambda 搭配使用時可能遇到的錯誤和問題，提供疑難排解建議。

如需更多疑難排解說明，請造訪 [AWS 知識中心](https://repost.aws/knowledge-center#AWS_Lambda)。

## 身分驗證和授權錯誤
<a name="kafka-permissions-errors"></a>

如果遺失了從 Kafka 叢集取用資料的任何必要許可，Lambda 會在 **LastProcessingResult** 下的事件來源映射中顯示下列其中一種錯誤訊息。

**Topics**
+ [

### 叢集無法授權 Lambda
](#kafka-authorize-errors)
+ [

### SASL 身分驗證失敗
](#kafka-sasl-errors)
+ [

### 伺服器無法驗證 Lambda
](#kafka-mtls-errors-server)
+ [

### Lambda 無法驗證伺服器
](#kafka-mtls-errors-lambda)
+ [

### 提供的憑證或私有金鑰無效
](#kafka-key-errors)

### 叢集無法授權 Lambda
<a name="kafka-authorize-errors"></a>

對於 SASL/SCRAM 或 mTLS，此錯誤表示提供的使用者不具備下列 Kafka 存取控制清單 (ACL) 的所有許可：
+ DescribeConfigs 叢集
+ 描述群組
+ 讀取群組
+ 描述主題
+ 讀取主題

當您建立具有必要的 `kafka-cluster` 許可之 Kafka ACL 時，請將主題和群組指定為資源。主題名稱必須與事件來源映射中的主題相符。群組名稱必須與事件來源映射的 UUID 相符。

將必要的許可新增至執行角色後，可能需要數分鐘變更才會生效。

以下是針對此問題啟用[記錄組態](esm-logging.md)後的範例 ESM 系統層級日誌：

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567890123,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE11111-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Not authorized to access topics: [my-topic]",
        "errorCode": "org.apache.kafka.common.errors.TopicAuthorizationException"
    }
}
```

### SASL 身分驗證失敗
<a name="kafka-sasl-errors"></a>

若使用 SASL/SCRAM 或 SASL/PLAIN，此錯誤表示所提供的登入憑證無效。

對於 IAM 存取控制，執行角色缺少叢集的 `kafka-cluster:Connect` 許可。將此許可新增至角色，並將叢集的 Amazon Resource Name (ARN) 指定為資源。

您可能會間歇性地看到此錯誤發生。TCP 連線數量超過服務配額後，此叢集就會拒絕連線。Lambda 會關閉並重試，直到連線成功為止。Lambda 連接到叢集並輪詢記錄之後，上次處理結果會變更為 `OK`。

以下是在使用 IAM 身分驗證時，針對此問題啟用[記錄組態](esm-logging.md)後的範例 ESM 系統層級日誌：

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567890456,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE22222",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE22222-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE22222/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "[a1b2c3d4-5678-90ab-cdef-EXAMPLE22222]: Access denied",
        "errorCode": "org.apache.kafka.common.errors.SaslAuthenticationException"
    }
}
```

### 伺服器無法驗證 Lambda
<a name="kafka-mtls-errors-server"></a>

此錯誤表示 Kafka 代理程式無法驗證 Lambda。此狀況的發生原因如下：
+ 您並未提供 mTLS 身分驗證的用戶端憑證。
+ 您已提供用戶端憑證，但並未將 Kafka 代理程式設定為使用 mTLS 身分驗證。
+ 用戶端憑證不受 Kafka 代理程式信任。

### Lambda 無法驗證伺服器
<a name="kafka-mtls-errors-lambda"></a>

此錯誤表示 Lambda 無法驗證 Kafka 代理程式。此狀況的發生原因如下：
+ 對於自我管理的 Apache Kafka：Kafka 代理程式會使用自我簽署憑證或私有 CA，但不會提供伺服器根 CA 憑證。
+ 對於自我管理的 Apache Kafka：伺服器根 CA 憑證與簽署代理程式憑證的根 CA 不相符。
+ 主機名稱驗證失敗，因為代理程式的憑證不包含代理程式做為主體替代名稱的 DNS 名稱或 IP 地址。

### 提供的憑證或私有金鑰無效
<a name="kafka-key-errors"></a>

此錯誤表示 Kafka 取用者無法使用提供的憑證或私有金鑰。請確定憑證和金鑰使用 PEM 格式，且私有金鑰加密使用 PBES1 演算法。

以下是針對此問題啟用[記錄組態](esm-logging.md)後的範例 ESM 系統層級日誌：

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567891234,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE44444",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE44444-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE44444/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Invalid PEM keystore configs",
        "errorCode": "org.apache.kafka.common.errors.InvalidConfigurationException"
    }
}
```

## 網路和連線錯誤
<a name="kafka-network-errors"></a>

網路組態問題可防止 Lambda 連線至 Kafka 叢集。下列主題說明常見的網路相關錯誤。

**Topics**
+ [

### 安全群組組態導致連線逾時
](#kafka-security-group-errors)
+ [

### 無法解析 Kafka 代理程式端點
](#kafka-cluster-deleted-errors)

### 安全群組組態導致連線逾時
<a name="kafka-security-group-errors"></a>

如果與 Kafka 叢集相關聯的安全群組不允許來自本身的傳入流量，則 Lambda 無法連線至叢集。確定安全群組的傳入規則允許來自 Kafka 代理程式連接埠上安全群組本身的流量。

以下是針對此問題啟用[記錄組態](esm-logging.md)後的範例 ESM 系統層級日誌：

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567892345,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE55555",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE55555-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE55555/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Timeout expired while fetching topic metadata",
        "errorCode": "org.apache.kafka.common.errors.TimeoutException"
    }
}
```

您也可以檢查 Kafka 消費者 INFO 日誌，以驗證連線和網路組態。`brokerEndpoints` 欄位顯示 Kafka 代理程式地址，`securityProtocol`而 `saslMechanism`（如果適用） 顯示身分驗證方法，而 `networkConfig` 欄位顯示事件來源映射所使用的 IP 地址、子網路 CIDR 區塊和安全群組。確認列出的安全群組允許必要的傳入流量：

```
{
    "eventType": "POLLER_STATUS_EVENT",
    "timestamp": 1734567892456,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-11111EXAMPLE",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/a1b2c3d4-5678-90ab-cdef-11111EXAMPLE-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE/0",
    "logLevel": "INFO",
    "kafkaEventSourceConnection": {
        "brokerEndpoints": "boot-abcd1234.c2.kafka-serverless.us-east-1.amazonaws.com:9098",
        "consumerId": "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE-0",
        "topics": [
            "my-topic"
        ],
        "consumerGroupId": "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE",
        "securityProtocol": "SASL_SSL",
        "saslMechanism": "AWS_MSK_IAM",
        "totalPartitionCount": 2,
        "assignedPartitionCount": 2,
        "partitionsAssignmentGeneration": 1,
        "assignedPartitions": [
            "my-topic-0",
            "my-topic-1"
        ],
        "networkConfig": {
            "ipAddresses": [
                "10.0.0.37"
            ],
            "subnetCidrBlock": "10.0.0.32/28",
            "securityGroups": [
                "sg-0123456789abcdef0"
            ]
        }
    }
}
```

### 無法解析 Kafka 代理程式端點
<a name="kafka-cluster-deleted-errors"></a>

此錯誤表示 Kafka 叢集不存在或已刪除。確認事件來源映射中指定的叢集存在且處於作用中狀態。

以下是針對此問題啟用[記錄組態](esm-logging.md)後的範例 ESM 系統層級日誌：

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567893456,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE66666",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE66666-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE66666/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "No resolvable bootstrap urls given in bootstrap.servers",
        "errorCode": "org.apache.kafka.common.config.ConfigException"
    }
}
```

## 事件來源映射錯誤
<a name="services-event-errors"></a>

當您將 Apache Kafka 叢集新增為 Lambda 函數的[事件來源](invocation-eventsourcemapping.md)時，如果您的函數遇到錯誤，則您的 Kafka 取用者會停止處理記錄。主題分割區的取用者是訂閱、讀取和處理記錄者。您的其他 Kafka 取用者可以繼續處理記錄，只要他們沒有遇到相同的錯誤。

若要確定停止取用者的原因，請檢查 `EventSourceMapping` 的回應中的 `StateTransitionReason` 欄位。下列清單說明了您可能收到的事件來源錯誤：

**`ESM_CONFIG_NOT_VALID`**  
事件來源映射組態無效。

**`EVENT_SOURCE_AUTHN_ERROR`**  
Lambda 無法驗證事件來源。

**`EVENT_SOURCE_AUTHZ_ERROR`**  
Lambda 沒有存取事件來源所需的許可。

**`FUNCTION_CONFIG_NOT_VALID`**  
函數組態無效。

**注意**  
如果您的 Lambda 事件記錄超過允許的 6 MB 大小限制，則可能不會進行處理。

# 使用 Amazon API Gateway 端點調用 Lambda 函數
<a name="services-apigateway"></a>

您可以使用 Amazon API Gateway 為您的 Lambda 函數建立具有 HTTP 端點的 Web API。API Gateway 提供了用於建立和記錄 Web API 的工具，可將 HTTP 請求路由至 Lambda 函數。您可以使用身分驗證和授權控制來保護對 API 的存取。您的 API 可以透過網際網路提供流量，也可以只在 VPC 內存取。

**提示**  
Lambda 提供兩種透過 HTTP 端點調用函數的方式：API Gateway 與 Lambda 函數 URL。如果不確定哪種方法最適合自己的使用案例，請參閱[選取一種使用 HTTP 請求調用 Lambda 函數的方法](apig-http-invoke-decision.md)。

API 中的資源定義一個或多個方法，例如 GET 或 POST。方法具有將請求路由到 Lambda 函數或其他整合類型的整合。您可以個別定義每個資源和方法，或使用特殊資源和方法類型來比對所有符合某模式的請求。[代理資源](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html)會擷取資源下的所有路徑。`ANY` 方法會擷取所有 HTTP 方法。

**Topics**
+ [

## 選擇 API 類型
](#services-apigateway-apitypes)
+ [

## 將端點新增至您的 Lambda 函數
](#apigateway-add)
+ [

## Proxy 整合
](#apigateway-proxy)
+ [

## 事件格式
](#apigateway-example-event)
+ [

## 回應格式
](#apigateway-types-transforms)
+ [

## 許可
](#apigateway-permissions)
+ [

## 範例應用程式
](#services-apigateway-samples)
+ [

## Powertools for AWS Lambda 的事件處理常式
](#services-apigateway-powertools)
+ [

# 教學課程：搭配使用 Lambda 與 API Gateway
](services-apigateway-tutorial.md)
+ [

# 使用 API Gateway API 處理 Lambda 錯誤
](services-apigateway-errors.md)
+ [

# 選取一種使用 HTTP 請求調用 Lambda 函數的方法
](apig-http-invoke-decision.md)

## 選擇 API 類型
<a name="services-apigateway-apitypes"></a>

API Gateway 支援三種調用 Lambda 函數的 API 類型：
+ [HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html)：輕量型的低延遲 RESTful API。
+ [REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html)：功能豐富的可自訂 RESTful API。
+ [WebSocket API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html)：與用戶端維持持續連線以進行全雙工通訊的 Web API。

HTTP API 和 REST API 都是處理 HTTP 請求並傳回回應的 RESTful API。HTTP API 較新，並且是使用 API Gateway 版本 2 API 建置而成。下列功能是 HTTP API 的新功能：

**HTTP API 功能**
+ **自動部署** - 當您修改路由或整合時，變更會自動部署至已啟用自動部署的階段。
+ **預設階段** - 您可以建立預設階段 (`$default`)，在 API URL 的根路徑提供請求。對於具名階段，您必須在路徑的開頭加入階段名稱。
+ **CORS 組態** - 您可以設定 API 將 CORS 標頭新增到傳出回應中，而不是在函數程式碼中手動新增。

REST API 是 API Gateway 自推出以來支援的典型 RESTful API。REST API 目前具有更多的自訂、整合和管理功能。

**REST API 功能**
+ **整合類型** - REST API 支援自訂 Lambda 整合。您可以使用自訂整合，只將請求的本文傳送到函數，或者在將請求本文傳送到函數之前套用轉換範本。
+ **存取控制** - REST API 支援其他身分驗證和授權選項。
+ **監控和追蹤** – REST APIs支援 AWS X-Ray 追蹤和其他記錄選項。

如需詳細比較，請參閱《API Gateway 開發人員指南》**中的 [Choose between HTTP APIs and REST APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html)。

WebSocket API 也使用 API Gateway 版本 2 API，並支援類似的功能集。對於可從用戶端與 API 之間持續連線獲益的應用程式，請使用 WebSocket API。WebSocket API 提供全雙工通訊，這意味著用戶端和 API 都可以連續傳送訊息，而無需等待回應。

HTTP API 支援簡化的事件格式 (2.0 版)。如需 HTTP API 事件的範例，請參閱[在 API Gateway 中建立 HTTP APIs AWS Lambda 代理整合](https://docs.aws.amazon.com//apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)。

如需詳細資訊，請參閱[在 API Gateway 中建立 HTTP APIs AWS Lambda 代理整合](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)。

## 將端點新增至您的 Lambda 函數
<a name="apigateway-add"></a>

**若要將公有端點新增至您的 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇一個函數。

1. 在**函數概觀**下，選擇**新增觸發條件**。

1. 選取 **API Gateway** (API Gateway )。

1. 選擇 **Create an API** (建立 API) 或 **Use an existing API** (使用現有 API)。

   1. **全新 API**：對於 **API type** (API 類型)，請選擇 **HTTP API**。如需詳細資訊，請參閱[選擇 API 類型](#services-apigateway-apitypes)。

   1. **現有 API：**從下拉式清單中選取 API 或輸入 API ID (例如，r3pmxmplak)。

1. 在 **Security** (安全性) 中，選擇 **Open** (開啟)。

1. 選擇 **Add** (新增)。

## Proxy 整合
<a name="apigateway-proxy"></a>

API Gateway API 由階段、資源、方法和整合所組成。階段和資源決定端點的路徑：

**API 路徑格式**
+ `/prod/` - `prod` 階段和根資源。
+ `/prod/user` - `prod` 階段和 `user` 資源。
+ `/dev/{proxy+}` - `dev` 階段中的任何路由。
+ `/` - (HTTP API) 預設階段和根資源。

Lambda 整合將路徑和 HTTP 方法組合映射到一個 Lambda 函數。您可以設定 API Gateway 依現狀傳遞 HTTP 請求的主體 (自訂整合)，或將請求主體封裝在一個包含所有請求資訊 (包括標頭、資源、路徑和方法) 的文件中。

如需設定詳細資訊，請參閱 [Lambda proxy integrations in API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html)。

## 事件格式
<a name="apigateway-example-event"></a>

Amazon API Gateway 使用包含 HTTP 請求之 JSON 表示的事件來[同步](invocation-sync.md)調用您的函數。對於自訂整合，事件是請求的本文。對於代理整合，事件具有已定義的結構。如需 API Gateway REST API 的代理事件範例，請參閱《API Gateway 開發人員指南》**中的[代理整合之 Lambda 函數的輸入格式](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format)。

## 回應格式
<a name="apigateway-types-transforms"></a>

API Gateway 會等待函數的回應並將結果轉達給呼叫者。對於自訂整合，您可以定義整合回應和方法回應，將函數的輸出轉換為 HTTP 回應。對於代理整合，函數必須以特定格式的回應表示作出回應。

下列範例顯示來自 Node.js 函數的回應物件。回應物件表示包含 JSON 文件的成功 HTTP 回應。

**Example index.mjs - 代理整合回應物件 (Node.js)**  

```
var response = {
      "statusCode": 200,
      "headers": {
        "Content-Type": "application/json"
      },
      "isBase64Encoded": false,
      "multiValueHeaders": { 
        "X-Custom-Header": ["My value", "My other value"],
      },
      "body": "{\n  \"TotalCodeSize\": 104330022,\n  \"FunctionCount\": 26\n}"
    }
```

Lambda 執行時間會將回應物件序列化為 JSON，並將其傳送至 API。API 會剖析該回應並用它來建立 HTTP 回應，然後將其傳送到發出原始請求的用戶端。

**Example HTTP 回應**  

```
< HTTP/1.1 200 OK
  < Content-Type: application/json
  < Content-Length: 55
  < Connection: keep-alive
  < x-amzn-RequestId: 32998fea-xmpl-4268-8c72-16138d629356
  < X-Custom-Header: My value
  < X-Custom-Header: My other value
  < X-Amzn-Trace-Id: Root=1-5e6aa925-ccecxmplbae116148e52f036
  <
  {
    "TotalCodeSize": 104330022,
    "FunctionCount": 26
  }
```

## 許可
<a name="apigateway-permissions"></a>

Amazon API Gateway 會取得許可，從函數的[以資源為基礎的政策](access-control-resource-based.md)中調用您的函數。您可以將呼叫許可授與整個 API，或將有限存取權授與階段、資源或方法。

當您透過使用 Lambda 主控台、使用 API Gateway 主控台或在 AWS SAM 範本中，將 API 新增至函數時，會自動更新函數的以資源為基礎的政策。範例函數政策範例如下。

**Example 函數政策**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Id": "default",
  "Statement": [
    {
      "Sid": "nodejs-apig-functiongetEndpointPermissionProd-BWDBXMPLXE2F",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-2:111122223333:function:nodejs-apig-function-1G3MXMPLXVXYI",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "111122223333"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:execute-api:us-east-2:111122223333:ktyvxmpls1/*/GET/"
        }
      }
    }
  ]
}
```

您可以使用下列 API 操作來手動管理函數政策許可：
+ [AddPermission](https://docs.aws.amazon.com/lambda/latest/api/API_AddPermission.html)
+ [RemovePermission](https://docs.aws.amazon.com/lambda/latest/api/API_RemovePermission.html)
+ [GetPolicy](https://docs.aws.amazon.com/lambda/latest/api/API_GetPolicy.html)

若要將調用許可授與現有 API，請使用 `add-permission` 命令。範例：

```
aws lambda add-permission \
  --function-name my-function \
  --statement-id apigateway-get --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:us-east-2:123456789012:mnh1xmpli7/default/GET/"
```

您應該會看到下列輸出：

```
{
    "Statement": "{\"Sid\":\"apigateway-test-2\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-2:123456789012:function:my-function\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:us-east-2:123456789012:mnh1xmpli7/default/GET\"}}}"
}
```

**注意**  
如果您的函數和 API 位於不同的 中 AWS 區域，來源 ARN 中的區域識別符必須符合函數的區域，而不是 API 的區域。當 API Gateway 調用函數時，它會使用以 API 的 ARN 為基礎的資源 ARN，但會加以修改以符合函數的區域。

此範例中的來源 ARN 會將許可授與 API 的預設階段中根資源 GET 方法的整合 (ID 為 `mnh1xmpli7`)。您可以在來源 ARN 中使用星號，將許可授與多個階段、方法或資源。

**資源模式**
+ `mnh1xmpli7/*/GET/*` - 所有階段中所有資源上的 GET 方法。
+ `mnh1xmpli7/prod/ANY/user` - `prod` 階段中 `user` 資源上的 ANY 方法。
+ `mnh1xmpli7/*/*/*` - 所有階段中所有資源上的任何方法。

如需檢視政策和移除陳述式的詳細資訊，請參閱 [在 Lambda 中檢視資源型 IAM 政策](access-control-resource-based.md)。

## 範例應用程式
<a name="services-apigateway-samples"></a>

[具有 Node.js 的 API Gateway](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/nodejs-apig) 範例應用程式包含具有 範本的 AWS SAM 函數，該範本會建立已啟用 AWS X-Ray 追蹤的 REST API。它也包括用於部署、調用函數、測試 API 和清理的指令碼。

## Powertools for AWS Lambda 的事件處理常式
<a name="services-apigateway-powertools"></a>

撰寫 API Gateway 端點 (HTTP 或 REST) 調用的 Lambda 函數時，來自 Powertools for AWS Lambda 工具組的事件處理常式提供路由、中介軟體、CORS 組態、OpenAPI 規格產生、請求驗證、錯誤處理和其他實用功能。該事件處理常式公用程式適用於 Python 與 TypeScript/JavaScript。如需詳細資訊，請參閱 *Powertools for AWS Lambda (Python) 文件*中的[事件處理常式 REST API](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/)，以及 *Powertools for AWS Lambda (TypeScript) 文件*中的[事件處理常式 HTTP API](https://docs.aws.amazon.com/powertools/typescript/latest/features/event-handler/http/)。

### Python
<a name="services-apigateway-powertools-python"></a>

```
from aws_lambda_powertools import Logger
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing.lambda_context import LambdaContext

app = APIGatewayRestResolver()
logger = Logger()

@app.get("/healthz")
def ping():
    return {"message": "health status ok"}

@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)  
def lambda_handler(event: dict, context: LambdaContext) -> dict:
    return app.resolve(event, context)
```

### Typescript
<a name="services-apigateway-powertools-typescript"></a>

```
import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest';
import { Logger } from '@aws-lambda-powertools/logger';
import {
  correlationPaths,
  search,
} from '@aws-lambda-powertools/logger/correlationId';
import type { Context } from 'aws-lambda/handler';

const logger = new Logger({
  correlationIdSearchFn: search,
});

const app = new Router({ logger });

app.get("/healthz", async () => {
  return { message: "health status ok" };
});

export const handler = async (event: unknown, context: Context) => {
  // You can continue using other utilities just as before
  logger.addContext(context);
  logger.setCorrelationId(event, correlationPaths.API_GATEWAY_REST);
  return app.resolve(event, context);
};
```

# 教學課程：搭配使用 Lambda 與 API Gateway
<a name="services-apigateway-tutorial"></a>

在此教學課程中，您將建立 REST API，並透過此 API 調用 Lambda 函數。Lambda 函數會對 DynamoDB 資料表執行建立、讀取、更新及刪除 (CRUD) 操作。這裡提供的函數僅供示範，您將學習如何設定可調用任何 Lambda 函數的 API Gateway REST API。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/APIG_tut_resources.png)


使用 API Gateway 為使用者提供安全的 HTTP 端點以調用 Lambda 函數，並透過流量限流以及自動驗證和授權 API 呼叫，協助管理函數的大量呼叫。API Gateway 也提供使用 AWS Identity and Access Management (IAM) 和 Amazon Cognito 的彈性安全控制。對於需要預先授權才能呼叫應用程式的使用案例，這非常有用。

**提示**  
Lambda 提供兩種透過 HTTP 端點調用函數的方式：API Gateway 與 Lambda 函數 URL。如果不確定哪種方法最適合自己的使用案例，請參閱[選取一種使用 HTTP 請求調用 Lambda 函數的方法](apig-http-invoke-decision.md)。

完成本教學課程需逐一進行以下階段：

1. 以 Python 或 Node.js 建立並設定 Lambda 函數，用於對 DynamoDB 資料表執行操作。

1. 在 API Gateway 中建立 REST API 以連接 Lambda 函數。

1. 建立 DynamoDB 資料表，然後在主控台中使用您的 Lambda 函數進行測試。

1. 在終端內使用 curl 部署 API 並測試完整設定。

完成這些階段後，您將了解如何使用 API Gateway 建立 HTTP 端點，以安全地調用任何規模的 Lambda 函數。您也會學習如何部署 API，以及如何在控制台中以及使用終端傳送 HTTP 請求來進行測試。

## 建立許可政策
<a name="services-apigateway-tutorial-policy"></a>

在建立 Lambda 函數的[執行角色](lambda-intro-execution-role.md)之前，您必須先建立許可政策，以授予函數存取所需 AWS 資源的許可。在本教學課程中，政策允許 Lambda 對 DynamoDB 資料表執行 CRUD 操作，以及寫入 Amazon CloudWatch Logs。

**建立政策**

1. 開啟 IAM 主控台中的[政策頁面](https://console.aws.amazon.com/iam/home#/policies)。

1. 選擇**建立政策**。

1. 選擇 **JSON** 索引標籤，然後將下列政策貼到 JSON 編輯器。

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "Stmt1428341300017",
         "Action": [
           "dynamodb:DeleteItem",
           "dynamodb:GetItem",
           "dynamodb:PutItem",
           "dynamodb:Query",
           "dynamodb:Scan",
           "dynamodb:UpdateItem"
         ],
         "Effect": "Allow",
         "Resource": "*"
       },
       {
         "Sid": "",
         "Resource": "*",
         "Action": [
           "logs:CreateLogGroup",
           "logs:CreateLogStream",
           "logs:PutLogEvents"
         ],
         "Effect": "Allow"
       }
     ]
   }
   ```

------

1. 選擇下**一步：標籤**。

1. 選擇下**一步：檢閱**。

1. 在**檢閱政策下**，針對政策**名稱**，輸入 **lambda-apigateway-policy**。

1. 選擇**建立政策**。

## 建立執行角色
<a name="services-apigateway-tutorial-role"></a>

[執行角色](lambda-intro-execution-role.md)是授予 Lambda 函數存取 AWS 服務 和資源許可的 AWS Identity and Access Management (IAM) 角色。若要讓函數對 DynamoDB 資料表執行操作，您需附加在上個步驟中建立的許可政策。

**建立執行角色並附加自訂許可政策**

1. 開啟 IAM 主控台中的[角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇 **建立角色**。

1. 信任的實體類型請選擇 **AWS 服務**，使用案例則選擇 **Lambda**。

1. 選擇**下一步**。

1. 在政策搜尋方塊中，輸入 **lambda-apigateway-policy**。

1. 在搜尋結果中，選取您建立的政策 (`lambda-apigateway-policy`)，然後選擇**下一步**。

1. 在**角色詳細資料**底下，**角色名稱**請輸入 **lambda-apigateway-role**，然後選擇**建立角色**。

## 建立 Lambda 函式
<a name="services-apigateway-tutorial-function"></a>

1. 開啟 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)，然後選擇**建立函數**。

1. 選擇**從頭開始撰寫**。

1. 針對**函數名稱**，請輸入 `LambdaFunctionOverHttps`。

1. 在**執行時期**欄位中，選擇最新版本的 Node.js 或 Python 執行時期。

1. 在**許可**下，展開**變更預設執行角色**。

1. 選擇**使用現有角色**，然後選取先前建立的 **lambda-apigateway-role** 角色。

1. 選擇**建立函數**。

1. 在**程式碼來源**窗格中，以下列 Node.js 或 Python 程式碼取代預設程式碼。

------
#### [ Node.js ]

   `region` 設定必須符合您部署函數和[建立 DynamoDB 資料表](#services-apigateway-tutorial-table) AWS 區域 的 。

**Example index.mjs**  

   ```
   import { DynamoDBDocumentClient, PutCommand, GetCommand, 
            UpdateCommand, DeleteCommand} from "@aws-sdk/lib-dynamodb";
   import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
   
   const ddbClient = new DynamoDBClient({ region: "us-east-2" });
   const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);
   
   // Define the name of the DDB table to perform the CRUD operations on
   const tablename = "lambda-apigateway";
   
   /**
    * Provide an event that contains the following keys:
    *
    *   - operation: one of 'create,' 'read,' 'update,' 'delete,' or 'echo'
    *   - payload: a JSON object containing the parameters for the table item
    *     to perform the operation on
    */
   export const handler = async (event, context) => {
      
        const operation = event.operation;
      
        if (operation == 'echo'){
             return(event.payload);
        }
        
       else { 
           event.payload.TableName = tablename;
           let response;
           
           switch (operation) {
             case 'create':
                  response = await ddbDocClient.send(new PutCommand(event.payload));
                  break;
             case 'read':
                  response = await ddbDocClient.send(new GetCommand(event.payload));
                  break;
             case 'update':
                  response = ddbDocClient.send(new UpdateCommand(event.payload));
                  break;
             case 'delete':
                  response = ddbDocClient.send(new DeleteCommand(event.payload));
                  break;
             default:
               response = 'Unknown operation: ${operation}';
             }
           console.log(response);
           return response;
       }
   };
   ```

------
#### [ Python ]

**Example lambda\$1function.py**  

   ```
   import boto3
   
   # Define the DynamoDB table that Lambda will connect to
   table_name = "lambda-apigateway"
   
   # Create the DynamoDB resource
   dynamo = boto3.resource('dynamodb').Table(table_name)
   
   # Define some functions to perform the CRUD operations
   def create(payload):
       return dynamo.put_item(Item=payload['Item'])
   
   def read(payload):
       return dynamo.get_item(Key=payload['Key'])
   
   def update(payload):
       return dynamo.update_item(**{k: payload[k] for k in ['Key', 'UpdateExpression', 
       'ExpressionAttributeNames', 'ExpressionAttributeValues'] if k in payload})
   
   def delete(payload):
       return dynamo.delete_item(Key=payload['Key'])
   
   def echo(payload):
       return payload
   
   operations = {
       'create': create,
       'read': read,
       'update': update,
       'delete': delete,
       'echo': echo,
   }
   
   def lambda_handler(event, context):
       '''Provide an event that contains the following keys:
         - operation: one of the operations in the operations dict below
         - payload: a JSON object containing parameters to pass to the 
           operation being performed
       '''
       
       operation = event['operation']
       payload = event['payload']
       
       if operation in operations:
           return operations[operation](payload)
           
       else:
           raise ValueError(f'Unrecognized operation "{operation}"')
   ```

------
**注意**  
在此範例中，DynamoDB 資料表的名稱定義為函數程式碼中的變數。在實際的應用程式中，最佳實務是將此參數做為環境變數來傳遞，並避免對資料表名稱進行硬式編碼。如需詳細資訊，請參閱[使用 AWS Lambda 環境變數](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html)。

1. 在 **DEPLOY** 區段中，選擇**部署**以更新函數的程式碼：  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## 測試函數
<a name="services-apigateway-tutorial-test-function"></a>

在將函數與 API Gateway 整合之前，請確認已成功部署該函數。使用 Lambda 主控台將測試事件傳送至函式。

1. 在函式的 Lambda 主控台頁面中，選擇**測試**索引標籤。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/test-tab.png)

1. 向下捲動至**事件 JSON** 區段，以下列內容取代預設事件。此事件符合 Lambda 函式預期的結構。

   ```
   {
       "operation": "echo",
       "payload": {
           "somekey1": "somevalue1",
           "somekey2": "somevalue2"
       }
   }
   ```

1. 選擇**測試**。

1. 在**執行函式：成功**欄位中，展開**詳細資訊**。您應該會看到下列回應：

   ```
   {
     "somekey1": "somevalue1",
     "somekey2": "somevalue2"
   }
   ```

## 使用 API Gateway 建立 REST API
<a name="services-apigateway-tutorial-api"></a>

在此步驟中，您將建立用來調用 Lambda 函數的 API Gateway REST API。

**若要建立 API**

1. 開啟 [API Gateway 主控台](https://console.aws.amazon.com/apigateway)。

1. 選擇 **建立 API** 。

1. 在 **REST API** 方塊中，選擇 **建置** 。

1. 在 **API 詳細資訊**下，讓**新增 API**維持在已選取的狀態，然後對於 **API 名稱**，輸入 **DynamoDBOperations**。

1. 選擇 **建立 API** 。

## 在 REST API 上建立資源
<a name="services-apigateway-tutorial-resource"></a>

若要將 HTTP 方法新增到 API 中，首先需為該方法建立用來操作的資源。您可以在此建立資源來管理 DynamoDB 資料表。

**若要建立資源**

1. 在 [API Gateway 主控台](https://console.aws.amazon.com/apigateway)的 API **資源**頁面上，選擇**建立資源**。

1. 在**資源詳細資訊**中，針對**資源名稱**輸入 **DynamoDBManager**。

1. 選擇 **建立資源** 。

## 建立 HTTP POST 方法
<a name="services-apigateway-tutorial-method"></a>

在此步驟中，您將為 `DynamoDBManager` 資源建立方法 (`POST`)。您需將此 `POST` 方法連結到 Lambda 函數，如此一來當方法收到 HTTP 請求，API Gateway 就會調用 Lambda 函數。

**注意**  
 基於本教學課程的目的，會使用一個 HTTP 方法 (`POST`) 來調用單一 Lambda 函數，該函數會對 DynamoDB 資料表執行所有操作。在實際的應用程式中，最佳實務是針對每項操作使用不同的 Lambda 函數和 HTTP 方法。如需詳細資訊，請參閱無伺服器園地中的 [The Lambda Monolith](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/monolith)。

**建立 POST 方法**

1. 在 API 的**資源**頁面上，確定已反白選取 `/DynamoDBManager` 資源。然後，在**方法**窗格中，選擇**建立方法**。

1. 針對**方法類型**，選擇 **POST**。

1. 對於**整合類型**，讓 **Lambda 函數**維持在已選取的狀態。

1. 對於 **Lambda 函數**，請為函數 (`LambdaFunctionOverHttps`) 選擇 Amazon Resource Name (ARN)。

1. 選擇**建立方法**。

## 建立 DynamoDB 資料表
<a name="services-apigateway-tutorial-table"></a>

建立空白的 DynamoDB 資料表，Lambda 函數會對該資料表執行 CRUD 操作。

**若要建立 DynamoDB 資料表**

1. 開啟 DynamoDB 主控台的[資料表](https://console.aws.amazon.com/dynamodbv2#tables)頁面。

1. 選擇 **建立資料表** 。

1. 在 **Table details** (資料表詳細資訊) 下，執行下列動作：

   1. 對於 **Table name** (資料表名稱)，請輸入 **lambda-apigateway**。

   1. 對於 **Partition key** (分割區索引鍵)，輸入**id**，並保持資料類型設定為 **String** (字串)。

1. 在 **Table settings** (資料表設定) 下，保留 **Default settings** (預設設定)。

1. 選擇 **建立資料表** 。

## 測試 API Gateway、Lambda 和 DynamoDB 的整合
<a name="services-apigateway-tutorial-test-setup"></a>

您現在已準備好測試 API Gateway API 方法與 Lambda 函數和 DynamoDB 資料表的整合。使用 API Gateway 主控台，您可以利用主控台的測試功能，將請求直接傳送至您的 `POST` 方法。在此步驟中，首先需使用 `create` 操作將新項目新增至 DynamoDB 資料表，然後使用 `update` 操作來修改項目。

**測試 1：在 DynamoDB 資料表中建立新項目**

1. 在 [API Gateway 主控台](https://console.aws.amazon.com/apigateway)中，選擇您的 API (`DynamoDBOperations`)。

1. 在 `DynamoDBManager` 資源下方，選擇 **POST** 方法。

1. 選擇**測試**標籤。您可能需要選擇向右箭頭按鈕才能顯示此索引標籤。

1. 在**測試方法**下，讓**查詢字串**和**標頭**留空。對於**請求主體**，貼上下列 JSON：

   ```
   {
     "operation": "create",
     "payload": {
       "Item": {
         "id": "1234ABCD",
         "number": 5
       }
     }
   }
   ```

1. 選擇 **測試** 。

   測試完成時顯示的結果應該會顯示 `200` 狀態。此狀態碼表示 `create` 操作成功。

    若要確認，您可以檢查 DynamoDB 資料表現在是否包含新項目。

1. 開啟 DynamoDB 主控台的 [資料表頁面](https://console.aws.amazon.com/dynamodbv2#tables) ，然後選擇 `lambda-apigateway` 資料表。

1. 選擇 **探索資料表項目** 。在 **Items returned** (傳回的項目) 窗格中，應該會看到一個包含 **id** `1234ABCD` 和 **number** `5` 的項目。範例：  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/items-returned.png)

**測試 2 ：更新 DynamoDB 資料表中的項目**

1. 在 [API Gateway 主控台](https://console.aws.amazon.com/apigateway)中，返回到 POST 方法的**測試**分頁。

1. 在**測試方法**下，讓**查詢字串**和**標頭**留空。對於**請求主體**，貼上下列 JSON：

   ```
   {
       "operation": "update",
       "payload": {
           "Key": {
               "id": "1234ABCD"
           },
           "UpdateExpression": "SET #num = :newNum",
           "ExpressionAttributeNames": {
               "#num": "number"
           },
           "ExpressionAttributeValues": {
               ":newNum": 10
           }
       }
   }
   ```

1. 選擇 **測試** 。

   測試完成時顯示的結果應該會顯示 `200` 狀態。此狀態碼表示 `update` 操作成功。

    若要確認，請檢查 DynamoDB 資料表中的項目是否已修改。

1. 開啟 DynamoDB 主控台的 [資料表頁面](https://console.aws.amazon.com/dynamodbv2#tables) ，然後選擇 `lambda-apigateway` 資料表。

1. 選擇 **探索資料表項目** 。在 **Items returned** (傳回的項目) 窗格中，應該會看到一個包含 **id** `1234ABCD` 和 **number** `10` 的項目。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/items-returned-2.png)

## 部署 API
<a name="services-apigateway-tutorial-deploy-api"></a>

為了讓用戶端能呼叫您的 API，您必須建立部署並建立相關聯的階段。階段代表 API 的快照，包括其方法和整合項目。

**部署 API**

1. 開啟 [API Gateway 主控台](https://console.aws.amazon.com/apigateway)中的 **API** 頁面，然後選擇 `DynamoDBOperations` API。

1. 在 API 的**資源**頁面上，選擇**部署 API**。

1. 對於**階段**，請選擇**\$1新增階段\$1**，然後在**階段名稱**輸入 **test**。

1. 選擇**部署**。

1. 在**階段詳細資訊**窗格中，複製**調用 URL**。您將在下一個步驟中使用此資料來透過 HTTP 請求調用函數。

## 使用 curl 來透過 HTTP 請求調用函數
<a name="services-apigateway-tutorial-invoke-function"></a>

您現在可以透過向 API 發出 HTTP 請求來調用 Lambda 函數。在此步驟中，您將在 DynamoDB 資料表中建立新項目，然後對該項目執行讀取、更新和刪除操作。

**若要使用 curl 在 DynamoDB 資料表中建立項目**

1. 在本機電腦上開啟終端或命令提示，並使用在上一個步驟中複製的調用 URL 執行下列 `curl` 命令。此命令使用下列選項：
   + `-H`：將自訂標頭新增至請求。此處用於指定內容類型為 JSON。
   + `-d`：在請求內文中傳送資料。此選項預設使用 HTTP POST 方法。

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "create", "payload": {"Item": {"id": "5678EFGH", "number": 15}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"create\", \"payload\": {\"Item\": {\"id\": \"5678EFGH\", \"number\": 15}}}'
   ```

------

   如果操作成功，您應該會看到傳回的回應及 HTTP 狀態碼 200。

1. 您也可以使用 DynamoDB 主控台執行下列步驟，驗證新項目是否在您的資料表中：

   1. 開啟 DynamoDB 主控台的 [資料表頁面](https://console.aws.amazon.com/dynamodbv2#tables) ，然後選擇 `lambda-apigateway` 資料表。

   1. 選擇 **探索資料表項目** 。在 **Items returned** (傳回的項目) 窗格中，應該會看到一個包含 **id** `5678EFGH` 和 **number** `15` 的項目。

**若要使用 curl 讀取 DynamoDB 資料表中的項目**
+ 在終端或命令提示中執行以下 `curl` 命令，讀取剛建立項目的值。使用您自己的調用 URL。

------
#### [ Linux/macOS ]

  ```
  curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
  -H "Content-Type: application/json" \
  -d '{"operation": "read", "payload": {"Key": {"id": "5678EFGH"}}}'
  ```

------
#### [ PowerShell ]

  ```
  curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"read\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}}}'
  ```

------

  視您選擇 Node.js 或 Python 函數程式碼而定，您應該會看到類似下列其中一項的輸出：

------
#### [ Node.js ]

  ```
  {"$metadata":{"httpStatusCode":200,"requestId":"7BP3G5Q0C0O1E50FBQI9NS099JVV4KQNSO5AEMVJF66Q9ASUAAJG",
  "attempts":1,"totalRetryDelay":0},"Item":{"id":"5678EFGH","number":15}}
  ```

------
#### [ Python ]

  ```
  {"Item":{"id":"5678EFGH","number":15},"ResponseMetadata":{"RequestId":"QNDJICE52E86B82VETR6RKBE5BVV4KQNSO5AEMVJF66Q9ASUAAJG",
  "HTTPStatusCode":200,"HTTPHeaders":{"server":"Server","date":"Wed, 31 Jul 2024 00:37:01 GMT","content-type":"application/x-amz-json-1.0",
  "content-length":"52","connection":"keep-alive","x-amzn-requestid":"QNDJICE52E86B82VETR6RKBE5BVV4KQNSO5AEMVJF66Q9ASUAAJG","x-amz-crc32":"2589610852"},
  "RetryAttempts":0}}
  ```

------

**若要使用 curl 更新 DynamoDB 資料表中的項目**

1. 在終端或命令提示中執行下列 `curl` 命令，透過變更 `number` 值來更新剛建立的項目。使用您自己的調用 URL。

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "update", "payload": {"Key": {"id": "5678EFGH"}, "UpdateExpression": "SET #num = :new_value", "ExpressionAttributeNames": {"#num": "number"}, "ExpressionAttributeValues": {":new_value": 42}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"update\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}, \"UpdateExpression\": \"SET #num = :new_value\", \"ExpressionAttributeNames\": {\"#num\": \"number\"}, \"ExpressionAttributeValues\": {\":new_value\": 42}}}'
   ```

------

1. 若要確認項目的 `number` 值已更新，請執行另一個讀取命令：

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "read", "payload": {"Key": {"id": "5678EFGH"}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"read\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}}}'
   ```

------

**若要使用 curl 刪除 DynamoDB 資料表中的項目**

1. 在終端或命令提示中，執行以下 `curl` 命令，刪除剛建立的項目。使用您自己的調用 URL。

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "delete", "payload": {"Key": {"id": "5678EFGH"}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"delete\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}}}'
   ```

------

1. 確認刪除操作成功。在 DynamoDB 主控台**探索項目**頁面的**已傳回項目**窗格中，確認具有 **id** `5678EFGH` 的項目已不存在於資料表中。

## 清除資源 (選用)
<a name="cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇**刪除**。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇 **刪除** 。

**若要刪除 API**

1. 開啟 API Gateway 主控台中的 [API 頁面](https://console.aws.amazon.com/apigateway/main/apis) 。

1. 選取您建立的 API。

1. 選擇 **動作** 、**刪除** 。

1. 選擇 **刪除** 。

**若要刪除 DynamoDB 資料表**

1. 開啟 DynamoDB 主控台的 [資料表頁面](https://console.aws.amazon.com//dynamodb/home#tables:) 。

1. 選取您建立的資料表。

1. 選擇 **刪除** 。

1. 在文字方塊中輸入 **delete**。

1. 選擇 **刪除資料表** 。

# 使用 API Gateway API 處理 Lambda 錯誤
<a name="services-apigateway-errors"></a>

API Gateway 會將所有調用和函數錯誤視為內部錯誤。如果 Lambda API 拒絕調用請求，則 API Gateway 會傳回 500 錯誤代碼。如果函數執行但傳回錯誤，或傳回格式錯誤的回應，API Gateway 會傳回 502。在這兩種情況下，API Gateway 的回應主體為 `{"message": "Internal server error"}`。

**注意**  
API Gateway 不會重試任何 Lambda 調用。如果 Lambda 傳回錯誤，API Gateway 會將錯誤回應傳回至用戶端。

下列範例顯示導致函數錯誤和 API Gateway 傳回 502 的請求的 X-Ray 流程圖。用戶端會收到一般錯誤訊息。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/tracemap-apig-502.png)


若要自訂錯誤回應，您必須在程式碼中發現錯誤，並以必要的格式格式化回應。

**Example [index.mjs](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/nodejs-apig/function/index.mjs) - 格式錯誤**  

```
var formatError = function(error){
  var response = {
    "statusCode": error.statusCode,
    "headers": {
      "Content-Type": "text/plain",
      "x-amzn-ErrorType": error.code
    },
    "isBase64Encoded": false,
    "body": error.code + ": " + error.message
  }
  return response
}
```

API Gateway 將此回應轉換為具有自定義狀態碼和主體的 HTTP 錯誤。在流程圖中，函數節點是綠色的，因為它會處理錯誤。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/tracemap-apig-404.png)


# 選取一種使用 HTTP 請求調用 Lambda 函數的方法
<a name="apig-http-invoke-decision"></a>

Lambda 的許多常見使用案例涉及使用 HTTP 請求調用您的函數。例如，您可能希望 Web 應用程式透過瀏覽器請求調用您的函式。Lambda 函式也可用於建立完整的 REST API、處理來自行動應用程式的使用者互動、透過 HTTP 呼叫處理來自外部服務的資料，或建立自訂 Webhook。

以下各節說明透過 HTTP 調用 Lambda 的選擇，並提供資訊以協助您針對特定使用案例做出正確決策。

## 選取 HTTP 調用方法時，您有哪些選擇？
<a name="w2aad101c29c46b9"></a>

Lambda 提供兩種主要方法來使用 HTTP 請求調用函數 - [函數 URL](urls-configuration.md) 和 [API Gateway](services-apigateway.md)。這兩種選項的主要差異如下所示：
+ **Lambda 函數 URL** 可為 Lambda 函數提供簡單、直接的 HTTP 端點。已針對簡單性和成本效益對其進行最佳化，並提供透過 HTTP 公開 Lambda 函數的最快路徑。
+ **API Gateway** 是一種更進階的服務，用於建置功能完整的 API。API Gateway 已針對大規模建置和管理生產 API 進行最佳化，並提供完整的安全、監控和流量管理工具。

## 您已知道自己需求時的建議
<a name="w2aad101c29c46c11"></a>

如果您已經清楚自己的需求，以下是基本建議：

建議**[函數 URL](urls-configuration.md)** 用於簡單的應用程式或原型設計，其中您只需要基本的身分驗證方法和請求/回應處理，並想要將成本和複雜性降至最低。

**[API Gateway](services-apigateway.md)** 是大規模生產應用程式或需要更進階功能的情況的更佳選擇，例如 [OpenAPI Description](https://www.openapis.org/) 支援、身分驗證選項、自訂網域名稱或豐富的請求/回應處理，包括限流、快取和請求/回應轉換。

## 選擇調用 Lambda 函數的方法時應考慮的事項
<a name="w2aad101c29c46c13"></a>

在函數 URL 和 API Gateway 之間選取時，需要考慮下列因素：
+ 您的身分驗證需要，例如是否需要 OAuth 或 Amazon Cognito 來驗證使用者
+ 您的擴展需求以及您要實作之 API 的複雜性
+ 您是否需要進階功能，例如請求驗證和請求/回應格式化
+ 您的監控需求
+ 您的成本目標

透過了解這些因素，可以選擇最能平衡您的安全性、複雜性和成本需求的選項。

下列資訊摘要說明兩個選項之間的主要差異。

### 身分驗證
<a name="w2aad101c29c46c13c11b1"></a>
+ **函數 URLs**提供基本身分驗證選項。 AWS Identity and Access Management 可以將端點設定為公有 (無身分驗證) 或需要 IAM 身分驗證。透過 IAM 身分驗證，您可以使用標準 AWS 登入資料或 IAM 角色來控制存取。雖然設定簡單，但相較於其他驗證方法，此方法提供的選項有限。
+ **API Gateway** 可存取更全面的身分驗證選項。除了 IAM 身分驗證之外，也可以使用 [Lambda 授權工具](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) (自訂身分驗證邏輯)、[Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html) 使用者集區和 OAuth2.0 流程。此彈性可讓您實作複雜的身分驗證機制，包括第三方身分驗證提供者、權杖型身分驗證和多重要素身分驗證。

### 請求/回應處理
<a name="w2aad101c29c46c13c11b3"></a>
+ **函數 URL** 提供基本的 HTTP 請求和回應處理。它們支援標準 HTTP 方法，並包含內建的跨來源資源共用 (CORS) 支援。雖然他們可以自然處理 JSON 承載和查詢參數，但它們不提供請求轉換或驗證功能。回應處理同樣簡單 – 用戶端接收來自 Lambda 函數的回應，就像 Lambda 傳回它一樣。
+ **API Gateway** 可提供複雜的請求和回應處理功能。您可以定義請求驗證器，使用映射範本轉換請求和回應，設定請求/回應標頭，以及實作回應快取。API Gateway 也支援二進位承載和自訂網域名稱，並且可以在回應到達用戶端之前對其進行修改。可以使用 JSON 結構描述來設定請求/回應驗證和轉換的模型。

### 擴展
<a name="w2aad101c29c46c13c11b5"></a>
+ **函數 URL** 會根據 Lambda 函數的並行限制直接擴展，並透過將函數擴展到其設定的並行限制上限來處理流量尖峰。達到該限制後，Lambda 會使用 HTTP 429 回應來回應其他請求。沒有內建佇列機制，因此處理擴展完全取決於 Lambda 函數的組態。根據預設，Lambda 函數每個 有 1，000 個並行執行的限制 AWS 區域。
+ 除了 Lambda 自己的擴展之外，**API Gateway** 還提供其他擴展功能。它包含內建的請求佇列和限流控制，可讓您更輕鬆地管理流量尖峰。根據預設，API Gateway 每秒最多可以處理 10,000 個請求，高載容量為每秒 5,000 個請求。它也提供在不同層級調節請求的工具 (API、階段或方法)，以保護後端。

### 監控
<a name="w2aad101c29c46c13c11b7"></a>
+ **函數 URL** 透過 Amazon CloudWatch 指標提供基本監控，包括請求計數、延遲和錯誤率。可以存取標準 Lambda 指標和日誌，它們會顯示傳入函數的原始請求。雖然這可提供基本的操作可見性，但指標主要著重於函數執行。
+ **API Gateway** 提供全面的監控功能，包括詳細的指標、記錄和追蹤選項。可以透過 CloudWatch 來監控 API 呼叫、延遲、錯誤率和快取命中率/遺失率。API Gateway 也會整合 與 AWS X-Ray 以進行分散式追蹤，並提供可自訂的記錄格式。

### Cost
<a name="w2aad101c29c46c13c11b9"></a>
+ **函數 URL** 遵循標準 Lambda 定價模型 – 您只需支付函數調用和運算時間的費用。URL 端點本身不收取額外費用。如果您不需要 API Gateway 的其他功能，這對於簡單的 API 或低流量應用程式而言是一個具成本效益的選擇。
+ **API Gateway** 提供[免費方案](https://aws.amazon.com/api-gateway/pricing/#Free_Tier)，其中包含針對 REST API 收到的一百萬個 API 呼叫，以及針對 HTTP API 收到的一百萬個 API 呼叫。之後，API Gateway 會針對 API 呼叫、資料傳輸和快取 (如果啟用) 收取費用。請參閱 API Gateway [定價頁面](https://aws.amazon.com/api-gateway/pricing/)，了解您自己的使用案例費用。

### 其他功能
<a name="w2aad101c29c46c13c11c11"></a>
+ **函數 URL** 旨在實現簡便性和直接 Lambda 整合。它們支援 HTTP 和 HTTPS 端點，提供內建 CORS 支援，並提供雙堆疊 (IPv4 和 IPv6) 端點。雖然它們缺乏進階功能，但它們在您需要快速、直接地透過 HTTP 公開 Lambda 函數時表現卓越。
+ **API Gateway** 包含許多其他功能，例如 API 版本控制、階段管理、用於用量計劃的 API 金鑰、透過 Swagger/OpenAPI 的 API 文件、WebSocket API、VPC 中的私有 API 以及 WAF 整合，以提供額外的安全性。它還支援 Canary 部署、用於測試的模擬整合，以及與 Lambda AWS 服務 以外的其他 整合。

## 選取調用 Lambda 函數的方法
<a name="w2aad101c29c46c15"></a>

現在您已了解在 Lambda 函數 URL 和 API Gateway 之間進行選擇的條件，以及它們之間的主要差異，您可以選擇最符合您需求的選項，並使用下列資源來協助您開始使用。

------
#### [ Function URLs ]

**使用下列資源開始使用函數 URL**
+ 遵循教學課程[建立具有函數 URL 的 Lambda 函數](urls-webhook-tutorial.md)
+ 在本指南的 [建立及管理 Lambda 函數 URL](urls-configuration.md) 章節中進一步了解 函數 URL
+ 透過執行以下操作，嘗試主控台內的引導式教學課程**建立簡單的 Web 應用程式**：

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇畫面右上角的圖示以開啟說明面板。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/console_help_screenshot.png)

1. 選取**教學課程**。

1. 在**建立簡單的 Web 應用程式中**，選擇**開始教學課程**。

------
#### [ API Gateway ]

**使用下列資源開始使用 Lambda 和 API Gateway**
+ 依照教學課程[搭配使用 Lambda 與 API Gateway](services-apigateway-tutorial.md) 來建立與後端 Lambda 函數整合的 REST API。
+ 在 *Amazon API Gateway 開發人員指南*的下列章節中，進一步了解 API Gateway 提供的不同類型 API：
  + [API Gateway REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html)
  + [API Gateway HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html)
  + [API Gateway WebSocket API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html)
+ 請嘗試 *Amazon API Gateway 開發人員指南*的[教學課程和研討會](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-tutorials.html)一節中的一個或多個範例。

------

# AWS Lambda 搭配 使用 AWS Infrastructure Composer
<a name="services-appcomposer"></a>

AWS Infrastructure Composer 是一種視覺化建置器，用於卸載現代應用程式 AWS。您可以透過在視覺化畫布 AWS 服務 中拖曳、分組和連線來設計應用程式架構。Infrastructure Composer 會從您的設計建立基礎設施即程式碼 (IaC) 範本，您可以使用 [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) 或 [CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) 部署。

## 將 Lambda 函數匯出至 Infrastructure Composer
<a name="services-appcomposer-export"></a>

您可以使用 Lambda 主控台根據現有 Lambda 函數的組態建立新專案，開始使用 Infrastructure Composer。若要將函數的組態和程式碼匯出至 Infrastructure Composer 以建立新專案，請執行下列動作：

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選取您希望使用做為 Infrastructure Composer 專案基礎的函數。

1. 在**函數概觀**窗格中，選擇**匯出至 Infrastructure Composer**。

   若要將函數的組態和程式碼匯出至 Infrastructure Composer，Lambda 會在您的帳戶中建立 Amazon S3 儲存貯體來暫時存放此資料。

1. 在對話方塊中，選擇**確認並建立專案**以接受此儲存貯體的預設名稱，並將函數的設定和程式碼匯出至 Infrastructure Composer。

1. (選擇性) 若要為 Lambda 建立的 Amazon S3 儲存貯體選擇其他名稱，請輸入新名稱，然後選擇**確認並建立專案**。Amazon S3 儲存貯體的名稱必須是全域唯一的，並遵循[儲存貯體命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)。

1. 若要在 Infrastructure Composer 中儲存專案和函數檔案，請啟用[本機同步模式](https://docs.aws.amazon.com/application-composer/latest/dg/reference-features-local-sync.html)。

**注意**  
如果您之前已使用**匯出至應用程式編寫器**功能，並使用預設名稱建立 Amazon S3 儲存貯體，則 Lambda 可以重複使用此儲存貯體 (如果儲存貯體仍然存在)。接受對話方塊中的預設儲存貯體名稱，以重新使用現有儲存貯體。

### Amazon S3 傳輸儲存貯體組態
<a name="services-appcomposer-bucket-info"></a>

Lambda 建立用來傳輸函數組態的 Amazon S3 儲存貯體，會使用 AES 256 加密標準的自動加密物件。Lambda 也會將儲存貯體設定為使用[儲存貯體擁有者條件](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html)，以確保只有您的 AWS 帳戶 能夠將物件新增至儲存貯體。

Lambda 會將儲存貯體設定為在上傳物件 10 天後自動刪除物件。但是，Lambda 不會自動刪除儲存貯體本身。若要從 中刪除儲存貯體 AWS 帳戶，請遵循[刪除儲存貯](https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html)體中的指示。預設儲存貯體名稱使用字首 `lambdasam`、10 位數英數字串，以及 AWS 區域 您在其中建立函數的 ：

```
lambdasam-06f22da95b-us-east-1
```

為避免將額外費用新增至您的 AWS 帳戶，我們建議您在完成將函數匯出至 Infrastructure Composer 後，立即刪除 Amazon S3 儲存貯體。

適用標準 [Amazon S3 定價](https://aws.amazon.com/s3/pricing/)。

### 所需的許可
<a name="services-appcomposer-permissions"></a>

若要使用 Lambda 與 Infrastructure Composer 功能的整合，您需要特定許可才能下載 AWS SAM 範本，並將函數的組態寫入 Amazon S3。

若要下載 AWS SAM 範本，您必須具有使用下列 API 動作的許可：
+ [GetPolicy](https://docs.aws.amazon.com/lambda/latest/api/API_GetPolicy.html)
+ [iam:GetPolicyVersion](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicyVersion.html)
+ [iam:GetRole](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetRole.html)
+ [iam:GetRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetRolePolicy.html)
+ [iam:ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html)
+ [iam:ListRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListRolePolicies.html)
+ [iam:ListRoles](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListRoles.html)

您可以將 [https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambda_ReadOnlyAccess.html](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambda_ReadOnlyAccess.html) AWS 受管政策新增至 IAM 使用者角色，以授予使用所有這些動作的許可。

若要讓 Lambda 將函數的組態寫入 Amazon S3，您必須擁有使用下列 API 動作的許可：
+ [S3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)
+ [S3:CreateBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html)
+ [S3:PutBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html)
+ [S3:PutBucketLifecycleConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html)

如果您無法將函數組態匯出至 Infrastructure Composer，請檢查您的帳戶是否具有執行這些操作所需要的許可。如果您擁有所需要的許可，但仍然無法匯出函數組態，請檢查任何可能會限制 Amazon S3 存取的[資源型政策](access-control-resource-based.md)。

## 其他資源
<a name="w2aad101c33b7"></a>

如需取得如何根據現有 Lambda 函數在 Infrastructure Composer 中設計無伺服器應用程式的詳細教學課程，請參閱[將 Lambda 搭配基礎設施即程式碼 (IaC)](foundation-iac.md)。

若要使用 Infrastructure Composer 和使用 Lambda AWS SAM 設計和部署完整的無伺服器應用程式，您也可以遵循[AWS 無伺服器模式研討會](https://catalog.workshops.aws/serverless-patterns/en-US)中的[AWS Infrastructure Composer 教學](https://catalog.workshops.aws/serverless-patterns/en-US/dive-deeper/module1a)課程。

# AWS Lambda 搭配 使用 CloudFormation
<a name="services-cloudformation"></a>

在 AWS CloudFormation 範本中，您可以將 Lambda 函數指定為自訂資源的目標。使用自訂資源來處理參數、擷取組態值，或在堆疊生命週期事件 AWS 服務 期間呼叫其他 。

下列範例叫用在範本中其他地方定義的函數。

**Example - 自訂資源定義**  

```
Resources:
  primerinvoke:
    Type: [AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cfn-customresource.html)
    Version: "1.0"
    Properties:
      ServiceToken: !GetAtt primer.Arn
      FunctionName: !Ref randomerror
```

服務權杖是函數的 Amazon Resource Name (ARN)，在您建立、更新或刪除堆疊時 CloudFormation 叫用該函數。您也可以包含其他屬性，例如 `FunctionName`，這些屬性會照原樣 CloudFormation 傳遞給您的函數。

CloudFormation 使用包含回呼 URL 的事件[非同步](invocation-async.md)叫用 Lambda 函數。

**Example – CloudFormation 訊息事件**  

```
{
    "RequestType": "Create",
    "ServiceToken": "arn:aws:lambda:us-east-1:123456789012:function:lambda-error-processor-primer-14ROR2T3JKU66",
    "ResponseURL": "https://cloudformation-custom-resource-response-useast1.s3-us-east-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-1%3A123456789012%3Astack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456%7Cprimerinvoke%7C5d478078-13e9-baf0-464a-7ef285ecc786?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Expires=1555451971&Signature=28UijZePE5I4dvukKQqM%2F9Rf1o4%3D",
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456",
    "RequestId": "5d478078-13e9-baf0-464a-7ef285ecc786",
    "LogicalResourceId": "primerinvoke",
    "ResourceType": "AWS::CloudFormation::CustomResource",
    "ResourceProperties": {
        "ServiceToken": "arn:aws:lambda:us-east-1:123456789012:function:lambda-error-processor-primer-14ROR2T3JKU66",
        "FunctionName": "lambda-error-processor-randomerror-ZWUC391MQAJK"
    }
}
```

函式負責回傳回應到回呼 URL，說明呼叫成功或失敗。如需完整的回應語法，請參閱[自訂資源回應物件](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html)。

**Example – CloudFormation 自訂資源回應**  

```
{
    "Status": "SUCCESS",
    "PhysicalResourceId": "2019/04/18/[$LATEST]b3d1bfc65f19ec610654e4d9b9de47a0",
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456",
    "RequestId": "5d478078-13e9-baf0-464a-7ef285ecc786",
    "LogicalResourceId": "primerinvoke"
}
```

CloudFormation 提供名為 的程式庫`cfn-response`，可處理傳送回應。如果您在範本中定義函數，您可以要求程式庫名稱。 CloudFormation 然後， 會將程式庫新增至其為函數建立的部署套件。

如果自訂資源使用的函數已連接[彈性網路介面](configuration-vpc.md#configuration-vpc-enis)，則請將下列資源新增至 VPC 政策，其中 **region** 是函數所在的區域 (不含破折號)。例如，`us-east-1` 為 `useast1`。這將允許自訂資源回應將訊號傳回 CloudFormation 堆疊的回呼 URL。

```
arn:aws:s3:::cloudformation-custom-resource-response-region",
"arn:aws:s3:::cloudformation-custom-resource-response-region/*",
```

下列的範例函式會叫用第二個函式。如果呼叫成功，函數會傳送成功回應給 CloudFormation，且堆疊更新會繼續。範本使用 AWS Serverless Application Model提供的 [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html) 資源類型。

**Example – 自訂資源函數**  

```
Transform: 'AWS::Serverless-2016-10-31'
Resources:
  primer:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      Handler: index.handler
      Runtime: nodejs16.x
      InlineCode: |
        var aws = require('aws-sdk');
        var response = require('cfn-response');
        exports.handler = function(event, context) {
            // For Delete requests, immediately send a SUCCESS response.
            if (event.RequestType == "Delete") {
                response.send(event, context, "SUCCESS");
                return;
            }
            var responseStatus = "FAILED";
            var responseData = {};
            var functionName = event.ResourceProperties.FunctionName
            var lambda = new aws.Lambda();
            lambda.invoke({ FunctionName: functionName }, function(err, invokeResult) {
                if (err) {
                    responseData = {Error: "Invoke call failed"};
                    console.log(responseData.Error + ":\n", err);
                }
                else responseStatus = "SUCCESS";
                response.send(event, context, responseStatus, responseData);
            });
        };
      Description: Invoke a function to create a log stream.
      MemorySize: 128
      Timeout: 8
      Role: !GetAtt role.Arn
      Tracing: Active
```

如果未在範本中定義自訂資源叫用的函數，您可以從 AWS CloudFormation 《 使用者指南》中的 `cfn-response` [cfn-response 模組](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html)取得 的原始程式碼。

如需自訂資源的詳細資訊，請參閱 *AWS CloudFormation 使用者指南*中的[自訂資源](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html)。

# 使用 Lambda 處理 Amazon DocumentDB 事件
<a name="with-documentdb"></a>

您可以透過將 Amazon DocumentDB 叢集設定為事件來源，使用 Lambda 函數處理 [Amazon DocumentDB (with MongoDB compatibility) 變更串流](https://docs.aws.amazon.com/documentdb/latest/developerguide/change_streams.html)中的事件。接著，您可以在每次使用 Amazon DocumentDB 叢集變更資料時，調用 Lambda 函數來自動執行事件驅動的工作負載。

**注意**  
Lambda 僅支援 Amazon DocumentDB 4.0 和 5.0 版。Lambda 不支援 3.6 版。  
此外，針對事件來源映射，Lambda 僅支援執行個體型叢集和區域叢集。Lambda 不支援 [彈性叢集](https://docs.aws.amazon.com/documentdb/latest/developerguide/docdb-using-elastic-clusters.html) 或 [全域叢集](https://docs.aws.amazon.com/documentdb/latest/developerguide/global-clusters.html)。使用 Lambda 做為用戶端連線至 Amazon DocumentDB 時不適用此限制。Lambda 可以連線至所有叢集類型來執行 CRUD 操作。

Lambda 會依照抵達的順序處理來自 Amazon DocumentDB 變更串流的事件。因此，函數一次只能處理來自 Amazon DocumentDB 的一個並行調用。若要監控函數，您可以追蹤其[並行指標](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-concurrency.html)。

**警告**  
Lambda 事件來源映射至少會處理每個事件一次，而且可能會重複處理記錄。為避免與重複事件相關的潛在問題，強烈建議您讓函數程式碼具有等冪性。若要進一步了解，請參閱 AWS 知識中心中的[如何使 Lambda 函數具有等冪性](https://repost.aws/knowledge-center/lambda-function-idempotent)。

**Topics**
+ [

## Amazon DocumentDB 事件範例
](#docdb-sample-event)
+ [

## 先決條件和許可
](#docdb-prereqs)
+ [

## 設定網路安全
](#docdb-network)
+ [

## 建立 Amazon DocumentDB 事件來源映射 (主控台)
](#docdb-configuration)
+ [

## 建立 Amazon DocumentDB 事件來源映射 (SDK 或 CLI)
](#docdb-api)
+ [

## 輪詢和串流開始位置
](#docdb-stream-polling)
+ [

## 監控 Amazon DocumentDB 事件來源
](#docdb-monitoring)
+ [

# 教學課程： AWS Lambda 搭配 Amazon DocumentDB Streams 使用
](with-documentdb-tutorial.md)

## Amazon DocumentDB 事件範例
<a name="docdb-sample-event"></a>

```
{
    "eventSourceArn": "arn:aws:rds:us-east-1:123456789012:cluster:canaryclusterb2a659a2-qo5tcmqkcl03",
    "events": [
        {
            "event": {
                "_id": {
                    "_data": "0163eeb6e7000000090100000009000041e1"
                },
                "clusterTime": {
                    "$timestamp": {
                        "t": 1676588775,
                        "i": 9
                    }
                },
                "documentKey": {
                    "_id": {
                        "$oid": "63eeb6e7d418cd98afb1c1d7"
                    }
                },
                "fullDocument": {
                    "_id": {
                        "$oid": "63eeb6e7d418cd98afb1c1d7"
                    },
                    "anyField": "sampleValue"
                },
                "ns": {
                    "db": "test_database",
                    "coll": "test_collection"
                },
                "operationType": "insert"
            }
        }
    ],
    "eventSource": "aws:docdb"
}
```

如需有關此範例中事件及其形狀的詳細資訊，請參閱 MongoDB 文件網站上的[變更事件](https://www.mongodb.com/docs/manual/reference/change-events/)。

## 先決條件和許可
<a name="docdb-prereqs"></a>

將 Amazon DocumentDB 作為 Lambda 函數的事件來源使用前，請留意以下先決條件。您必須：
+ **在與函數相同的 AWS 帳戶 和 中擁有現有的 Amazon DocumentDB AWS 區域 叢集。**如果您沒有現有叢集，則可以按照*《Amazon DocumentDB 開發人員指南》*中[開始使用 Amazon DocumentDB](https://docs.aws.amazon.com/documentdb/latest/developerguide/get-started-guide.html)所述步驟建立叢集。或者，[教學課程： AWS Lambda 搭配 Amazon DocumentDB Streams 使用](with-documentdb-tutorial.md) 中的第一組步驟會引導您建立包含所有必要先決條件的 Amazon DocumentDB 叢集。
+ **允許 Lambda 存取與您 Amazon DocumentDB 叢集相關聯的 Amazon Virtual Private Cloud (Amazon VPC) 資源。**如需詳細資訊，請參閱[設定網路安全](#docdb-network)。
+ **在您的 Amazon DocumentDB 叢集上啟用 TLS。**這是預設設定。若停用 TLS，Lambda 將無法與您的叢集進行通訊。
+ **啟用 Amazon DocumentDB 叢集上的變更串流。**如需詳細資訊，請參閱*《Amazon DocumentDB 開發人員指南》*中的[透過 Amazon DocumentDB 使用變更串流](https://docs.aws.amazon.com/documentdb/latest/developerguide/change_streams.html) 。
+ **為 Lambda 提供憑證以存取您的 Amazon DocumentDB 叢集。**設定事件來源時，請提供包含存取叢集所需驗證詳細資料 (使用者名稱和密碼) 的 [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 金鑰。若要在設定期間提供此金鑰，請執行下列其中一項操作：
  + 如果您要使用 Lambda 主控台進行設定，請在 **Secrets Manager 金鑰**欄位中提供此金鑰。
  + 如果您使用 AWS Command Line Interface (AWS CLI) 進行設定，請在 `source-access-configurations`選項中提供此金鑰。您可以連同 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 或 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 命令包括此選項。例如：

    ```
    aws lambda create-event-source-mapping \
        ...
        --source-access-configurations  '[{"Type":"BASIC_AUTH","URI":"arn:aws:secretsmanager:us-west-2:123456789012:secret:DocDBSecret-AbC4E6"}]' \
        ...
    ```
+ **您必須向 Lambda 授與許可，才能管理與 Amazon DocumentDB 串流相關的資源。**將下列許可手動新增到函數的 [執行角色](lambda-intro-execution-role.md)：
  + [rds:DescribeDBClusters](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusters.html)
  + [rds:DescribeDBClusterParameters](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusterParameters.html)
  + [rds:DescribeDBSubnetGroups](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBSubnetGroups.html)
  + [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
  + [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
  + [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
  + [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
  + [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
  + [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
  + [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)
  + [secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)
+ **傳送至 Lambda 的 Amazon DocumentDB 變更串流事件大小請勿超過 6 MB。**Lambda 支援的承載大小上限為 6MB。如果變更串流嘗試向 Lambda 傳送大於 6MB 的事件，Lambda 會捨棄訊息並發出 `OversizedRecordCount` 指標。Lambda 會盡力發送所有指標。

**注意**  
雖然 Lambda 函數的逾時上限通常為 15 分鐘，但 Amazon MSK、自我管理的 Apache Kafka、Amazon DocumentDB 以及 Amazon MQ for ActiveMQ 和 Amazon MQ for RabbitMQ 的事件來源映射只支援 14 分鐘逾時限制上限的函數。此限制條件可確保事件來源映射能夠正確處理函數錯誤和重試。

## 設定網路安全
<a name="docdb-network"></a>

若要透過事件來源映射授予 Lambda 對 Amazon DocumentDB 的完整存取權，您的叢集必須使用公有端點 (公有 IP 位址)，或者您必須提供建立叢集之 Amazon VPC 的存取權。

當您將 Amazon DocumentDB 與 Lambda 搭配使用時，請建立 [AWS PrivateLink VPC 端點](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html)，為您的函數提供 Amazon VPC 中資源的存取權。

**注意**  
AWS PrivateLink 具有使用事件輪詢器預設 （隨需） 模式之事件來源映射的函數需要 VPC 端點。如果您的事件來源映射使用[佈建模式](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)，則不需要設定 AWS PrivateLink VPC 端點。

建立端點以提供對下列資源的存取權：
+  Lambda：為 Lambda 服務主體建立端點。
+  AWS STS — 為 建立端點， AWS STS 以便服務主體代表您擔任角色。
+  Secrets Manager：如果您的叢集使用 Secrets Manager 來儲存憑證，則請為 Secrets Manager 建立端點。

或者，在 Amazon VPC 中的每個公有子網路上設定一個 NAT 閘道。如需詳細資訊，請參閱[啟用 VPC 連線的 Lambda 函數的網際網路存取](configuration-vpc-internet.md)。

當您為 Amazon DocumentDB 建立事件來源映射時，Lambda 會檢查是否已存在彈性網絡介面 (ENI)，適用於為您的 Amazon VPC 設定的子網路和安全群組。如果 Lambda 找到現有的 ENI，它會嘗試重複使用它們。否則，Lambda 會建立新的 ENI 以連線至事件來源並調用您的函數。

**注意**  
Lambda 函數一律會在 Lambda 服務所擁有的 VPC 內執行。函數的 VPC 組態不會影響事件來源映射。只有事件來源的聯網組態會決定 Lambda 如何連線至您的事件來源。

為包含叢集的 Amazon VPC 設定安全群組。依預設，Amazon DocumentDB 會使用下列連接埠：`27017`。
+ 傳入規則：允許與事件來源相關聯之安全群組的預設代理程式連接埠上的所有流量。或者，您可使用自我參照安全群組規則，允許來自同一安全群組內其他執行個體的存取。
+ 傳出規則 – 如果您的函數需要與服務通訊`443`，允許外部目的地連接埠上的所有流量 AWS 。或者，如果您不需要與其他 AWS 服務通訊，您也可以使用自我參考安全群組規則來限制對代理程式的存取。
+ Amazon VPC 端點傳入規則：如果您使用的是 Amazon VPC 端點，與您的 Amazon VPC 端點相關聯的安全群組必須允許來自叢集安全群組的連接埠 `443` 上的傳入流量。

如果您的叢集使用身分驗證，則您也可以限制 Secrets Manager 端點的端點政策。若要呼叫 Secrets Manager API，Lambda 會使用您的函數角色，而不是 Lambda 服務主體。

**Example VPC 端點政策 — Secrets Manager 端點**  

```
{
      "Statement": [
          {
              "Action": "secretsmanager:GetSecretValue",
              "Effect": "Allow",
              "Principal": {
                  "AWS": [
                      "arn:aws::iam::123456789012:role/my-role"
                  ]
              },
              "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
          }
      ]
  }
```

當您使用 Amazon VPC 端點時， 會使用端點的彈性網路界面 (ENI) AWS 路由您的 API 呼叫來叫用函數。Lambda 服務主體需要在使用這些 ENI 的任何角色和函數上呼叫 `lambda:InvokeFunction`。

根據預設，Amazon VPC 端點具有開放的 IAM 政策，允許廣泛存取資源。最佳實務是限制這些政策，以使用該端點執行所需的動作。為了確保事件來源映射能夠調用 Lambda 函數，VPC 端點政策必須允許 Lambda 服務主體呼叫 `sts:AssumeRole` 和 `lambda:InvokeFunction`。限制您的 VPC 端點政策以僅允許源自您組織內部的 API 呼叫，可阻止事件來源映射正常運作，因此在這些政策中需要 `"Resource": "*"`。

下列範例 VPC 端點政策展示了如何授予 Lambda 服務主體對 AWS STS 和 Lambda 端點的必要存取權。

**Example VPC 端點政策 — AWS STS 端點**  

```
{
      "Statement": [
          {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
    }
```

**Example VPC 端點政策 – Lambda 端點**  

```
{
      "Statement": [
          {
              "Action": "lambda:InvokeFunction",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
  }
```

## 建立 Amazon DocumentDB 事件來源映射 (主控台)
<a name="docdb-configuration"></a>

若要讓 Lambda 函數從 Amazon DocumentDB 叢集的變更串流中讀取，請建立 DocumentDB [事件來源映射](invocation-eventsourcemapping.md)。本節會說明如何透過 Lambda 主控台執行這項操作。如需 AWS SDK 和 AWS CLI 說明，請參閱 [建立 Amazon DocumentDB 事件來源映射 (SDK 或 CLI)](#docdb-api)。

**建立 Amazon DocumentDB 事件來源映射 (主控台)**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函數的名稱。

1. 在 **函式概觀** 下，選擇 **新增觸發條件** 。

1. 在**觸發條件組態**底下的下拉式清單中，選擇 **DocumentDB**。

1. 設定需要的選項，然後選擇**新增**。

Lambda 支援以下 Amazon DocumentDB 事件來源的選項：
+ **DocumentDB 叢集**：選取 Amazon DocumentDB 叢集。
+ **啟用觸發條件**：選擇您是否要立即啟用觸發條件。若勾選此核取方塊，您的函數會在建立事件來源映射時立即開始接收來自指定 Amazon DocumentDB 變更串流的流量。建議您取消勾選此核取方塊，以便在停用狀態下建立事件來源映射來進行測試。完成建立後，您隨時可以啟動事件來源映射。
+ **資料庫名稱：** 輸入叢集內要使用的資料庫名稱。
+ (選用) **集合名稱**：輸入資料庫內要使用的集合名稱。如果您未指定集合，Lambda 會偵聽資料庫中每個集合中的所有事件。
+ **批次大小：** 設定單一批次中要擷取的訊息數目上限 (最高 10,000)。預設批次大小為 100。
+ **開始位置：** 選擇串流中要從中開始讀取記錄的位置。
  + **最新：** 僅處理已新增到串流的新記錄。Lambda 建立完事件來源後，您的函數才會開始處理記錄。這表示系統可能會捨棄部分記錄，直到您的事件來源成功建立為止。
  + **水平修剪** - 處理所有在串流中的記錄。Lambda 會透過叢集的日誌保留持續時間來決定開始讀取事件的時間點。具體來說，Lambda 會從 `current_time - log_retention_duration` 開始進行讀取。變更串流必須在此時間戳記前處於作用中狀態，Lambda 才能正確讀取所有事件。
  + **At timestamp (在時間戳記為)** - 從特定時間開始處理記錄。變更串流必須在指定時間戳記前處於作用中狀態，Lambda 才能正確讀取所有事件。
+ **身分驗證：** 選擇在叢集中存取中介裝置的身分驗證方式。
  + **BASIC\$1AUTH：** 使用基本身分驗證下，您必須提供含有憑證的 Secrets Manager 金鑰，才能存取叢集。
+ **Secrets Manager 金鑰**：選擇含有存取 Amazon DocumentDB 叢集所需身分驗證詳細資料 (使用者名稱和密碼) 的 Secrets Manager 金鑰。
+ (選用) **批次間隔**：在調用函數前收集記錄的最長時間 (秒)，上限為 300 秒。
+ (選用) **完整文件組態**：文件更新作業方面，請選擇要傳送至串流的內容。預設值為 `Default`，這表示 Amazon DocumentDB 針對每個變更串流事件僅會傳送說明所做變更的差異。如需有關此欄位的詳細資訊，請參閱 MongoDB Javadoc API 文件中的 [FullDocument](https://mongodb.github.io/mongo-java-driver/3.9/javadoc/com/mongodb/client/model/changestream/FullDocument.html#DEFAULT)。
  + **預設：** Lambda 僅會傳送說明所做變更的部分文件。
  + **UpdateLookup：** Lambda 會傳送說明變更的差異，以及整個文件的副本。

## 建立 Amazon DocumentDB 事件來源映射 (SDK 或 CLI)
<a name="docdb-api"></a>

若要使用 [AWS SDK](https://aws.amazon.com/developer/tools/) 來建立或管理 Amazon DocumentDB 事件來源映射，您可以使用下列 API 操作：
+ [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html)
+ [ListEventSourceMappings](https://docs.aws.amazon.com/lambda/latest/api/API_ListEventSourceMappings.html)
+ [GetEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_GetEventSourceMapping.html)
+ [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)
+ [DeleteEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_DeleteEventSourceMapping.html)

若要使用 建立事件來源映射 AWS CLI，請使用 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html)命令。以下範例使用此命令，將名為 `my-function` 的函數映射至 Amazon DocumentDB 變更串流。事件來源是由 Amazon Resource Name (ARN) 指定，批次大小為 500，且開始時間為 Unix 時間的時間戳記。此命令也會指定 Lambda 用來連線至 Amazon DocumentDB 的 Secrets Manager 金鑰。此外也包括 `document-db-event-source-config` 參數，這個參數指定了要從哪個資料庫和集合讀取。

```
aws lambda create-event-source-mapping --function-name my-function \
    --event-source-arn arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy
    --batch-size 500 \
    --starting-position AT_TIMESTAMP \
    --starting-position-timestamp 1541139109 \
    --source-access-configurations '[{"Type":"BASIC_AUTH","URI":"arn:aws:secretsmanager:us-east-1:123456789012:secret:DocDBSecret-BAtjxi"}]' \
    --document-db-event-source-config '{"DatabaseName":"test_database", "CollectionName": "test_collection"}' \
```

您應該會看到類似下面的輸出：

```
{
    "UUID": "2b733gdc-8ac3-cdf5-af3a-1827b3b11284",
    "BatchSize": 500,
    "DocumentDBEventSourceConfig": {
        "CollectionName": "test_collection",
        "DatabaseName": "test_database",
        "FullDocument": "Default"
    },
    "MaximumBatchingWindowInSeconds": 0,
    "EventSourceArn": "arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy",
    "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:my-function",
    "LastModified": 1541348195.412,
    "LastProcessingResult": "No records processed",
    "State": "Creating",
    "StateTransitionReason": "User action"
}
```

完成建立後，您可以使用 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 命令來更新 Amazon DocumentDB 事件來源的設定。以下命令將批次大小更新為 1,000，並將批次間格更新為 10 秒。對於此命令，您必須擁有事件來源映射的 UUID (可使用 `list-event-source-mapping` 命令或 Lambda 主控台擷取)。

```
aws lambda update-event-source-mapping --function-name my-function \
    --uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
    --batch-size 1000 \
    --batch-window 10
```

您應該會看到類似以下內容的輸出：

```
{
    "UUID": "2b733gdc-8ac3-cdf5-af3a-1827b3b11284",
    "BatchSize": 500,
    "DocumentDBEventSourceConfig": {
        "CollectionName": "test_collection",
        "DatabaseName": "test_database",
        "FullDocument": "Default"
    },
    "MaximumBatchingWindowInSeconds": 0,
    "EventSourceArn": "arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy",
    "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:my-function",
    "LastModified": 1541359182.919,
    "LastProcessingResult": "OK",
    "State": "Updating",
    "StateTransitionReason": "User action"
}
```

Lambda 會以非同步方式更新設定，因此處理完成之前您可能無法在輸出中看到這些變更。若要檢視事件來源映射的目前設定，請使用 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) 命令。

```
aws lambda get-event-source-mapping --uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b
```

您應該會看到類似以下內容的輸出：

```
{
    "UUID": "2b733gdc-8ac3-cdf5-af3a-1827b3b11284",
    "DocumentDBEventSourceConfig": {
        "CollectionName": "test_collection",
        "DatabaseName": "test_database",
        "FullDocument": "Default"
    },
    "BatchSize": 1000,
    "MaximumBatchingWindowInSeconds": 10,
    "EventSourceArn": "arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy",
    "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:my-function",
    "LastModified": 1541359182.919,
    "LastProcessingResult": "OK",
    "State": "Enabled",
    "StateTransitionReason": "User action"
}
```

若要刪除 Amazon DocumentDB 事件來源映射，請使用 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/delete-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/delete-event-source-mapping.html) 命令。

```
aws lambda delete-event-source-mapping \
    --uuid 2b733gdc-8ac3-cdf5-af3a-1827b3b11284
```

## 輪詢和串流開始位置
<a name="docdb-stream-polling"></a>

請注意，建立和更新事件來源映射期間的串流輪詢最終會一致。
+ 在建立事件來源映射期間，從串流開始輪詢事件可能需要幾分鐘時間。
+ 在更新事件來源映射期間，從串流停止並重新開始輪詢事件可能需要幾分鐘時間。

這種行為表示如果您指定 `LATEST` 當作串流的開始位置，事件來源映射可能會在建立或更新期間遺漏事件。若要確保沒有遺漏任何事件，請將串流開始位置指定為 `TRIM_HORIZON` 或 `AT_TIMESTAMP`。

## 監控 Amazon DocumentDB 事件來源
<a name="docdb-monitoring"></a>

為協助您監控 Amazon DocumentDB 事件來源，Lambda 會在您的函數處理完一批記錄後發出 `IteratorAge` 指標。*迭代器存留期*是最近事件和目前時間戳記之間的差距。基本上，`IteratorAge` 指標會指出批次中最後處理的記錄經過了多久的時間。如果函數目前正在處理新的事件，可使用迭代器存留期來預估記錄新增與函數實際處理之間的延遲。從 `IteratorAge` 的增加趨勢可看出您函數的問題。如需詳細資訊，請參閱[將 CloudWatch 指標與 Lambda 搭配使用](monitoring-metrics.md)。

Amazon DocumentDB 變更串流未最佳化，無法處理事件之間的大量時間間隔。如果 Amazon DocumentDB 事件來源長時間未收到任何事件，Lambda 可能會停用事件來源映射。此期間長度可能從幾週到幾個月不等，取決於叢集大小和其他工作負載。

Lambda 支援的承載上限為 6MB。不過，Amazon DocumentDB 變更串流事件的大小可達 16MB。如果變更串流嘗試向 Lambda 傳送大於 6MB 的變更串流事件，Lambda 會捨棄訊息並發出 `OversizedRecordCount` 指標。Lambda 會盡力發送所有指標。

# 教學課程： AWS Lambda 搭配 Amazon DocumentDB Streams 使用
<a name="with-documentdb-tutorial"></a>

 在本教學課程中，您將建立一個基礎 Lambda 函數，它會從 Amazon DocumentDB (with MongoDB compatibility) 變更串流中取用事件。完成本教學課程需逐一進行以下階段：
+ 設定您的 Amazon DocumentDB 叢集、連線到叢集，然後在叢集上啟用變更串流。
+ 建立 Lambda 函數，並將 Amazon DocumentDB 叢集設定為函數的事件來源。
+ 將項目插入 Amazon DocumentDB 資料庫中，即可測試設定。

## 建立 Amazon DocumentDB 叢集
<a name="docdb-documentdb-cluster"></a>

1. 開啟 [Amazon DocumentDB 主控台](https://console.aws.amazon.com/docdb/home#)。在**叢集**下，選擇**建立**。

1. 使用下列組態建立叢集：
   + 在**叢集類型**欄位中，選擇**執行個體型叢集**。此為預設選項。
   + 在**叢集組態**欄位中，確保已選取**引擎版本** 5.0.0。此為預設選項。
   + 在**執行個體組態**欄位中：
     + 在**資料庫執行個體類別**欄位中，選取**記憶體最佳化類別**。此為預設選項。
     + 在**常規複本執行個體數量**欄位中，選擇 1。
     + 在**執行個體類別**欄位中，使用預設選項。
   + 在**身分驗證**欄位中，輸入主要使用者的使用者名稱，然後選擇**自我管理**。輸入密碼，然後進行確認。
   + 請保留所有其他預設設定。

1. 選擇 **Create Cluster** (建立叢集)。

## 在 Secrets Manager 中建立密碼
<a name="docdb-secret-in-secrets-manager"></a>

當 Amazon DocumentDB 正在建立叢集時，請建立 AWS Secrets Manager 秘密來存放資料庫登入資料。在後續步驟中建立 Lambda 事件來源映射時，您需要提供此秘密。

**在 Secrets Manager 中建立密碼**

1. 開啟 [Secrets Manager](https://console.aws.amazon.com/secretsmanager/home#) 主控台，並選擇**儲存新密碼**。

1. 針對**選擇密碼類型**，選擇以下選項：
   + 在**基本詳細資訊**下：
     + **密碼類型**：Amazon DocumentDB 資料庫的憑證
     + 在**憑證**欄位中，輸入用於建立 Amazon DocumentDB 叢集的相同使用者名稱與密碼。
     + **資料庫**：選擇您的 Amazon DocumentDB 叢集。
     + 選擇**下一步**。

1. 針對**設定密碼**，選擇下列選項：
   + **秘密名稱**：`DocumentDBSecret`
   + 選擇**下一步**。

1. 選擇**下一步**。

1. 選擇**儲存**。

1. 重新整理主控台以確認您已成功儲存 `DocumentDBSecret` 密碼。

請記錄**秘密 ARN**。在後續步驟中需要它。

## 連線至叢集
<a name="docdb-connect-to-cluster"></a>

**使用 連線至您的 Amazon DocumentDB 叢集 AWS CloudShell**

1. 在 Amazon DocumentDB 管理主控台的**叢集**下，找到已建立的叢集。按一下叢集旁的核取方塊，選擇對應叢集。

1. 選擇**連線至叢集**。CloudShell **執行命令**畫面隨即顯示。

1. 在**新增環境名稱**欄位中，輸入唯一名稱 (例如 "test")，然後選擇**建立並執行**。

1. 出現提示時，輸入您的密碼。當提示變為 `rs0 [direct: primary] <env-name>>`，表示已成功連線至 Amazon DocumentDB 叢集。

## 啟用變更串流
<a name="docdb-activate-change-streams"></a>

在本教學課程中，您將追蹤 Amazon DocumentDB 叢集中 `docdbdemo` 資料庫 `products` 集合的變更。可以透過啟用[變更串流](https://docs.aws.amazon.com/documentdb/latest/developerguide/change_streams.html)來完成此操作。

**在叢集內建立新資料庫**

1. 執行下列命令，建立名為 `docdbdemo` 的新資料庫：

   ```
   use docdbdemo
   ```

1. 在終端機視窗中，使用下列命令將記錄插入 `docdbdemo`：

   ```
   db.products.insertOne({"hello":"world"})
   ```

   您應該會看到如下所示的輸出：

   ```
   {
     acknowledged: true,
     insertedId: ObjectId('67f85066ca526410fd531d59')
   }
   ```

1. 接下來，使用以下命令在 `docdbdemo` 資料庫的 `products` 集合上啟用變更串流：

   ```
   db.adminCommand({modifyChangeStreams: 1,
       database: "docdbdemo",
       collection: "products", 
       enable: true});
   ```

    您應該會看到類似下面的輸出：

   ```
   { "ok" : 1, "operationTime" : Timestamp(1680126165, 1) }
   ```

## 建立介面 VPC 端點
<a name="docdb-create-interface-vpc-endpoints"></a>

接下來，建立[介面 VPC 端點](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html#create-interface-endpoint-aws)，以確保 Lambda 和 Secrets Manager (稍後用來儲存我們的叢集存取憑證) 可以連線到您的預設 VPC。

**建立介面 VPC 端點**

1. 開啟 [VPC 主控台](https://console.aws.amazon.com/vpc/home#)。在左側選單的**虛擬私有雲端**下，選擇**端點**。

1. 選擇**建立端點**。使用下列組態建立端點：
   + 針對**名稱標籤**，輸入 `lambda-default-vpc`。
   + 針對**服務類別**，選擇 AWS 服務。
   + 針對**服務**，在搜尋方塊中輸入 `lambda`。選擇格式為 `com.amazonaws.<region>.lambda` 的服務。
   + 在 **VPC** 欄位中，選擇 Amazon DocumentDB 叢集所在的 VPC。這通常是[預設 VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html)。
   + 針對**子網路**，請核取每個可用區域旁邊的方塊。請選擇每個可用區域的正確子網路。
   + 針對 **IP 地址類型**，請選擇 IPv4。
   + 在**安全群組**欄位中，選擇 Amazon DocumentDB 叢集所使用的安全群組。這通常是 `default` 安全群組。
   + 請保留所有其他預設設定。
   + 選擇**建立端點**。

1. 再次選擇**建立端點**。使用下列組態建立端點：
   + 針對**名稱標籤**，輸入 `secretsmanager-default-vpc`。
   + 針對**服務類別**，選擇 AWS 服務。
   + 針對**服務**，在搜尋方塊中輸入 `secretsmanager`。選擇格式為 `com.amazonaws.<region>.secretsmanager` 的服務。
   + 在 **VPC** 欄位中，選擇 Amazon DocumentDB 叢集所在的 VPC。這通常是[預設 VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html)。
   + 針對**子網路**，請核取每個可用區域旁邊的方塊。請選擇每個可用區域的正確子網路。
   + 針對 **IP 地址類型**，請選擇 IPv4。
   + 在**安全群組**欄位中，選擇 Amazon DocumentDB 叢集所使用的安全群組。這通常是 `default` 安全群組。
   + 請保留所有其他預設設定。
   + 選擇**建立端點**。

 這就完成了本教學課程的叢集設定部分。

## 建立執行角色
<a name="docdb-create-the-execution-role"></a>

 在接下來的一組步驟中，您將建立 Lambda 函數。首先，您需要建立授予函數存取叢集許可的執行角色。您可先建立 IAM 政策，然後將此政策連接到 IAM 角色。

**建立 IAM 政策**

1. 開啟 IAM 主控台的[政策頁面](https://console.aws.amazon.com/iam/home#/policies)，並選擇**建立政策**。

1. 選擇 **JSON** 標籤。在下列政策中，將陳述式最後一行中的 Secrets Manager 資源 ARN 取代為先前的密碼 ARN，並將政策複製到編輯器中。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "LambdaESMNetworkingAccess",
               "Effect": "Allow",
               "Action": [
                   "ec2:CreateNetworkInterface",
                   "ec2:DescribeNetworkInterfaces",
                   "ec2:DescribeVpcs",
                   "ec2:DeleteNetworkInterface",
                   "ec2:DescribeSubnets",
                   "ec2:DescribeSecurityGroups",
                   "kms:Decrypt"
               ],
               "Resource": "*"
           },
           {
               "Sid": "LambdaDocDBESMAccess",
               "Effect": "Allow",
               "Action": [
                   "rds:DescribeDBClusters",
                   "rds:DescribeDBClusterParameters",
                   "rds:DescribeDBSubnetGroups"
               ],
               "Resource": "*"
           },
           {
               "Sid": "LambdaDocDBESMGetSecretValueAccess",
               "Effect": "Allow",
               "Action": [
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:DocumentDBSecret"
           }
       ]
   }
   ```

------

1. 選擇**下一步：標籤**，然後選擇**下一步：檢閱**。

1. 對於 **Name** (名稱)，輸入 `AWSDocumentDBLambdaPolicy`。

1. 選擇**建立政策**。

**建立 IAM 角色**

1. 開啟 IAM 主控台的[角色](https://console.aws.amazon.com/iam/home#/roles)頁面，然後選擇**建立角色**。

1. 針對**選取信任的實體**，請選擇以下選項：
   + **信任的實體類型**： AWS 服務
   + **服務或使用案例**：Lambda
   + 選擇**下一步**。

1. 針對**新增許可**，請選擇您剛建立的 `AWSDocumentDBLambdaPolicy` 政策以及 `AWSLambdaBasicExecutionRole`，授予函數寫入 Amazon CloudWatch Logs 的許可。

1. 選擇**下一步**。

1. 在**角色名稱**中，輸入 `AWSDocumentDBLambdaExecutionRole`。

1. 選擇建**立角色**。

## 建立 Lambda 函式
<a name="docdb-create-the-lambda-function"></a>

本教學課程使用 Python 3.14 執行時間，但我們也提供其他執行時間的範例程式碼檔案。您可以在下列方塊中選取索引標籤，查看您感興趣的執行期程式碼。

程式碼會接收 Amazon DocumentDB 事件輸入，並處理其包含的訊息。

**建立 Lambda 函數**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇**建立函數**。

1. 選擇**從頭開始撰寫**

1. 在**基本資訊**下，請執行下列動作：

   1. 在**函數名稱**輸入 `ProcessDocumentDBRecords`

   1. 針對**執行期**，選擇 **Python 3.14。**

   1. 對於 **Architecture** (架構)，選擇 **x86\$164**。

1. 在**變更預設執行角色**索引標籤中，執行下列操作：

   1. 展開索引標籤，然後選擇**使用現有角色**。

   1. 選擇您之前建立的 `AWSDocumentDBLambdaExecutionRole`。

1. 選擇**建立函數**。

**部署函數程式碼**

1. 在以下方塊中選擇 **Python** 索引標籤，然後複製程式碼。

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   using Amazon.Lambda.Core;
   using System.Text.Json;
   using System;
   using System.Collections.Generic;
   using System.Text.Json.Serialization;
   //Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
   [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
   
   namespace LambdaDocDb;
   
   public class Function
   {
       
        /// <summary>
       /// Lambda function entry point to process Amazon DocumentDB events.
       /// </summary>
       /// <param name="event">The Amazon DocumentDB event.</param>
       /// <param name="context">The Lambda context object.</param>
       /// <returns>A string to indicate successful processing.</returns>
       public string FunctionHandler(Event evnt, ILambdaContext context)
       {
           
           foreach (var record in evnt.Events)
           {
               ProcessDocumentDBEvent(record, context);
           }
   
           return "OK";
       }
   
        private void ProcessDocumentDBEvent(DocumentDBEventRecord record, ILambdaContext context)
       {
           
           var eventData = record.Event;
           var operationType = eventData.OperationType;
           var databaseName = eventData.Ns.Db;
           var collectionName = eventData.Ns.Coll;
           var fullDocument = JsonSerializer.Serialize(eventData.FullDocument, new JsonSerializerOptions { WriteIndented = true });
   
           context.Logger.LogLine($"Operation type: {operationType}");
           context.Logger.LogLine($"Database: {databaseName}");
           context.Logger.LogLine($"Collection: {collectionName}");
           context.Logger.LogLine($"Full document:\n{fullDocument}");
       }
   
   
   
       public class Event
       {
           [JsonPropertyName("eventSourceArn")]
           public string EventSourceArn { get; set; }
   
           [JsonPropertyName("events")]
           public List<DocumentDBEventRecord> Events { get; set; }
   
           [JsonPropertyName("eventSource")]
           public string EventSource { get; set; }
       }
   
       public class DocumentDBEventRecord
       {
           [JsonPropertyName("event")]
           public EventData Event { get; set; }
       }
   
       public class EventData
       {
           [JsonPropertyName("_id")]
           public IdData Id { get; set; }
   
           [JsonPropertyName("clusterTime")]
           public ClusterTime ClusterTime { get; set; }
   
           [JsonPropertyName("documentKey")]
           public DocumentKey DocumentKey { get; set; }
   
           [JsonPropertyName("fullDocument")]
           public Dictionary<string, object> FullDocument { get; set; }
   
           [JsonPropertyName("ns")]
           public Namespace Ns { get; set; }
   
           [JsonPropertyName("operationType")]
           public string OperationType { get; set; }
       }
   
       public class IdData
       {
           [JsonPropertyName("_data")]
           public string Data { get; set; }
       }
   
       public class ClusterTime
       {
           [JsonPropertyName("$timestamp")]
           public Timestamp Timestamp { get; set; }
       }
   
       public class Timestamp
       {
           [JsonPropertyName("t")]
           public long T { get; set; }
   
           [JsonPropertyName("i")]
           public int I { get; set; }
       }
   
       public class DocumentKey
       {
           [JsonPropertyName("_id")]
           public Id Id { get; set; }
       }
   
       public class Id
       {
           [JsonPropertyName("$oid")]
           public string Oid { get; set; }
       }
   
       public class Namespace
       {
           [JsonPropertyName("db")]
           public string Db { get; set; }
   
           [JsonPropertyName("coll")]
           public string Coll { get; set; }
       }
   }
   ```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 Go 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   package main
   
   import (
   	"context"
   	"encoding/json"
   	"fmt"
   
   	"github.com/aws/aws-lambda-go/lambda"
   )
   
   type Event struct {
   	Events []Record `json:"events"`
   }
   
   type Record struct {
   	Event struct {
   		OperationType string `json:"operationType"`
   		NS            struct {
   			DB   string `json:"db"`
   			Coll string `json:"coll"`
   		} `json:"ns"`
   		FullDocument interface{} `json:"fullDocument"`
   	} `json:"event"`
   }
   
   func main() {
   	lambda.Start(handler)
   }
   
   func handler(ctx context.Context, event Event) (string, error) {
   	fmt.Println("Loading function")
   	for _, record := range event.Events {
   		logDocumentDBEvent(record)
   	}
   
   	return "OK", nil
   }
   
   func logDocumentDBEvent(record Record) {
   	fmt.Printf("Operation type: %s\n", record.Event.OperationType)
   	fmt.Printf("db: %s\n", record.Event.NS.DB)
   	fmt.Printf("collection: %s\n", record.Event.NS.Coll)
   	docBytes, _ := json.MarshalIndent(record.Event.FullDocument, "", "  ")
   	fmt.Printf("Full document: %s\n", string(docBytes))
   }
   ```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 Java 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   import java.util.List;
   import java.util.Map;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   
   public class Example implements RequestHandler<Map<String, Object>, String> {
   
       @SuppressWarnings("unchecked")
       @Override
       public String handleRequest(Map<String, Object> event, Context context) {
           List<Map<String, Object>> events = (List<Map<String, Object>>) event.get("events");
           for (Map<String, Object> record : events) {
               Map<String, Object> eventData = (Map<String, Object>) record.get("event");
               processEventData(eventData);
           }
   
           return "OK";
       }
   
       @SuppressWarnings("unchecked")
       private void processEventData(Map<String, Object> eventData) {
           String operationType = (String) eventData.get("operationType");
           System.out.println("operationType: %s".formatted(operationType));
   
           Map<String, Object> ns = (Map<String, Object>) eventData.get("ns");
   
           String db = (String) ns.get("db");
           System.out.println("db: %s".formatted(db));
           String coll = (String) ns.get("coll");
           System.out.println("coll: %s".formatted(coll));
   
           Map<String, Object> fullDocument = (Map<String, Object>) eventData.get("fullDocument");
           System.out.println("fullDocument: %s".formatted(fullDocument));
       }
   
   }
   ```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   console.log('Loading function');
   exports.handler = async (event, context) => {
       event.events.forEach(record => {
           logDocumentDBEvent(record);
       });
       return 'OK';
   };
   
   const logDocumentDBEvent = (record) => {
       console.log('Operation type: ' + record.event.operationType);
       console.log('db: ' + record.event.ns.db);
       console.log('collection: ' + record.event.ns.coll);
       console.log('Full document:', JSON.stringify(record.event.fullDocument, null, 2));
   };
   ```
使用 TypeScript 搭配 Lambda 使用 Amazon DocumentDB 事件  

   ```
   import { DocumentDBEventRecord, DocumentDBEventSubscriptionContext } from 'aws-lambda';
   
   console.log('Loading function');
   
   export const handler = async (
     event: DocumentDBEventSubscriptionContext,
     context: any
   ): Promise<string> => {
     event.events.forEach((record: DocumentDBEventRecord) => {
       logDocumentDBEvent(record);
     });
     return 'OK';
   };
   
   const logDocumentDBEvent = (record: DocumentDBEventRecord): void => {
     console.log('Operation type: ' + record.event.operationType);
     console.log('db: ' + record.event.ns.db);
     console.log('collection: ' + record.event.ns.coll);
     console.log('Full document:', JSON.stringify(record.event.fullDocument, null, 2));
   };
   ```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   <?php
   
   require __DIR__.'/vendor/autoload.php';
   
   use Bref\Context\Context;
   use Bref\Event\Handler;
   
   class DocumentDBEventHandler implements Handler
   {
       public function handle($event, Context $context): string
       {
   
           $events = $event['events'] ?? [];
           foreach ($events as $record) {
               $this->logDocumentDBEvent($record['event']);
           }
           return 'OK';
       }
   
       private function logDocumentDBEvent($event): void
       {
           // Extract information from the event record
   
           $operationType = $event['operationType'] ?? 'Unknown';
           $db = $event['ns']['db'] ?? 'Unknown';
           $collection = $event['ns']['coll'] ?? 'Unknown';
           $fullDocument = $event['fullDocument'] ?? [];
   
           // Log the event details
   
           echo "Operation type: $operationType\n";
           echo "Database: $db\n";
           echo "Collection: $collection\n";
           echo "Full document: " . json_encode($fullDocument, JSON_PRETTY_PRINT) . "\n";
       }
   }
   return new DocumentDBEventHandler();
   ```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 Python 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   import json
   
   def lambda_handler(event, context):
       for record in event.get('events', []):
           log_document_db_event(record)
       return 'OK'
   
   def log_document_db_event(record):
       event_data = record.get('event', {})
       operation_type = event_data.get('operationType', 'Unknown')
       db = event_data.get('ns', {}).get('db', 'Unknown')
       collection = event_data.get('ns', {}).get('coll', 'Unknown')
       full_document = event_data.get('fullDocument', {})
   
       print(f"Operation type: {operation_type}")
       print(f"db: {db}")
       print(f"collection: {collection}")
       print("Full document:", json.dumps(full_document, indent=2))
   ```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   require 'json'
   
   def lambda_handler(event:, context:)
     event['events'].each do |record|
       log_document_db_event(record)
     end
     'OK'
   end
   
   def log_document_db_event(record)
     event_data = record['event'] || {}
     operation_type = event_data['operationType'] || 'Unknown'
     db = event_data.dig('ns', 'db') || 'Unknown'
     collection = event_data.dig('ns', 'coll') || 'Unknown'
     full_document = event_data['fullDocument'] || {}
   
     puts "Operation type: #{operation_type}"
     puts "db: #{db}"
     puts "collection: #{collection}"
     puts "Full document: #{JSON.pretty_generate(full_document)}"
   end
   ```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 使用 Amazon DocumentDB 事件。  

   ```
   use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
   use aws_lambda_events::{
       event::documentdb::{DocumentDbEvent, DocumentDbInnerEvent},
      };
   
   
   // Built with the following dependencies:
   //lambda_runtime = "0.11.1"
   //serde_json = "1.0"
   //tokio = { version = "1", features = ["macros"] }
   //tracing = { version = "0.1", features = ["log"] }
   //tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
   //aws_lambda_events = "0.15.0"
   
   async fn function_handler(event: LambdaEvent<DocumentDbEvent>) ->Result<(), Error> {
       
       tracing::info!("Event Source ARN: {:?}", event.payload.event_source_arn);
       tracing::info!("Event Source: {:?}", event.payload.event_source);
     
       let records = &event.payload.events;
      
       if records.is_empty() {
           tracing::info!("No records found. Exiting.");
           return Ok(());
       }
   
       for record in records{
           log_document_db_event(record);
       }
   
       tracing::info!("Document db records processed");
   
       // Prepare the response
       Ok(())
   
   }
   
   fn log_document_db_event(record: &DocumentDbInnerEvent)-> Result<(), Error>{
       tracing::info!("Change Event: {:?}", record.event);
       
       Ok(())
   
   }
   
   #[tokio::main]
   async fn main() -> Result<(), Error> {
       tracing_subscriber::fmt()
       .with_max_level(tracing::Level::INFO)
       .with_target(false)
       .without_time()
       .init();
   
       let func = service_fn(function_handler);
       lambda_runtime::run(func).await?;
       Ok(())
       
   }
   ```

------

1. 在 Lambda 主控台的**程式碼來源**窗格中，將程式碼貼到程式碼編輯器中，取代 Lambda 建立的程式碼。

1. 在 **DEPLOY** 區段中，選擇**部署**以更新函數的程式碼：  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## 建立 Lambda 事件來源映射
<a name="docdb-create-the-lambda-event-source-mapping"></a>

 建立可將 Amazon DocumentDB 變更串流與 Lambda 函數建立關聯的事件來源映射。建立此事件來源映射之後， 會 AWS Lambda 立即開始輪詢串流。

**建立事件來源映射**

1. 開啟 Lambda 主控台中的[函數](https://console.aws.amazon.com/lambda/home#/functions)頁面。

1. 選擇您之前建立的 `ProcessDocumentDBRecords` 函數。

1. 選擇**組態**索引標籤，然後選擇左側功能表中的**觸發程序**。

1. 選擇 **Add trigger (新增觸發條件)**。

1. 在**觸發條件組態**下，針對來源選取 **Amazon DocumentDB**。

1. 使用下列組態建立事件來源映射：
   + **Amazon DocumentDB 叢集**：選擇您先前建立的叢集。
   + **資料庫名稱**：docdbdemo
   + **集合名稱**：產品
   + **批次大小**：1
   + **起始位置**：最新
   + **身分驗證**：BASIC\$1AUTH
   + **Secrets Manager 金鑰**：選擇 Amazon DocumentDB 叢集對應的秘密。其名稱應該類似 `rds!cluster-12345678-a6f0-52c0-b290-db4aga89274f`。
   + **批次時段**：1
   + **完整文件組態**：UpdateLookup

1. 選擇**新增**。建立事件來源映射可能需要幾分鐘的時間。

## 測試 函數
<a name="docdb-test-insert"></a>

等待事件來源映射進入**已啟用**狀態。這可能需要幾分鐘的時間。接著，透過插入、更新和刪除資料庫記錄來測試端對端設定。開始之前：

1. 在 CloudShell 環境中[重新連線至 Amazon DocumentDB 叢集](#docdb-connect-to-cluster)。

1. 執行下列命令，確保使用的是 `docdbdemo` 資料庫：

   ```
   use docdbdemo
   ```

### 插入記錄
<a name="docdb-test-insert"></a>

將記錄插入到 `docdbdemo` 資料庫的 `products` 集合中：

```
db.products.insertOne({"name":"Pencil", "price": 1.00})
```

透過[檢查 CloudWatch Logs](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)，確認函式已成功處理此事件。您應該會看到如下所示的日誌項目：

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/documentdb-insert-log.png)


### 更新記錄
<a name="docdb-test-update"></a>

使用下列命令更新剛剛插入的記錄：

```
db.products.updateOne(
    { "name": "Pencil" },
    { $set: { "price": 0.50 }}
)
```

透過[檢查 CloudWatch Logs](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)，確認函式已成功處理此事件。您應該會看到如下所示的日誌項目：

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/documentdb-update-log.png)


### 刪除記錄
<a name="docdb-test-delete"></a>

使用下列命令刪除剛剛更新的記錄：

```
db.products.deleteOne( { "name": "Pencil" } )
```

透過[檢查 CloudWatch Logs](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)，確認函式已成功處理此事件。您應該會看到如下所示的日誌項目：

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/documentdb-delete-log.png)


## 疑難排解
<a name="docdb-lambda-troubleshooting"></a>

若未在函式的 CloudWatch 日誌中看到任何資料庫事件，請檢查下列項目：
+ 確認 Lambda 事件來源映射 (也稱為觸發程序) 處於**已啟用**狀態。事件來源映射的建立可能需要數分鐘時間。
+ 若事件來源映射**已啟用**，但您仍然無法在 CloudWatch 中看到資料庫事件：
  + 確認事件來源映射中的**資料庫名稱**設定為 `docdbdemo`。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/documentdb-trigger.png)
  + 檢查事件來源映射的**上次處理結果**欄位，看是否出現 "PROBLEM: Connection error. Your VPC must be able to connect to Lambda and STS, as well as Secrets Manager if authentication is required." 訊息。若看到此錯誤，確認[已建立 Lambda 與 Secrets Manager VPC 介面端點](#docdb-create-interface-vpc-endpoints)，且這些端點使用的 VPC 及子網路與 Amazon DocumentDB 叢集所使用的相同。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/documentdb-lastprocessingresult.png)

## 清除您的資源
<a name="docdb-cleanup"></a>

 除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用的 AWS 資源，可為 AWS 帳戶避免不必要的費用。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇**刪除**。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇**刪除**。

**刪除 VPC 端點。**

1. 開啟 [VPC 主控台](https://console.aws.amazon.com/vpc/home#)。在左側選單的**虛擬私有雲端**下，選擇**端點**。

1. 選擇您建立的端點。

1. 選擇 **Actions** (動作)、**Delete VPC endpoints** (刪除 VPC 端點)。

1. 在文字輸入欄位中輸入 **delete**。

1. 選擇 **刪除**。

**刪除 Amazon DocumentDB 叢集**

1. 開啟 [Amazon DocumentDB 主控台](https://console.aws.amazon.com/docdb/home#)。

1. 選擇您為本教學課程建立的 Amazon DocumentDB 叢集，並停用刪除保護。

1. 在主**叢集**頁面中，再次選擇您的 Amazon DocumentDB 叢集。

1. 選擇 **動作**、**刪除**。

1. 針對**建立最終叢集快照**，請選取**否**。

1. 在文字輸入欄位中輸入 **delete**。

1. 選擇 **刪除**。

**在 Secrets Manager 中刪除密碼**

1. 開啟 [Secrets Manager 主控台](https://console.aws.amazon.com/secretsmanager/home#)。

1. 選擇您為此教學課程建立的密碼。

1. 選擇**動作**、**刪除機密**。

1. 選擇 **Schedule deletion** (排定刪除)。

# AWS Lambda 搭配 Amazon DynamoDB 使用
<a name="with-ddb"></a>

**注意**  
如要將資料傳送到 Lambda 函數以外的目標，或在傳送資料之前讓資料更豐富，請參閱 [Amazon EventBridge Pipes](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes.html)。

您可以使用 AWS Lambda 函數來處理 [Amazon DynamoDB 串流](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html)中的記錄。您可以透過 DynamoDB Streams，以在每次更新 DynamoDB 資料表時，觸發 Lambda 函數來執行額外的工作。

處理 DynamoDB 串流時，您需要實作部分批次回應邏輯，避免批次中部分記錄處理失敗時，已成功處理的記錄被重新執行。適用於 的 Powertools 的 [Batch Processor 公用程式](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/) AWS Lambda 可在 Python、TypeScript、.NET 和 Java 中使用，並透過自動處理部分批次回應邏輯、縮短開發時間並改善可靠性來簡化此實作。

**Topics**
+ [

## 輪詢和批次處理串流
](#dynamodb-polling-and-batching)
+ [

## 輪詢和串流開始位置
](#dyanmo-db-stream-poll)
+ [

## DynamoDB Streams 中的碎片同時讀取
](#events-dynamodb-simultaneous-readers)
+ [

## 範例事件
](#events-sample-dynamodb)
+ [

# 使用 Lambda 處理 DynamoDB 記錄
](services-dynamodb-eventsourcemapping.md)
+ [

# 使用 DynamoDB 和 Lambda 設定部分批次回應
](services-ddb-batchfailurereporting.md)
+ [

# 在 Lambda 中保留 DynamoDB 事件來源的捨棄記錄
](services-dynamodb-errors.md)
+ [

# 在 Lambda 中實作有狀態的 DynamoDB 串流處理
](services-ddb-windows.md)
+ [

# Amazon DynamoDB 事件來源映射的 Lambda 參數
](services-ddb-params.md)
+ [

# 搭配 DynamoDB 事件來源使用事件篩選
](with-ddb-filtering.md)
+ [

# 教學課程： AWS Lambda 搭配 Amazon DynamoDB 串流使用
](with-ddb-example.md)

## 輪詢和批次處理串流
<a name="dynamodb-polling-and-batching"></a>

Lambda 會輪詢您 DynamoDB 串流中的碎片，其記錄的基本速率為每秒 4 次。當記錄可用時，Lambda 會調用您的函數，並等待結果。如果處理成功，Lambda 會恢復輪詢，直到收到多筆記錄。

Lambda 預設會在記錄可用時立即調用函數。如果 Lambda 從事件來源中讀取的批次只有一筆記錄，Lambda 只會傳送一筆記錄至函數。為避免調用具有少量記錄的函數，您可設定*批次間隔*，請求事件來源緩衝記錄最長達五分鐘。調用函數之前，Lambda 會繼續從事件來源中讀取記錄，直到收集到完整批次、批次間隔到期或者批次達到 6 MB 的承載限制。如需詳細資訊，請參閱[批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)。

**警告**  
Lambda 事件來源映射至少會處理每個事件一次，而且可能會重複處理記錄。為避免與重複事件相關的潛在問題，強烈建議您讓函數程式碼具有等冪性。若要進一步了解，請參閱 AWS 知識中心中的[如何使 Lambda 函數具有等冪性](https://repost.aws/knowledge-center/lambda-function-idempotent)。

Lambda 在傳送下一批進行處理前不會等待任何已設定的[擴充](lambda-extensions.md)完成。換句話說，當 Lambda 處理下一批記錄時，您的擴充功能可能會繼續執行。如果您違反任何帳戶的 [並行](lambda-concurrency.md) 設定或限制，便可能會產生限流的問題。若要偵測此是否為潛在問題，請監控您的函數，並確認您看到的 [並行指標](monitoring-concurrency.md#general-concurrency-metrics) 是否高於事件來源映射的預期值。由於兩次調用之間的時間很短，Lambda 可能會短暫報告比碎片數目更高的並行用量。即使對於沒有延伸項目的 Lambda 函數也可能如此。

設定 [ParallelizationFactor](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-ParallelizationFactor) 設定來同時處理 DynamoDB 資料串流的一個碎片與多個 Lambda 調用。您可以透過從 1 (預設) 到 10 的並行化因子指定 Lambda 從碎片輪詢的並行批次數。例如，當 `ParallelizationFactor` 設定為 2 時，您最多可以有 200 個並行 Lambda 調用，來處理 100 個 DynamoDB 串流碎片 (不過在實務中，`ConcurrentExecutions` 指標可能有不同值)。當資料量急劇波動並且 [IteratorAge](monitoring-metrics-types.md#performance-metrics) 較高時，這有助於向上擴展處理輸送量。如果增加每個碎片的並行批次數量，Lambda 仍會確保在項目 (分割區和排序索引鍵) 層級進行依序處理。

## 輪詢和串流開始位置
<a name="dyanmo-db-stream-poll"></a>

請注意，建立和更新事件來源映射期間的串流輪詢最終會一致。
+ 在建立事件來源映射期間，從串流開始輪詢事件可能需要幾分鐘時間。
+ 在更新事件來源映射期間，從串流停止並重新開始輪詢事件可能需要幾分鐘時間。

這種行為表示如果您指定 `LATEST` 當作串流的開始位置，事件來源映射可能會在建立或更新期間遺漏事件。若要確保沒有遺漏任何事件，請將串流開始位置指定為 `TRIM_HORIZON`。

## DynamoDB Streams 中的碎片同時讀取
<a name="events-dynamodb-simultaneous-readers"></a>

對於不是全域資料表的單一區域資料表，您最多可以設計兩個 Lambda 函數，以便同時讀取同一個 DynamoDB Streams 碎片。超過此限制會導致請求限流。對於全域資料表，建議您將同時函數的數量限制為一個，以避免請求限流。

## 範例事件
<a name="events-sample-dynamodb"></a>

**Example**  

```
{
  "Records": [
    {
      "eventID": "1",
      "eventVersion": "1.0",
      "dynamodb": {
        "Keys": {
          "Id": {
            "N": "101"
          }
        },
        "NewImage": {
          "Message": {
            "S": "New item!"
          },
          "Id": {
            "N": "101"
          }
        },
        "StreamViewType": "NEW_AND_OLD_IMAGES",
        "SequenceNumber": "111",
        "SizeBytes": 26
      },
      "awsRegion": "us-west-2",
      "eventName": "INSERT",
      "eventSourceARN": "arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525",
      "eventSource": "aws:dynamodb"
    },
    {
      "eventID": "2",
      "eventVersion": "1.0",
      "dynamodb": {
        "OldImage": {
          "Message": {
            "S": "New item!"
          },
          "Id": {
            "N": "101"
          }
        },
        "SequenceNumber": "222",
        "Keys": {
          "Id": {
            "N": "101"
          }
        },
        "SizeBytes": 59,
        "NewImage": {
          "Message": {
            "S": "This item has changed"
          },
          "Id": {
            "N": "101"
          }
        },
        "StreamViewType": "NEW_AND_OLD_IMAGES"
      },
      "awsRegion": "us-west-2",
      "eventName": "MODIFY",
      "eventSourceARN": "arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525",
      "eventSource": "aws:dynamodb"
    }
  ]}
```

# 使用 Lambda 處理 DynamoDB 記錄
<a name="services-dynamodb-eventsourcemapping"></a>

建立事件來源映射，指示 Lambda 從您的串流傳送記錄至 Lambda 函數。您可以建立多個事件來源映射，來使用多個 Lambda 函數處理相同資料，或使用單一函數處理來自多個串流的項目。

您可以設定事件來源映射，以處理來自不同 AWS 帳戶中的串流的記錄。如需詳細資訊，請參閱 [建立跨帳戶事件來源映射](#services-dynamodb-eventsourcemapping-cross-account)。

若要將函數設定為從 DynamoDB Streams 讀取，請將 [AWSLambdaDynamoDBExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaDynamoDBExecutionRole.html) AWS 受管政策連接至您的執行角色，然後建立 **DynamoDB** 觸發。

**若要新增許可並建立觸發條件**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函數的名稱。

1. 依序選擇 **Configuration** (組態) 索引標籤和 **Permissions** (許可)。

1. 在**角色名稱**下面，選擇執行角色連結。此連結會在 IAM 主控台中開啟該角色。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/execution-role.png)

1. 選擇**新增許可**，然後選擇**連接政策**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/attach-policies.png)

1. 在搜尋欄位中輸入 `AWSLambdaDynamoDBExecutionRole`。將此政策新增至您的執行角色。這是 AWS 受管政策，其中包含函數從 DynamoDB 串流讀取所需的許可。如需此政策的詳細資訊，請參閱《AWS 受管政策參考》**中的 [AWSLambdaDynamoDBExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaDynamoDBExecutionRole.html)。

1. 在 Lambda 主控台中返回您的 Lambda 函數。在**函數概觀**下，選擇**新增觸發條件**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/add-trigger.png)

1. 選擇觸發條件類型。

1. 設定需要的選項，然後選擇**新增**。

Lambda 支援 DynamoDB 事件來源的下列選項：

**事件來源選項**
+ **DynamoDB 資料表** - 從中讀取記錄的 DynamoDB 資料表。
+ **批次大小** – 每個批次中要傳送至函數的記錄數量，最高為 10,000。Lambda 會將批次中所有記錄以單一呼叫傳送至函數，前提是事件的總大小不超過同步調用的[酬載限制](gettingstarted-limits.md) (6 MB)。
+ **批次間隔** - 指定調用函數前收集記錄的最長時間 (秒)。
+ **開始位置** - 只處理新記錄，或所有現有的記錄。
  + **最新** - 處理已新增到串流的記錄。
  + **水平修剪** - 處理所有在串流中的記錄。

  處理任何現有的記錄後，該函式已跟上進度並持續處理新的記錄。
+ **故障目的地** - 用於無法處理之記錄的標準 SQS 佇列或標準 SNS 主題。當 Lambda 捨棄太舊或已耗盡所有重試的一批記錄時，Lambda 會將該批次的詳細資料傳送至此佇列或主題。
+ **重試嘗試** - 當函數傳回錯誤時，Lambda 重試的次數上限。這不適用於服務錯誤或調節，其中批次並沒有到達函數。
+ **記錄最大存留期** - Lambda 傳送至函數之記錄的最大存留期。
+ **在錯誤時分割批次** - 當函數傳回錯誤時，先將批次分割為兩個，再進行重試。您原始的批次大小設定仍會維持不變。
+ **每個碎片的並行批次** - 同時處理來自同一個碎片的多個批次。
+ **已啟用** - 設定為 true 可啟用事件來源映射。設定為 false 以停止處理記錄。Lambda 會追蹤上次處理的進度，並在重新啟用映射時從該時間點恢復處理。

**注意**  
對於由 DynamoDB 觸發條件中的 Lambda 調用的 GetRecords API 呼叫，您不需要付費。

若要稍後管理事件來源的組態，請選擇設計工具中的觸發。

## 建立跨帳戶事件來源映射
<a name="services-dynamodb-eventsourcemapping-cross-account"></a>

Amazon DynamoDB 現在支援以[資源為基礎的政策](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/access-control-resource-based.html)。使用此功能，您可以在另一個帳戶中 AWS 帳戶 使用 Lambda 函數處理來自 DynamoDB 串流的資料。

若要使用不同 DynamoDB 串流為您的 Lambda 函數建立事件來源映射 AWS 帳戶，您必須使用資源型政策來設定串流，以授予 Lambda 函數讀取記錄的許可。若要了解如何設定串流以進行跨帳戶存取，請參閱《*Amazon DynamoDB 開發人員指南*》中的[使用跨帳戶 Lambda 函數共用存取權](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/rbac-cross-account-access.html#rbac-analyze-cross-account-lambda-access)。

使用為 Lambda 函數提供必要許可的資源型政策設定串流後，請使用跨帳戶串流 ARN 建立事件來源映射。您可以在跨帳戶 DynamoDB 主控台的資料表**匯出和串流**索引標籤下找到串流 ARN。

使用 Lambda 主控台時，請將串流 ARN 直接貼到事件來源映射建立頁面的 DynamoDB 資料表輸入欄位。

 **注意：**不支援跨區域觸發。

# 使用 DynamoDB 和 Lambda 設定部分批次回應
<a name="services-ddb-batchfailurereporting"></a>

取用和處理事件來源的串流資料時，依預設，只有在批次成功完成時，Lambda 檢查點才會到批次的最高序號。Lambda 會將所有其他結果視為完全失敗，並重試處理批次，直至達到重試限制。若要在處理串流的批次時允許部分成功，請開啟 `ReportBatchItemFailures`。允許部分成功有助於減少記錄的重試次數，但其不會完全消除在成功記錄中重試的可能性。

若要開啟 `ReportBatchItemFailures`，請在 [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionResponseTypes) 清單中包含枚舉值 **ReportBatchItemFailures**。此清單指示已為您的函數啟用哪些回應類型。您可以在[建立](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html)或[更新](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)事件來源映射時設定此清單。

**注意**  
即使函式程式碼傳回了部分批次失敗回應，除非針對事件來源映射明確啟用 `ReportBatchItemFailures` 功能，否則 Lambda 將不會處理這些回應。

## 報告語法
<a name="streams-batchfailurereporting-syntax"></a>

設定批次項目失敗的報告時，會傳回 `StreamsEventResponse` 類別，其中包含批次項目失敗的清單。您可以使用 `StreamsEventResponse` 物件，來傳回批次中第一個失敗記錄的序號。您還可以使用正確的回應語法，建立自己的自訂類別。下列 JSON 結構顯示所需的回應語法：

```
{ 
  "batchItemFailures": [ 
        {
            "itemIdentifier": "<SequenceNumber>"
        }
    ]
}
```

**注意**  
如果 `batchItemFailures` 陣列包含多個項目，則 Lambda 會使用具有最低序列號的記錄作為檢查點。然後，Lambda 會重試從該檢查點開始的所有記錄。

## 成功與失敗條件
<a name="streams-batchfailurereporting-conditions"></a>

如果您傳回下列任一項目，Lambda 會將批次視為完全成功：
+ 空白 `batchItemFailure` 清單
+ Null `batchItemFailure` 清單
+ 空白 `EventResponse`
+ Null `EventResponse`

如果您傳回下列任一項目，Lambda 會將批次視為完全失敗：
+ 空白字串 `itemIdentifier`
+ Null `itemIdentifier`
+ 具有錯誤金鑰名稱的 `itemIdentifier`

Lambda 會根據您的重試政策來重試失敗。

## 將批次平分
<a name="streams-batchfailurereporting-bisect"></a>

如果您的調用失敗且 `BisectBatchOnFunctionError` 已開啟，則無論您的 `ReportBatchItemFailures` 設定如何，批次都會被平分。

收到部分批次成功回應且 `BisectBatchOnFunctionError` 和 `ReportBatchItemFailures` 均開啟時，批次會依傳回的序號進行平分，並且 Lambda 僅會重試剩餘的記錄。

為了簡化部分批次回應邏輯的實作，請考慮使用 Powertools 中的 [Batch Processor 公用程式](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/) AWS Lambda，其會自動為您處理這些複雜性。

以下範例函數程式碼會傳回批次中失敗訊息 ID 的清單：

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
using System.Text.Json;
using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.DynamoDBEvents;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace AWSLambda_DDB;

public class Function
{
    public StreamsEventResponse FunctionHandler(DynamoDBEvent dynamoEvent, ILambdaContext context)

    {
        context.Logger.LogInformation($"Beginning to process {dynamoEvent.Records.Count} records...");
        List<StreamsEventResponse.BatchItemFailure> batchItemFailures = new List<StreamsEventResponse.BatchItemFailure>();
        StreamsEventResponse streamsEventResponse = new StreamsEventResponse();

        foreach (var record in dynamoEvent.Records)
        {
            try
            {
                var sequenceNumber = record.Dynamodb.SequenceNumber;
                context.Logger.LogInformation(sequenceNumber);
            }
            catch (Exception ex)
            {
                context.Logger.LogError(ex.Message);
                batchItemFailures.Add(new StreamsEventResponse.BatchItemFailure() { ItemIdentifier = record.Dynamodb.SequenceNumber });
            }
        }

        if (batchItemFailures.Count > 0)
        {
            streamsEventResponse.BatchItemFailures = batchItemFailures;
        }

        context.Logger.LogInformation("Stream processing complete.");
        return streamsEventResponse;
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Go 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

type BatchItemFailure struct {
	ItemIdentifier string `json:"ItemIdentifier"`
}

type BatchResult struct {
	BatchItemFailures []BatchItemFailure `json:"BatchItemFailures"`
}

func HandleRequest(ctx context.Context, event events.DynamoDBEvent) (*BatchResult, error) {
	var batchItemFailures []BatchItemFailure
	curRecordSequenceNumber := ""

	for _, record := range event.Records {
		// Process your record
		curRecordSequenceNumber = record.Change.SequenceNumber
	}

	if curRecordSequenceNumber != "" {
		batchItemFailures = append(batchItemFailures, BatchItemFailure{ItemIdentifier: curRecordSequenceNumber})
	}
	
	batchResult := BatchResult{
		BatchItemFailures: batchItemFailures,
	}

	return &batchResult, nil
}

func main() {
	lambda.Start(HandleRequest)
}
```

------
#### [ Java ]

**適用於 Java 2.x 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Java 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;
import com.amazonaws.services.lambda.runtime.events.models.dynamodb.StreamRecord;

import java.util.ArrayList;
import java.util.List;

public class ProcessDynamodbRecords implements RequestHandler<DynamodbEvent, StreamsEventResponse> {

    @Override
    public StreamsEventResponse handleRequest(DynamodbEvent input, Context context) {

        List<StreamsEventResponse.BatchItemFailure> batchItemFailures = new ArrayList<>();
        String curRecordSequenceNumber = "";

        for (DynamodbEvent.DynamodbStreamRecord dynamodbStreamRecord : input.getRecords()) {
          try {
                //Process your record
                StreamRecord dynamodbRecord = dynamodbStreamRecord.getDynamodb();
                curRecordSequenceNumber = dynamodbRecord.getSequenceNumber();
                
            } catch (Exception e) {
                /* Since we are working with streams, we can return the failed item immediately.
                   Lambda will immediately begin to retry processing from this failed item onwards. */
                batchItemFailures.add(new StreamsEventResponse.BatchItemFailure(curRecordSequenceNumber));
                return new StreamsEventResponse(batchItemFailures);
            }
        }
       
       return new StreamsEventResponse();   
    }
}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
export const handler = async (event) => {
  const records = event.Records;
  let curRecordSequenceNumber = "";

  for (const record of records) {
    try {
      // Process your record
      curRecordSequenceNumber = record.dynamodb.SequenceNumber;
    } catch (e) {
      // Return failed record's sequence number
      return { batchItemFailures: [{ itemIdentifier: curRecordSequenceNumber }] };
    }
  }

  return { batchItemFailures: [] };
};
```
使用 TypeScript 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
import {
  DynamoDBBatchResponse,
  DynamoDBBatchItemFailure,
  DynamoDBStreamEvent,
} from "aws-lambda";

export const handler = async (
  event: DynamoDBStreamEvent
): Promise<DynamoDBBatchResponse> => {
  const batchItemFailures: DynamoDBBatchItemFailure[] = [];
  let curRecordSequenceNumber;

  for (const record of event.Records) {
    curRecordSequenceNumber = record.dynamodb?.SequenceNumber;

    if (curRecordSequenceNumber) {
      batchItemFailures.push({
        itemIdentifier: curRecordSequenceNumber,
      });
    }
  }

  return { batchItemFailures: batchItemFailures };
};
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\DynamoDb\DynamoDbEvent;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handle(mixed $event, Context $context): array
    {
        $dynamoDbEvent = new DynamoDbEvent($event);
        $this->logger->info("Processing records");

        $records = $dynamoDbEvent->getRecords();
        $failedRecords = [];
        foreach ($records as $record) {
            try {
                $data = $record->getData();
                $this->logger->info(json_encode($data));
                // TODO: Do interesting work based on the new data
            } catch (Exception $e) {
                $this->logger->error($e->getMessage());
                // failed processing the record
                $failedRecords[] = $record->getSequenceNumber();
            }
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");

        // change format for the response
        $failures = array_map(
            fn(string $sequenceNumber) => ['itemIdentifier' => $sequenceNumber],
            $failedRecords
        );

        return [
            'batchItemFailures' => $failures
        ];
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**適用於 Python (Boto3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Python 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def handler(event, context):
    records = event.get("Records")
    curRecordSequenceNumber = ""
    
    for record in records:
        try:
            # Process your record
            curRecordSequenceNumber = record["dynamodb"]["SequenceNumber"]
        except Exception as e:
            # Return failed record's sequence number
            return {"batchItemFailures":[{"itemIdentifier": curRecordSequenceNumber}]}

    return {"batchItemFailures":[]}
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
def lambda_handler(event:, context:)
    records = event["Records"]
    cur_record_sequence_number = ""
  
    records.each do |record|
      begin
        # Process your record
        cur_record_sequence_number = record["dynamodb"]["SequenceNumber"]
      rescue StandardError => e
        # Return failed record's sequence number
        return {"batchItemFailures" => [{"itemIdentifier" => cur_record_sequence_number}]}
      end
    end
  
    {"batchItemFailures" => []}
  end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 報告 DynamoDB 批次項目失敗。  

```
use aws_lambda_events::{
    event::dynamodb::{Event, EventRecord, StreamRecord},
    streams::{DynamoDbBatchItemFailure, DynamoDbEventResponse},
};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

/// Process the stream record
fn process_record(record: &EventRecord) -> Result<(), Error> {
    let stream_record: &StreamRecord = &record.change;

    // process your stream record here...
    tracing::info!("Data: {:?}", stream_record);

    Ok(())
}

/// Main Lambda handler here...
async fn function_handler(event: LambdaEvent<Event>) -> Result<DynamoDbEventResponse, Error> {
    let mut response = DynamoDbEventResponse {
        batch_item_failures: vec![],
    };

    let records = &event.payload.records;

    if records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(response);
    }

    for record in records {
        tracing::info!("EventId: {}", record.event_id);

        // Couldn't find a sequence number
        if record.change.sequence_number.is_none() {
            response.batch_item_failures.push(DynamoDbBatchItemFailure {
                item_identifier: Some("".to_string()),
            });
            return Ok(response);
        }

        // Process your record here...
        if process_record(record).is_err() {
            response.batch_item_failures.push(DynamoDbBatchItemFailure {
                item_identifier: record.change.sequence_number.clone(),
            });
            /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
            return Ok(response);
        }
    }

    tracing::info!("Successfully processed {} record(s)", records.len());

    Ok(response)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

## 使用 Powertools 進行 AWS Lambda 批次處理器
<a name="services-ddb-batchfailurereporting-powertools"></a>

Powertools for 的批次處理器公用程式 AWS Lambda 會自動處理部分批次回應邏輯，降低實作批次失敗報告的複雜性。以下是使用批次處理器的範例：

**Python**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)。
使用 AWS Lambda 批次處理器處理 DynamoDB 串流記錄。  

```
import json
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.batch import BatchProcessor, EventType, process_partial_response
from aws_lambda_powertools.utilities.data_classes import DynamoDBStreamEvent
from aws_lambda_powertools.utilities.typing import LambdaContext

processor = BatchProcessor(event_type=EventType.DynamoDBStreams)
logger = Logger()

def record_handler(record):
    logger.info(record)
    # Your business logic here
    # Raise an exception to mark this record as failed
    
def lambda_handler(event, context: LambdaContext):
    return process_partial_response(
        event=event, 
        record_handler=record_handler, 
        processor=processor,
        context=context
    )
```

**TypeScript**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.aws.amazon.com/powertools/typescript/latest/features/batch/)。
使用 AWS Lambda 批次處理器處理 DynamoDB 串流記錄。  

```
import { BatchProcessor, EventType, processPartialResponse } from '@aws-lambda-powertools/batch';
import { Logger } from '@aws-lambda-powertools/logger';
import type { DynamoDBStreamEvent, Context } from 'aws-lambda';

const processor = new BatchProcessor(EventType.DynamoDBStreams);
const logger = new Logger();

const recordHandler = async (record: any): Promise<void> => {
    logger.info('Processing record', { record });
    // Your business logic here
    // Throw an error to mark this record as failed
};

export const handler = async (event: DynamoDBStreamEvent, context: Context) => {
    return processPartialResponse(event, recordHandler, processor, {
        context,
    });
};
```

**Java**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.powertools.aws.dev/lambda/java/latest/utilities/batch/)。
使用 AWS Lambda 批次處理器處理 DynamoDB 串流記錄。  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;
import software.amazon.lambda.powertools.batch.BatchMessageHandlerBuilder;
import software.amazon.lambda.powertools.batch.handler.BatchMessageHandler;

public class DynamoDBStreamBatchHandler implements RequestHandler<DynamodbEvent, StreamsEventResponse> {

    private final BatchMessageHandler<DynamodbEvent, StreamsEventResponse> handler;

    public DynamoDBStreamBatchHandler() {
        handler = new BatchMessageHandlerBuilder()
                .withDynamoDbBatchHandler()
                .buildWithRawMessageHandler(this::processMessage);
    }

    @Override
    public StreamsEventResponse handleRequest(DynamodbEvent ddbEvent, Context context) {
        return handler.processBatch(ddbEvent, context);
    }

    private void processMessage(DynamodbEvent.DynamodbStreamRecord dynamodbStreamRecord, Context context) {
        // Process the change record
    }
}
```

**.NET**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.aws.amazon.com/powertools/dotnet/utilities/batch-processing/)。
使用 AWS Lambda 批次處理器處理 DynamoDB 串流記錄。  

```
using System;
using System.Threading;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.DynamoDBEvents;
using Amazon.Lambda.Serialization.SystemTextJson;
using AWS.Lambda.Powertools.BatchProcessing;

[assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))]

namespace HelloWorld;

public class Customer
{
    public string? CustomerId { get; set; }
    public string? Name { get; set; }
    public string? Email { get; set; }
    public DateTime CreatedAt { get; set; }
}

internal class TypedDynamoDbRecordHandler : ITypedRecordHandler<Customer> 
{
    public async Task<RecordHandlerResult> HandleAsync(Customer customer, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(customer.Email)) 
        {
            throw new ArgumentException("Customer email is required");
        }

        return await Task.FromResult(RecordHandlerResult.None); 
    }
}

public class Function
{
    [BatchProcessor(TypedRecordHandler = typeof(TypedDynamoDbRecordHandler))]
    public BatchItemFailuresResponse HandlerUsingTypedAttribute(DynamoDBEvent _)
    {
        return TypedDynamoDbStreamBatchProcessor.Result.BatchItemFailuresResponse; 
    }
}
```

# 在 Lambda 中保留 DynamoDB 事件來源的捨棄記錄
<a name="services-dynamodb-errors"></a>

DynamoDB 事件來源映射的錯誤處理取決於錯誤是在調用函數之前還是在調用函數期間發生：
+ **調用前：**如果 Lambda 事件來源映射因為限流或其他問題而無法調用函數，它會重試，直到記錄過期或超過事件來源映射上設定的最長存留期 ([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))。
+ **在調用期間：**如果調用函數但傳回錯誤，Lambda 會重試，直到記錄過期、超過最長存留期 ([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))，或達到設定的重試配額 ([MaximumRetryAttempts](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRetryAttempts))。對於函數錯誤，您也可以設定 [BisectBatchOnFunctionError](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-response-BisectBatchOnFunctionError)，將失敗的批次分割為兩個較小的批次，隔離錯誤的記錄並避免逾時。分割批次不會消耗重試配額。

如果錯誤處理措施失敗，Lambda 會捨棄相應記錄，並繼續處理串流中的批次。使用預設設定時，這表示不良的記錄可能會封鎖受影響碎片上的處理長達一天。若要避免此情況，在設定函數的事件來源映射時，請使用合理的重試次數和符合您使用案例的記錄最大保留期。

## 設定失敗調用的目的地
<a name="dynamodb-on-failure-destination-console"></a>

若要保留失敗的事件來源映射調用記錄，請將目標地新增到函數的事件來源映射中。傳送至該目的地的每筆記錄都是包含失敗調用之中繼資料的 JSON 文件。對於 Amazon S3 目的地，Lambda 還會將整個調用記錄與中繼資料一起傳送。您可以設定任何 Amazon SNS 主題、Amazon SQS 佇列、Amazon S3 儲存貯體或 Kafka 做為目的地。

透過 Amazon S3 目的地，您可以使用 [Amazon S3 事件通知](https://docs.aws.amazon.com/)功能，在物件上傳至您的目的地 S3 儲存貯體時接收通知。您也可以設定 S3 事件通知來調用另一個 Lambda 函數，以對失敗的批次執行自動處理。

執行角色必須具有目的地的許可：
+ **對於 SQS 目的地：**[sqs：SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)
+ **對於 SNS 目的地：**[sns：Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html)
+ **對於 S3 目的地：**[s3：PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 和 [s3：ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/ListObjectsV2.html)
+ **對於 Kafka 目的地：**[kafka-cluster：WriteData](https://docs.aws.amazon.com/msk/latest/developerguide/kafka-actions.html)

您可以將 Kafka 主題設定為 Kafka 事件來源映射的失敗時目的地。當 Lambda 在耗盡重試嘗試後或記錄超過最長存留期後無法處理記錄時，Lambda 會將失敗的記錄傳送至指定的 Kafka 主題，以供稍後處理。請參閱[使用 Kafka 主題做為失敗時的目的地](kafka-on-failure-destination.md)。

如果您已使用自己的 KMS 金鑰為 S3 目的地啟用加密，則函數的執行角色也必須具有呼叫 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) 的許可。如果 KMS 金鑰和 S3 儲存貯體目的地與 Lambda 函數和執行角色位於不同的帳戶中，請將 KMS 金鑰設定為信任執行角色以允許 kms:GenerateDataKey。

若要使用主控台設定失敗時的目的地，請依照下列步驟執行：

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇一個函數。

1. 在**函數概觀下**，選擇**新增目的地**。

1. 針對**來源**，請選擇**事件來源映射調用**。

1. 對於**事件來源映射**，請選擇針對此函數設定的事件來源。

1. 對於**條件**，選取**失敗時**。對於事件來源映射調用，這是唯一可接受的條件。

1. 對於**目標類型**，請選擇 Lambda 將調用記錄傳送至的目標類型。

1. 對於**目的地**，請選擇一個資源。

1. 選擇**儲存**。

您也可以使用 AWS Command Line Interface () 設定失敗時的目的地AWS CLI。例如，下列 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 命令會將具有 SQS 失敗時的目的地的事件來源映射新增至 `MyFunction`：

```
aws lambda create-event-source-mapping \
--function-name "MyFunction" \
--event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sqs:us-east-1:123456789012:dest-queue"}}'
```

下列 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 命令會更新事件來源映射，以在嘗試兩次重試後，或在記錄超過一小時時，將失敗的調用記錄傳送至 SNS 目的地。

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--maximum-retry-attempts 2 \
--maximum-record-age-in-seconds 3600 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sns:us-east-1:123456789012:dest-topic"}}'
```

系統會以非同步的方式套用更新的設定，在處理完成之前不會反映在輸出中。使用 [get-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) 命令檢視目前的狀態。

若要移除目的地，請提供空白字串作為 `destination-config` 參數的引數：

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": ""}}'
```

### Amazon S3 目的地的安全最佳實務
<a name="ddb-s3-destination-security"></a>

刪除已設定為目的地的 S3 儲存貯體而不從函數的組態中移除目的地，可能會產生安全風險。如果其他使用者知道目的地儲存貯體的名稱，他們可以在其 AWS 帳戶中重新建立儲存貯體。失敗調用的記錄會被傳送到其儲存貯體，可能公開來自您函數的資料。

**警告**  
為了確保無法將來自函數的調用記錄傳送到另一個 中的 S3 儲存貯體 AWS 帳戶，請將條件新增至函數的執行角色，以限制您帳戶中儲存貯體的`s3:PutObject`許可。

下列範例顯示的 IAM 政策，將函數的 `s3:PutObject` 許可限制為帳戶中的儲存貯體。此政策也為 Lambda 提供了使用 S3 儲存貯體做為目的地所需的 `s3:ListBucket` 許可。

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "S3BucketResourceAccountWrite",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::*/*",
                "arn:aws:s3:::*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:ResourceAccount": "111122223333"
                }
            }
        }
    ]
}
```

若要使用 AWS 管理主控台 或 將許可政策新增至函數的執行角色 AWS CLI，請參閱下列程序中的指示：

------
#### [ Console ]

**若要將許可政策新增至函數的執行角色 (主控台)**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選取您要修改其執行角色的 Lambda 函數。

1. 在**組態**索引標籤中，選擇**許可**。

1. 在**執行角色**索引標籤中，選取函數的**角色名稱**，以開啟角色的 IAM 主控台頁面。

1. 透過下列步驟將許可政策新增至角色：

   1. 在**許可政策**窗格中，選擇**新增許可** ，然後選取**建立內嵌政策**。

   1. 在**政策編輯器**中，選取 **JSON**。

   1. 將您要新增的政策貼入編輯器 (取代現有的 JSON)，然後選擇**下一步**。

   1. 在**政策詳細資訊**下，輸入**政策名稱**。

   1. 選擇**建立政策**。

------
#### [ AWS CLI ]

**若要將許可政策新增至函數的執行角色 (CLI)**

1. 建立具有所需許可的 JSON 政策文件，並將其儲存在本機目錄中。

1. 使用 IAM `put-role-policy` CLI 命令，將許可新增至函數的執行角色。從您儲存 JSON 政策文件的目錄執行下列命令，並將角色名稱、政策名稱和政策文件取代為您自己的值。

   ```
   aws iam put-role-policy \
   --role-name my_lambda_role \
   --policy-name LambdaS3DestinationPolicy \
   --policy-document file://my_policy.json
   ```

------

### Amazon SNS 和 Amazon SQS 調用記錄範例
<a name="kinesis-on-failure-destination-example-sns-sqs"></a>

下列範例顯示了 Lambda 傳送至 DynamoDB 串流的 SQS 或 SNS 目的地的一條調用記錄。

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:13:49.717Z",
    "DDBStreamBatchInfo": {
        "shardId": "shardId-00000001573689847184-864758bb",
        "startSequenceNumber": "800000000003126276362",
        "endSequenceNumber": "800000000003126276362",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:13:19Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:13:19Z",
        "batchSize": 1,
        "streamArn": "arn:aws:dynamodb:us-east-2:123456789012:table/mytable/stream/2019-11-14T00:04:06.388"
    }
}
```

您可以使用此資訊來從串流擷取受影響的記錄，以進行疑難排解。實際的記錄不包含在內，因此您必須處理此記錄，並在因過期而遺失之前從資料串流中擷取它們。

### Amazon S3 調用記錄範例
<a name="kinesis-on-failure-destination-example-sns-sqs-s3"></a>

下列範例顯示了 Lambda 傳送至 DynamoDB 串流的 S3 儲存貯體目的地的一條調用記錄。除了上一個 SQS 和 SNS 目的地範例中的所有欄位之外，此 `payload` 欄位還包含原始調用記錄做為逸出 JSON 字串。

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:13:49.717Z",
    "DDBStreamBatchInfo": {
        "shardId": "shardId-00000001573689847184-864758bb",
        "startSequenceNumber": "800000000003126276362",
        "endSequenceNumber": "800000000003126276362",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:13:19Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:13:19Z",
        "batchSize": 1,
        "streamArn": "arn:aws:dynamodb:us-east-2:123456789012:table/mytable/stream/2019-11-14T00:04:06.388"
    },
    "payload": "<Whole Event>" // Only available in S3
}
```

包含調用記錄的 S3 物件使用以下命名慣例：

```
aws/lambda/<ESM-UUID>/<shardID>/YYYY/MM/DD/YYYY-MM-DDTHH.MM.SS-<Random UUID>
```

# 在 Lambda 中實作有狀態的 DynamoDB 串流處理
<a name="services-ddb-windows"></a>

Lambda 函數可執行持續串流處理應用程式。串流表示持續在應用程式中流動的無限制資料。若要分析此持續更新輸入中的資訊，您可以使用定義的時段來限制包含的記錄。

輪轉時段是定期開啟和關閉的不同時段。依預設，Lambda 調用是無狀態的，您無法在沒有外部資料庫的情況下，將其用於處理多個持續調用的資料。然而，使用輪轉時段，您可以在不同的調用間維護狀態。此狀態包含之前為目前時段處理之訊息的彙總結果。狀態可以是每個分區最多 1 MB。如果超過該大小，則 Lambda 會提前終止時段。

串流中的每個記錄都屬於一個特定時段。Lambda 至少會處理一次每筆記錄，但不保證每筆記錄只會處理一次。在極少數情況下，例如錯誤處理，某些記錄可能會處理多次。第一次時一律會依序處理記錄。如果多次處理記錄，則可能不會按順序處理。

## 彙總與處理
<a name="streams-tumbling-processing"></a>

調用您的使用者管理函數進行彙總，以及處理該彙總的最終結果。Lambda 會彙總時段中接收的所有記錄。您可以在多個批次中接收這些記錄，各自作為單獨的調用。每次調用會收到一個狀態。因此，當使用輪轉時段時，您的 Lambda 函數回應必須包含 `state` 屬性。如果回應不包含 `state` 屬性，Lambda 會將此視為失敗的調用。為了滿足此條件，您的函數可以返回一個 `TimeWindowEventResponse` 物件，它具有下列 JSON 形狀：

**Example `TimeWindowEventResponse` 值**  

```
{
    "state": {
        "1": 282,
        "2": 715
    },
    "batchItemFailures": []
}
```

**注意**  
對於 Java 函數，我們建議使用 `Map<String, String>` 來表示狀態。

在時段結束時，標記 `isFinalInvokeForWindow` 會設定為 `true` 以指示這是最終狀態，並且可隨時進行處理。處理完成後，時段結束並完成最終調用，然後丟棄該狀態。

在時段結束時，Lambda 會針對彙總結果上的動作使用最終處理。您的最終處理將同步調用。成功調用後，您的函數檢查點序號和串流處理將會繼續。如果調用失敗，則您的 Lambda 函數會暫停進一步處理，直至成功調用。

**Example DynamodbTimeWindowEvent**  

```
{
   "Records":[
      {
         "eventID":"1",
         "eventName":"INSERT",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"111",
            "SizeBytes":26,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"2",
         "eventName":"MODIFY",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"222",
            "SizeBytes":59,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"3",
         "eventName":"REMOVE",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"333",
            "SizeBytes":38,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      }
   ],
    "window": {
        "start": "2020-07-30T17:00:00Z",
        "end": "2020-07-30T17:05:00Z"
    },
    "state": {
        "1": "state1"
    },
    "shardId": "shard123456789",
    "eventSourceARN": "stream-ARN",
    "isFinalInvokeForWindow": false,
    "isWindowTerminatedEarly": false
}
```

## Configuration
<a name="streams-tumbling-config"></a>

您可以在建立或更新事件來源對映時設定輪轉時段。若要設定輪轉時段，請以秒為單位指定時段 ([TumblingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-TumblingWindowInSeconds))。下列 example AWS Command Line Interface (AWS CLI) 命令會建立輪轉時段為 120 秒的串流事件來源映射。針對彙總與處理定義的 Lambda 函數命名為 `tumbling-window-example-function`。

```
aws lambda create-event-source-mapping \
--event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525 \
--function-name tumbling-window-example-function \
--starting-position TRIM_HORIZON \
--tumbling-window-in-seconds 120
```

Lambda 根據記錄插入串流的時間，確定輪轉時段邊界。所有記錄都有 Lambda 在邊界確定中使用的近似時間戳記。

輪轉時段彙總不支援重新分區。分區結束後，Lambda 會考慮關閉時段，並且子分區會以新的狀態開始自己的時段。

輪轉時段完全支援現有的重試政策 `maxRetryAttempts` 和 `maxRecordAge`。

**Example Handler.py - 彙總與處理**  
下列 Python 函數示範了如何彙總，然後處理您的最終狀態：  

```
def lambda_handler(event, context):
    print('Incoming event: ', event)
    print('Incoming state: ', event['state'])

#Check if this is the end of the window to either aggregate or process.
    if event['isFinalInvokeForWindow']:
        # logic to handle final state of the window
        print('Destination invoke')
    else:
        print('Aggregate invoke')

#Check for early terminations
    if event['isWindowTerminatedEarly']:
        print('Window terminated early')

    #Aggregation logic
    state = event['state']
    for record in event['Records']:
        state[record['dynamodb']['NewImage']['Id']] = state.get(record['dynamodb']['NewImage']['Id'], 0) + 1

    print('Returning state: ', state)
    return {'state': state}
```

# Amazon DynamoDB 事件來源映射的 Lambda 參數
<a name="services-ddb-params"></a>

所有 Lambda 事件來源類型都會共用相同的 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 和 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 操作。但是，只有一些參數適用於 DynamoDB Streams。


| 參數 | 必要 | 預設 | 備註 | 
| --- | --- | --- | --- | 
|  BatchSize  |  否  |  100  |  上限：10,000  | 
|  BisectBatchOnFunctionError  |  N  |  false  | 無  | 
|  DestinationConfig  |  N  | N/A  |  捨棄記錄的標準 Amazon SQS 佇列或標準 Amazon SNS 主題目的地  | 
|  已啟用  |  N  |  true  | 無  | 
|  EventSourceArn  |  Y  | N/A |  資料串流或串流消費者的 ARN  | 
|  FilterCriteria  |  N  | N/A  |  [控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)  | 
|  FunctionName  |  是  | N/A  | 無  | 
|  FunctionResponseTypes  |  N  | N/A |  若要讓函數報告批次中的特定失敗，請將值 `ReportBatchItemFailures` 包含在 `FunctionResponseTypes` 中。如需詳細資訊，請參閱[使用 DynamoDB 和 Lambda 設定部分批次回應](services-ddb-batchfailurereporting.md)。  | 
|  MaximumBatchingWindowInSeconds  |  N  |  0  | 無  | 
|  MaximumRecordAgeInSeconds  |  N  |  -1  |  -1 代表無限：系統會重試失敗的記錄，直到記錄過期為止。[DynamoDB Streams 的資料保留限制](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html#Streams.DataRetention)為 24 小時。 下限：-1 上限：604,800  | 
|  MaximumRetryAttempts  |  N  |  -1  |  -1 代表無限：系統會重試失敗的記錄，直到記錄過期為止 下限：0 上限：10,000  | 
|  ParallelizationFactor  |  N  |  1  |  上限：10  | 
|  StartingPosition  |  Y  | N/A  |  TRIM\$1HORIZON 或 LATEST  | 
|  TumblingWindowInSeconds  |  N  | N/A  |  下限：0 上限：900  | 

# 搭配 DynamoDB 事件來源使用事件篩選
<a name="with-ddb-filtering"></a>

您可以使用事件篩選來控制 Lambda 將哪些記錄從串流或佇列中傳送至函數。如需事件篩選運作方式的一般資訊，請參閱[控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)。

本節重點介紹 DynamoDB 事件來源的事件篩選。

**注意**  
DynamoDB 事件來源映射僅支援依據 `dynamodb` 鍵進行篩選。

**Topics**
+ [

## DynamoDB 事件
](#filtering-ddb)
+ [

## 使用資料表屬性進行篩選
](#filtering-ddb-attributes)
+ [

## 使用布林表達式進行篩選
](#filtering-ddb-boolean)
+ [

## 使用 Exists 運算子
](#filtering-ddb-exists)
+ [

## DynamoDB 篩選的 JSON 格式
](#filtering-ddb-JSON-format)

## DynamoDB 事件
<a name="filtering-ddb"></a>

假設您有一個包含主索引鍵 `CustomerName` 和屬性 `AccountManager` 與 `PaymentTerms` 的 DynamoDB 表格。以下顯示 DynamoDB 表格串流中的範例記錄。

```
{
      "eventID": "1",
      "eventVersion": "1.0",
      "dynamodb": {
          "ApproximateCreationDateTime": "1678831218.0",
          "Keys": {
              "CustomerName": {
                  "S": "AnyCompany Industries"
              }
          },
          "NewImage": {
              "AccountManager": {
                  "S": "Pat Candella"
              },
              "PaymentTerms": {
                  "S": "60 days"
              },
              "CustomerName": {
                  "S": "AnyCompany Industries"
              }
          },
          "SequenceNumber": "111",
          "SizeBytes": 26,
          "StreamViewType": "NEW_IMAGE"
      }
  }
```

若要根據 DynamoDB 表格中的索引鍵值和屬性值進行篩選，請使用記錄中的 `dynamodb` 索引鍵。下列各節提供不同的篩選條件類型範例。

### 使用資料表索引進行篩選
<a name="filtering-ddb-keys"></a>

假設您希望函數僅處理主索引鍵 `CustomerName` 為 "AnyCompany Industries" 的記錄。`FilterCriteria` 物件如下所示。

```
{
     "Filters": [
          {
              "Pattern": "{ \"dynamodb\" : { \"Keys\" : { \"CustomerName\" : { \"S\" : [ \"AnyCompany Industries\" ] } } } }"
          }
      ]
 }
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
     "dynamodb": {
          "Keys": {
              "CustomerName": {
                  "S": [ "AnyCompany Industries" ]
                  }
              }
          }
 }
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "dynamodb" : { "Keys" : { "CustomerName" : { "S" : [ "AnyCompany Industries" ] } } } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"Keys\" : { \"CustomerName\" : { \"S\" : [ \"AnyCompany Industries\" ] } } } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"Keys\" : { \"CustomerName\" : { \"S\" : [ \"AnyCompany Industries\" ] } } } }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
   Filters:
     - Pattern: '{ "dynamodb" : { "Keys" : { "CustomerName" : { "S" : [ "AnyCompany Industries" ] } } } }'
```

------

## 使用資料表屬性進行篩選
<a name="filtering-ddb-attributes"></a>

使用 DynamoDB 時，您也可以使用 `NewImage` 和 `OldImage` 索引鍵來篩選屬性值。假設您想篩選最新表格映像中的 `AccountManager` 屬性為 "Pat Candella" 或 "Shirley Rodriguez" 的記錄。`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\", \"Shirley Rodriguez\" ] } } } }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "dynamodb": {
        "NewImage": {
            "AccountManager": {
                "S": [ "Pat Candella", "Shirley Rodriguez" ]
            }
        }
    }
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella", "Shirley Rodriguez" ] } } } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\", \"Shirley Rodriguez\" ] } } } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\", \"Shirley Rodriguez\" ] } } } }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella", "Shirley Rodriguez" ] } } } }'
```

------

## 使用布林表達式進行篩選
<a name="filtering-ddb-boolean"></a>

您也可以使用布林值 AND 運算式建立篩選條件。這些運算式可以同時包含資料表的索引鍵和屬性參數。假設您想篩選記錄，其中 `AccountManager` 的 `NewImage` 值是「Pat Candella」，`OldImage` 值是「Terry Whitlock」。`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\" ] } } } , \"dynamodb\" : { \"OldImage\" : { \"AccountManager\" : { \"S\" : [ \"Terry Whitlock\" ] } } } }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{ 
    "dynamodb" : { 
        "NewImage" : { 
            "AccountManager" : { 
                "S" : [ 
                    "Pat Candella" 
                ] 
            } 
        } 
    }, 
    "dynamodb": { 
        "OldImage": { 
            "AccountManager": { 
                "S": [ 
                    "Terry Whitlock" 
                ] 
            } 
        } 
    } 
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella" ] } } } , "dynamodb" : { "OldImage" : { "AccountManager" : { "S" : [ "Terry Whitlock" ] } } } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\" ] } } } , \"dynamodb\" : { \"OldImage\" : { \"AccountManager\" : { \"S\" : [ \"Terry Whitlock\" ] } } } } "}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\" ] } } } , \"dynamodb\" : { \"OldImage\" : { \"AccountManager\" : { \"S\" : [ \"Terry Whitlock\" ] } } } } "}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella" ] } } } , "dynamodb" : { "OldImage" : { "AccountManager" : { "S" : [ "Terry Whitlock" ] } } } }'
```

------

**注意**  
DynamoDB 事件篩選不支援使用數值運算子 (數值等於和數值範圍)。即使資料表中的項目儲存為數字，這些參數也會轉換為 JSON 記錄物件中的字串。

## 使用 Exists 運算子
<a name="filtering-ddb-exists"></a>

由於來自 DynamoDB 的 JSON 事件物件的構造方式，使用 Exists 運算子需要特別注意。Exists 運算子只能在事件 JSON 的分葉節點上運作，因此如果您的篩選模式使用 Exists 來測試中繼節點，則無法運作。請考慮下列 DynamoDB 資料表項目。

```
{
  "UserID": {"S": "12345"},
  "Name": {"S": "John Doe"},
  "Organizations": {"L": [
      {"S":"Sales"},
      {"S":"Marketing"},
      {"S":"Support"}
    ]
  }
}
```

您可能想要建立如下所示的篩選條件模式，以測試包含 `"Organizations"` 的事件：

```
{ "dynamodb" : { "NewImage" : { "Organizations" : [ { "exists": true } ] } } }
```

不過，此篩選條件模式永遠不會傳回相符項目，因為 `"Organizations"` 不是分葉節點。下列範例顯示了如何正確使用 Exists 運算子來建構所需的篩選條件模式：

```
{ "dynamodb" : { "NewImage" : {"Organizations": {"L": {"S": [ {"exists": true } ] } } } } }
```

## DynamoDB 篩選的 JSON 格式
<a name="filtering-ddb-JSON-format"></a>

若要正確篩選來自 DynamoDB 來源的事件，資料欄位和資料欄位 (`dynamodb`) 的篩選條件標準都必須是有效的 JSON 格式。如果其中一個欄位不是有效的 JSON 格式，則 Lambda 會捨棄訊息或擲回例外狀況。下表摘要說明特定行為：


| 傳入資料格式 | 資料屬性的篩選條件模式格式 | 產生的動作 | 
| --- | --- | --- | 
|  有效的 JSON  |  有效的 JSON  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 
|  有效的 JSON  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  非 JSON  |  Lambda 會在事件來源映射建立或更新時擲回例外狀況。資料屬性的篩選條件模式必須是有效的 JSON 格式。  | 
|  非 JSON  |  有效的 JSON  |  Lambda 捨棄記錄。  | 
|  非 JSON  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  非 JSON  |  非 JSON  |  Lambda 會在事件來源映射建立或更新時擲回例外狀況。資料屬性的篩選條件模式必須是有效的 JSON 格式。  | 

# 教學課程： AWS Lambda 搭配 Amazon DynamoDB 串流使用
<a name="with-ddb-example"></a>

 在此教學課程中，您建立 Lambda 函數以從 Amazon DynamoDB Streams 中取用事件。

## 先決條件
<a name="with-ddb-prepare"></a>

### 安裝 AWS Command Line Interface
<a name="install_aws_cli"></a>

如果您尚未安裝 AWS Command Line Interface，請依照[安裝或更新最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)中的步驟進行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中，使用您偏好的 Shell 和套件管理工具。

**注意**  
在 Windows 中，作業系統的內建終端不支援您常與 Lambda 搭配使用的某些 Bash CLI 命令 (例如 `zip`)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本，請[安裝適用於 Linux 的 Windows 子系統](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。

## 建立執行角色
<a name="with-ddb-create-execution-role"></a>

建立 [執行角色](lambda-intro-execution-role.md)，授予函數存取 AWS 資源的許可。

**若要建立執行角色**

1. 在 IAM 主控台中開啟[角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇建**立角色**。

1. 建立具備下列屬性的角色。
   + **信任實體** - Lambda。
   + **許可** - **AWSLambdaDynamoDBExecutionRole**。
   + **角色名稱** - **lambda-dynamodb-role**。

**AWSLambdaDynamoDBExecutionRole** 具備函數自 DynamoDB 讀取項目以及寫入日誌到 CloudWatch Logs 時所需的許可。

## 建立函數
<a name="with-ddb-example-create-function"></a>

建立 Lambda 函數來處理 DynamoDB 事件。函數程式碼將一些傳入的事件資料寫入 CloudWatch Logs。

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 來使用 DynamoDB 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
using System.Text.Json;
using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.DynamoDBEvents;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace AWSLambda_DDB;

public class Function
{
    public void FunctionHandler(DynamoDBEvent dynamoEvent, ILambdaContext context)
    {
        context.Logger.LogInformation($"Beginning to process {dynamoEvent.Records.Count} records...");

        foreach (var record in dynamoEvent.Records)
        {
            context.Logger.LogInformation($"Event ID: {record.EventID}");
            context.Logger.LogInformation($"Event Name: {record.EventName}");

            context.Logger.LogInformation(JsonSerializer.Serialize(record));
        }

        context.Logger.LogInformation("Stream processing complete.");
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 Go 搭配 Lambda 來使用 DynamoDB 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-lambda-go/events"
	"fmt"
)

func HandleRequest(ctx context.Context, event events.DynamoDBEvent) (*string, error) {
	if len(event.Records) == 0 {
		return nil, fmt.Errorf("received empty event")
	}

	for _, record := range event.Records {
	 	LogDynamoDBRecord(record)
	}

	message := fmt.Sprintf("Records processed: %d", len(event.Records))
	return &message, nil
}

func main() {
	lambda.Start(HandleRequest)
}

func LogDynamoDBRecord(record events.DynamoDBEventRecord){
	fmt.Println(record.EventID)
	fmt.Println(record.EventName)
	fmt.Printf("%+v\n", record.Change)
}
```

------
#### [ Java ]

**適用於 Java 2.x 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 Java 搭配 Lambda 來使用 DynamoDB 事件。  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent.DynamodbStreamRecord;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class example implements RequestHandler<DynamodbEvent, Void> {

    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    @Override
    public Void handleRequest(DynamodbEvent event, Context context) {
        System.out.println(GSON.toJson(event));
        event.getRecords().forEach(this::logDynamoDBRecord);
        return null;
    }

    private void logDynamoDBRecord(DynamodbStreamRecord record) {
        System.out.println(record.getEventID());
        System.out.println(record.getEventName());
        System.out.println("DynamoDB Record: " + GSON.toJson(record.getDynamodb()));
    }
}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 來使用 DynamoDB 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
    console.log(JSON.stringify(event, null, 2));
    event.Records.forEach(record => {
        logDynamoDBRecord(record);
    });
};

const logDynamoDBRecord = (record) => {
    console.log(record.eventID);
    console.log(record.eventName);
    console.log(`DynamoDB Record: ${JSON.stringify(record.dynamodb)}`);
};
```
使用 TypeScript 搭配 Lambda 來使用 DynamoDB 事件。  

```
export const handler = async (event, context) => {
    console.log(JSON.stringify(event, null, 2));
    event.Records.forEach(record => {
        logDynamoDBRecord(record);
    });
}
const logDynamoDBRecord = (record) => {
    console.log(record.eventID);
    console.log(record.eventName);
    console.log(`DynamoDB Record: ${JSON.stringify(record.dynamodb)}`);
};
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 來使用 DynamoDB 事件。  

```
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\DynamoDb\DynamoDbEvent;
use Bref\Event\DynamoDb\DynamoDbHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler extends DynamoDbHandler
{
    private StderrLogger $logger;

    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handleDynamoDb(DynamoDbEvent $event, Context $context): void
    {
        $this->logger->info("Processing DynamoDb table items");
        $records = $event->getRecords();

        foreach ($records as $record) {
            $eventName = $record->getEventName();
            $keys = $record->getKeys();
            $old = $record->getOldImage();
            $new = $record->getNewImage();
            
            $this->logger->info("Event Name:".$eventName."\n");
            $this->logger->info("Keys:". json_encode($keys)."\n");
            $this->logger->info("Old Image:". json_encode($old)."\n");
            $this->logger->info("New Image:". json_encode($new));
            
            // TODO: Do interesting work based on the new data

            // Any exception thrown will be logged and the invocation will be marked as failed
        }

        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords items");
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**適用於 Python (Boto3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 Python 搭配 Lambda 來使用 DynamoDB 事件。  

```
import json

def lambda_handler(event, context):
    print(json.dumps(event, indent=2))

    for record in event['Records']:
        log_dynamodb_record(record)

def log_dynamodb_record(record):
    print(record['eventID'])
    print(record['eventName'])
    print(f"DynamoDB Record: {json.dumps(record['dynamodb'])}")
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 來使用 DynamoDB 事件。  

```
def lambda_handler(event:, context:)
    return 'received empty event' if event['Records'].empty?
  
    event['Records'].each do |record|
      log_dynamodb_record(record)
    end
  
    "Records processed: #{event['Records'].length}"
  end
  
  def log_dynamodb_record(record)
    puts record['eventID']
    puts record['eventName']
    puts "DynamoDB Record: #{JSON.generate(record['dynamodb'])}"
  end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 來使用 DynamoDB 事件。  

```
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
use aws_lambda_events::{
    event::dynamodb::{Event, EventRecord},
   };


// Built with the following dependencies:
//lambda_runtime = "0.11.1"
//serde_json = "1.0"
//tokio = { version = "1", features = ["macros"] }
//tracing = { version = "0.1", features = ["log"] }
//tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
//aws_lambda_events = "0.15.0"

async fn function_handler(event: LambdaEvent<Event>) ->Result<(), Error> {
    
    let records = &event.payload.records;
    tracing::info!("event payload: {:?}",records);
    if records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(());
    }

    for record in records{
        log_dynamo_dbrecord(record);
    }

    tracing::info!("Dynamo db records processed");

    // Prepare the response
    Ok(())

}

fn log_dynamo_dbrecord(record: &EventRecord)-> Result<(), Error>{
    tracing::info!("EventId: {}", record.event_id);
    tracing::info!("EventName: {}", record.event_name);
    tracing::info!("DynamoDB Record: {:?}", record.change );
    Ok(())

}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
    .with_max_level(tracing::Level::INFO)
    .with_target(false)
    .without_time()
    .init();

    let func = service_fn(function_handler);
    lambda_runtime::run(func).await?;
    Ok(())
    
}
```

------

**建立函數**

1. 將範本程式碼複製到名為 `example.js` 的檔案。

1. 建立部署套件。

   ```
   zip function.zip example.js
   ```

1. 使用 `create-function` 命令建立一個 Lambda 函數。

   ```
   aws lambda create-function --function-name ProcessDynamoDBRecords \
       --zip-file fileb://function.zip --handler example.handler --runtime nodejs24.x \
       --role arn:aws:iam::111122223333:role/lambda-dynamodb-role
   ```

## 測試 Lambda 函數
<a name="with-dbb-invoke-manually"></a>

在此步驟中，您會使用 `invoke` AWS Lambda CLI 命令和下列範例 DynamoDB 事件手動叫用 Lambda 函數。將下列內容複製到名為 `input.txt` 的檔案。

**Example input.txt**  

```
{
   "Records":[
      {
         "eventID":"1",
         "eventName":"INSERT",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"111",
            "SizeBytes":26,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"2",
         "eventName":"MODIFY",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"222",
            "SizeBytes":59,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"3",
         "eventName":"REMOVE",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"333",
            "SizeBytes":38,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      }
   ]
}
```

執行以下 `invoke` 命令。

```
aws lambda invoke --function-name ProcessDynamoDBRecords \
    --cli-binary-format raw-in-base64-out \
    --payload file://input.txt outputfile.txt
```

如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

該函數會在回應本文中傳回字串 `message` 訊息。

在 `outputfile.txt` 檔案中確認輸出。

## 建立啟用串流的 DynamoDB 資料表
<a name="with-ddb-create-buckets"></a>

建立啟用串流的 Amazon DynamoDB 資料表。

**建立 DynamoDB 資料表**

1. 開啟 [DynamoDB 主控台](https://console.aws.amazon.com/dynamodb)。

1. 選擇 **Create Table** (建立資料表)。

1. 根據下列設定建立資料表。
   + **Table name (資料表名稱)** – **lambda-dynamodb-stream** 
   + **Primary key** (主要金鑰) - **id** (字串)

1. 選擇**建立**。

**啟用串流**

1. 開啟 [DynamoDB 主控台](https://console.aws.amazon.com/dynamodb)。

1. 選擇 **資料表**。

1. 選擇 **lambda-dynamodb-stream** 資料表。

1. 在 **匯出與串流** 下，選擇 **DynamoDB 串流詳細資訊** 。

1. 選擇 **Turn on (開啟)**。

1. 對於**檢視類型**，選擇**僅索引鍵屬性**。

1. 選擇**開啟串流**。

寫下串流 ARN。在下個步驟將串流與您的 Lambda 函數相關聯時會需要用到它。如需啟用串流的詳細資訊，請參閱[使用 DynamoDB Streams 擷取資料表活動](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html)。

## 在 中新增事件來源 AWS Lambda
<a name="with-ddb-attach-notification-configuration"></a>

在 AWS Lambda中建立事件來源映射。事件來源映射可將 DynamoDB 串流與您的 Lambda 函數相關聯。建立此事件來源映射後， 會 AWS Lambda 開始輪詢串流。

執行下列 AWS CLI `create-event-source-mapping` 命令。命令執行後，請記下 UUID。使用任何命令時，您會需要此 UUID 以參考到事件來源映射，例如當刪除事件來源映射的時候。

```
aws lambda create-event-source-mapping --function-name ProcessDynamoDBRecords \
    --batch-size 100 --starting-position LATEST --event-source DynamoDB-stream-arn
```

 這會在指定的 DynamoDB 串流和 Lambda 函數之間建立映射。您可以將 DynamoDB 串流與多個 Lambda 函數相關聯，也可以將相同的 Lambda 函數與多個串流相關聯。但是 Lambda 函數會共用其所共有之串流的讀取傳送量。

您可以執行下列命令來取得事件來源映射的清單。

```
aws lambda list-event-source-mappings
```

該清單傳回所有您建立的事件來源映射，並針對每個映射顯示 `LastProcessingResult` 和其他內容。此欄位可用在發生問題時，提供資訊豐富的訊息。例如 `No records processed`（表示 AWS Lambda 尚未開始輪詢或串流中沒有記錄） 和 `OK`（表示 AWS Lambda 成功從串流讀取記錄並叫用您的 Lambda 函數） 的值表示沒有問題。如果發生問題，您會收到錯誤訊息。

如果您有許多事件來源映射，請使用函數式稱參數來縮小結果。

```
aws lambda list-event-source-mappings --function-name ProcessDynamoDBRecords
```

## 測試設定
<a name="with-ddb-final-integration-test-no-iam"></a>

測試端對端的體驗。當您更新資料表時，DynamoDB 會將事件記錄寫入串流。當 AWS Lambda 輪詢串流時，若偵測到串流上的新記錄，便會透過傳送事件到函數來代表您調用 Lambda 函數。

1. 在 DynamoDB 主控台上針對資料表新增、更新、刪除項目。DynamoDB 會將這些動作的記錄寫入串流。

1. AWS Lambda 會輪詢串流，並在偵測到串流的更新時，透過傳入在串流中找到的事件資料來叫用 Lambda 函數。

1. 您的函數會執行並在 Amazon CloudWatch 中建立日誌。您可以驗證在 Amazon CloudWatch 主控台中報告的日誌。

## 後續步驟
<a name="with-ddb-next-steps"></a>

此教學課程介紹了使用 Lambda 處理 DynamoDB 串流事件的基礎知識。對於生產工作負載，建議實作部分批次回應邏輯，更有效率地處理個別記錄失敗。適用於 的 Powertools 批次[處理器公用程式](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/) AWS Lambda 可在 Python、TypeScript、.NET 和 Java 中使用，並為此提供強大的解決方案，可自動處理部分批次回應的複雜性，並減少成功處理記錄的重試次數。

## 清除您的資源
<a name="cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇**刪除**。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇 **刪除** 。

**若要刪除 DynamoDB 資料表**

1. 開啟 DynamoDB 主控台的 [資料表頁面](https://console.aws.amazon.com//dynamodb/home#tables:) 。

1. 選取您建立的資料表。

1. 選擇 **刪除** 。

1. 在文字方塊中輸入 **delete**。

1. 選擇 **刪除資料表** 。

# 使用 Lambda 函數處理 Amazon EC2 生命週期事件
<a name="services-ec2"></a>

您可以使用 AWS Lambda 處理來自 Amazon Elastic Compute Cloud 的生命週期事件，並管理 Amazon EC2 資源。Amazon EC2 就[生命週期事件](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-lifecycle.html)向 [Amazon EventBridge (CloudWatch Events)](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html) 傳送事件，例如執行個體狀態變更、Amazon Elastic Block Store 磁碟區快照完成，或排定 Spot 執行個體將終止。您可以設定 EventBridge (CloudWatch Events)，將這些事件轉遞至 Lambda 函數以進行處理。

EventBridge (CloudWatch Events) 會非同步地叫用您的 Lambda 函數與來自 Amazon EC2 的事件文件。

**Example 執行個體生命週期事件**  

```
{
    "version": "0",
    "id": "b6ba298a-7732-2226-xmpl-976312c1a050",
    "detail-type": "EC2 Instance State-change Notification",
    "source": "aws.ec2",
    "account": "111122223333",
    "time": "2019-10-02T17:59:30Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:ec2:us-east-1:111122223333:instance/i-0c314xmplcd5b8173"
    ],
    "detail": {
        "instance-id": "i-0c314xmplcd5b8173",
        "state": "running"
    }
}
```

如需設定事件的詳細資訊，請參閱[依排程調用 Lambda 函數](with-eventbridge-scheduler.md)。如需處理 Amazon EBS 快照通知的範例函數，請參閱[適用於 Amazon EBS 的 EventBridge 排程器](https://docs.aws.amazon.com/ebs/latest/userguide/ebs-cloud-watch-events.html)。

您也可以使用 AWS 開發套件，搭配 Amazon EC2 API 來管理執行個體和其他資源。

## 將許可授予 EventBridge (CloudWatch Events)
<a name="services-ec2-permissions"></a>

若要處理來自 Amazon EC2 的生命週期事件，EventBridge (CloudWatch Events) 需要叫用您函數的許可。此許可來自函數的[資源型政策](access-control-resource-based.md)。如果您使用 EventBridge (CloudWatch Events) 主控台設定事件觸發條件，則主控台會代您更新資源型政策。否則，新增如下的聲明：

**Example Amazon EC2 生命週期通知的資源型政策聲明**  

```
{
  "Sid": "ec2-events",
  "Effect": "Allow",
  "Principal": {
    "Service": "events.amazonaws.com"
  },
  "Action": "lambda:InvokeFunction",
  "Resource": "arn:aws:lambda:us-east-1:12456789012:function:my-function",
  "Condition": {
    "ArnLike": {
      "AWS:SourceArn": "arn:aws:events:us-east-1:12456789012:rule/*"
    }
  }
}
```

若要新增聲明，請使用 `add-permission` AWS CLI 命令。

```
aws lambda add-permission --action lambda:InvokeFunction --statement-id ec2-events \
--principal events.amazonaws.com --function-name my-function --source-arn 'arn:aws:events:us-east-1:12456789012:rule/*'
```

如果您的函數使用 AWS 開發套件來管理 Amazon EC2 資源，請將 Amazon EC2 許可新增到函數的[執行角色](lambda-intro-execution-role.md)。

# 使用 Lambda 處理 Application Load Balancer 請求
<a name="services-alb"></a>

您可以使用 Lambda 函數處理來自 Application Load Balancer 的請求。Elastic Load Balancing 支援 Lambda 函數作為 Application Load Balancer 的目標。使用負載平衡器規則，根據路徑或標頭值將 HTTP 請求路由至特定函式。由您的 Lambda 函數處理請求並傳回 HTTP 回應。

Elastic Load Balancer 將使用含有請求內文和中繼資料的事件，同步叫用您的 Lambda 函數。

**Example Application Load Balancer 請求事件**  

```
{
    "requestContext": {
        "elb": {
            "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/lambda-279XGJDqGZ5rsrHC2Fjr/49e9d65c45c6791a"
        }
    },
    "httpMethod": "GET",
    "path": "/lambda",
    "queryStringParameters": {
        "query": "1234ABCD"
    },
    "headers": {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "accept-encoding": "gzip",
        "accept-language": "en-US,en;q=0.9",
        "connection": "keep-alive",
        "host": "lambda-alb-123578498.us-east-1.elb.amazonaws.com",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
        "x-amzn-trace-id": "Root=1-5c536348-3d683b8b04734faae651f476",
        "x-forwarded-for": "72.12.164.125",
        "x-forwarded-port": "80",
        "x-forwarded-proto": "http",
        "x-imforwards": "20"
    },
    "body": "",
    "isBase64Encoded": False
}
```

您的函數會處理事件，並將 JSON 格式的回應文件傳回給負載平衡器。Elastic Load Balancing 會將文件轉換成 HTTP 成功或錯誤回應，並傳回給使用者。

**Example 回應文件格式**  

```
{
    "statusCode": 200,
    "statusDescription": "200 OK",
    "isBase64Encoded": False,
    "headers": {
        "Content-Type": "text/html"
    },
    "body": "<h1>Hello from Lambda!</h1>"
}
```

若要設定 Application Load Balancer 作為函數觸發條件，請授予 Elastic Load Balancing 執行函數的許可、建立目標群組將請求路由至函數，並且為負載平衡器加入規則以傳送請求至目標群組。

使用 `add-permission` 命令，將許可陳述式加入至函式以資源為基礎的政策。

```
aws lambda add-permission --function-name alb-function \
--statement-id load-balancer --action "lambda:InvokeFunction" \
--principal elasticloadbalancing.amazonaws.com
```

您應該會看到下列輸出：

```
{
    "Statement": "{\"Sid\":\"load-balancer\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"elasticloadbalancing.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-west-2:123456789012:function:alb-function\"}"
}
```

如需有關設定 Application Load Balancer 接聽程式和目標群組的說明，請參閱 *Application Load Balancer 使用者指南*中的 [Lambda 函數作為目標](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html)。

## Powertools for AWS Lambda 的事件處理常式
<a name="services-alb-powertools"></a>

來自 Powertools for AWS Lambda 工具組的事件處理常式，可在撰寫 Application Load Balancer 調用的 Lambda 函數時，提供路由、中介軟體、CORS 組態、OpenAPI 規格產生、請求驗證、錯誤處理和其他實用功能。該事件處理常式公用程式適用於 Python。如需詳細資訊，請參閱 *Powertools for AWS Lambda (Python) 文件*中的[事件處理常式 REST API](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/)。

### Python
<a name="services-alb-powertools-python"></a>

```
import requests
from requests import Response

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import ALBResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = ALBResolver()


@app.get("/todos")
@tracer.capture_method
def get_todos():
    todos: Response = requests.get("https://jsonplaceholder.typicode.com/todos")
    todos.raise_for_status()

    # for brevity, we'll limit to the first 10 only
    return {"todos": todos.json()[:10]}


# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.APPLICATION_LOAD_BALANCER)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
    return app.resolve(event, context)
```

# 依排程調用 Lambda 函數
<a name="with-eventbridge-scheduler"></a>

[Amazon EventBridge 排程器](https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html)是無伺服器排程器，可讓您從單一受管的中央服務建立、執行及管理任務。使用 EventBridge 排程器，您可以使用週期性模式的 Cron 和 Rate 運算式來建立排程，或設定一次性呼叫。您可以設定彈性的交付時段、定義重試次數上限，以及設定未處理事件的最長保留時間。

當您使用 Lambda 設定 EventBridge 排程器時，EventBridge 排程器會以非同步方式調用 Lambda 函數。本頁面說明如何使用 EventBridge 排程器，依照排程調用 Lambda 函數。

## 設定執行角色
<a name="using-eventbridge-scheduler-execution-role"></a>

 當您建立新排程時，EventBridge 排程器必須具有代表您調用其目標 API 操作的權限。您可以使用*執行角色*，授與 EventBridge 排程器這些許可。排程執行角色所連接的許可政策會定義哪些是必要許可。許可是否為必要權限，取決於您希望 EventBridge 排程器調用的目標 API。

 您在 EventBridge 排程器主控台建立排程時 (如以下程序所述)，EventBridge 排程器會根據您選取的目標自動設定執行角色。如果您要使用 EventBridge 排程器 SDK、AWS CLI 或 CloudFormation 建立排程，您必須具備現有的執行角色，授與 EventBridge 排程器調用目標所需的許可。如需手動設定排程執行角色的詳細資訊，請參閱《EventBridge 排程器使用者指南》**中的[設定執行角色](https://docs.aws.amazon.com/scheduler/latest/UserGuide/setting-up.html#setting-up-execution-role)。

## 建立排程
<a name="using-eventbridge-scheduler-create"></a>

**使用主控台建立排程**

1. 前往 [https://console.aws.amazon.com/scheduler/home](https://console.aws.amazon.com/scheduler/home/) 開啟 Amazon EventBridge 排程器。

1.  在**排程**頁面上，選擇**建立排程**。

1.  在**指定排程詳細資訊**頁面的**排程名稱和描述**區段中，執行以下動作：

   1. 在**排程名稱**中，輸入排程的名稱，例如 **MyTestSchedule**。

   1. (選用) 在**描述**中，輸入對排程的描述，例如 **My first schedule**。

   1. 針對**排程群組**，從下拉式清單中選擇排程群組。如果您沒有群組，請選擇**預設值**。若要建立排程群組，請選擇**建立自己的排程**。

      您可以使用排程群組，為不同群組的排程加上標籤。

1. 

   1. 選擇排程選項。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/with-eventbridge-scheduler.html)

1. (選用) 如果您在上一個步驟中選擇**週期性排程**，請在**時間範圍**區段執行以下動作：

   1. 針對**時區**選擇時區。

   1. 對於**開始日期和時間**，依 `YYYY/MM/DD` 格式輸入有效日期，接著依 24 小時的 `hh:mm` 格式指定時間戳記。

   1. 對於**結束日期和時間**，依 `YYYY/MM/DD` 格式輸入有效日期，接著依 24 小時的 `hh:mm` 格式指定時間戳記。

1. 選擇**下一步**。

1. 在**選取目標**頁面上，選擇 EventBridge 排程器調用的 AWS API 操作：

   1. 選擇**AWS Lambda調用**。

   1. 在**調用**區段中，選取函數或選擇**建立新的 Lambda 函數**。

   1. (選用) 輸入 JSON 承載。如果您未輸入承載，EventBridge 排程器會使用空白事件來調用函數。

1. 選擇**下一步**。

1. 在**設定**頁面執行以下動作：

   1. 若要開啟排程，請在**排程狀態**底下切換到**啟用排程**。

   1. 若要設定排程的重試政策，請在**重試政策和無效字母佇列 (DLQ)** 底下執行以下動作：
      + 切換到**重試**。
      + 針對**事件的最長存留期**，輸入 EventBridge 排程器保留未處理事件的最大**時數**和**分鐘數**。
      + 時間最長可設為 24 小時。
      + 針對**重試次數上限**，輸入目標傳回錯誤時，EventBridge 排程器重新嘗試執行排程的次數上限。

         最大值為重試 185 次。

      設定好重試政策後，如果排程無法調用其目標，EventBridge 排程器會重新執行排程。一旦設定此功能，您就必須設定排程的最長保留時間和重試次數。

   1. 選擇 EventBridge 排程器儲存未交付事件的位置。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/with-eventbridge-scheduler.html)

   1. 若要使用由客戶管理的金鑰加密您的目標輸入，請在**加密**底下選擇**自訂加密設定 (進階)**。

      如果選擇此選項，請輸入現有的 KMS 金鑰 ARN，或選擇**建立 AWS KMS key**，以導覽至 AWS KMS 控制台。如需 EventBridge 排程器如何加密靜態資料的詳細資訊，請參閱《Amazon EventBridge 排程器使用者指南》中的[靜態加密](https://docs.aws.amazon.com/scheduler/latest/UserGuide/encryption-rest.html)**。

   1. 若要讓 EventBridge 排程器為您建立新的執行角色，請選擇**為此排程建立新角色**。接著輸入**角色名稱**。如果您選擇此選項，EventBridge 排程器會將範本化目標所需的必要許可與角色連接。

1. 選擇**下一步**。

1.  在**檢閱和建立排程**頁面上，檢閱排程的詳細資訊。在每個區段中選擇**編輯**，即可返回該步驟並編輯其詳細資訊。

1. 選擇**建立排程**。

   您可以在**排程**頁面檢視新建立和現有的排程。在**狀態**欄底下，確認您的新排程狀態為**已啟用**。

若要確認 EventBridge 排程器是否順利調用函數，請[檢查 Amazon CloudWatch 日誌](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)。

## 相關資源
<a name="using-eventbridge-scheduler-related-resources"></a>

 如需 EventBridge 排程器的詳細資訊，請參閱下列內容：
+ [EventBridge 排程器使用者指南](https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html)
+ [EventBridge 排程器 API 參考](https://docs.aws.amazon.com/scheduler/latest/APIReference/Welcome.html)
+ [EventBridge 排程器定價](https://aws.amazon.com/eventbridge/pricing/#Scheduler)

# 搭配使用 AWS Lambda 與 AWS IoT
<a name="services-iot"></a>

AWS IoT 提供網際網路連線裝置 (例如感應器) 和 AWS 雲端間的安全通訊。這可以讓您收集、存放和分析來自多個裝置的遙測資料。

您可以為您的裝置建立 AWS IoT 規則，使其和 AWS 服務互動。AWS IoT [規則引擎](https://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html)提供 SQL 類型的語言，可讓您從訊息酬載中選取資料，以及傳送資料至其他服務，例如 Amazon S3、Amazon DynamoDB 和 AWS Lambda。當您希望叫用其他 AWS 服務或第三方服務時，您可以定義規則來叫用 Lambda 函數。

當傳入的 IoT 訊息觸發規則時，AWS IoT 會以[非同步](invocation-async.md)方式叫用您的 Lambda 函數，並將資料從 IoT 訊息傳遞至函數。

以下範例示範從溫室感應器讀取濕度。**資料列**和**資料行**的值會識別感應器的位置。此範例事件是以 [AWS IoT 規則教學](https://docs.aws.amazon.com/iot/latest/developerguide/iot-rules-tutorial.html)中的溫室類型為基礎。

**Example AWS IoT 訊息事件**  

```
{
    "row" : "10",
    "pos" : "23",
    "moisture" : "75"
}
```

針對非同步叫用，Lambda 會將訊息排入佇列，並且在您的函式傳回錯誤時[重試](invocation-retries.md)。為您的函數設定[目的地](invocation-async-retain-records.md#invocation-async-destinations)來保留函數無法處理的事件。

您需要授予許可，AWS IoT 服務才能叫用您的 Lambda 函數。使用 `add-permission` 命令，將許可陳述式加入至函式以資源為基礎的政策。

```
aws lambda add-permission --function-name my-function \
--statement-id iot-events --action "lambda:InvokeFunction" --principal iot.amazonaws.com
```

您應該會看到下列輸出：

```
{
    "Statement": "{\"Sid\":\"iot-events\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"iot.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-1:123456789012:function:my-function\"}"
}
```

如需如何搭配使用 Lambda 與 AWS IoT 的詳細資訊，請參閱[建立 AWS Lambda 規則](https://docs.aws.amazon.com/iot/latest/developerguide/iot-lambda-rule.html)。

# 使用 Lambda 處理來自 Amazon Kinesis Data Streams 的記錄
<a name="with-kinesis"></a>

您可以使用 Lambda 函數來處理 [Amazon Kinesis 資料串流](https://docs.aws.amazon.com/streams/latest/dev/introduction.html)中的記錄。您可以將 Lambda 函數對應至 Kinesis Data Streams 共用輸送量取用程式 (標準迭代程式)，或對應至具有[增強散發](https://docs.aws.amazon.com/kinesis/latest/dev/enhanced-consumers.html)功能的專用輸送量取用程式。對於標準迭代程式，Lambda 會使用 HTTP 協定輪詢 Kinesis 串流中的每個碎片以尋找記錄。事件來源映射會與碎片的其他取用者共用讀取傳輸量。

 如需 Kinesis 資料串流的詳細資訊，請參閱[從 Amazon Kinesis Data Streams 讀取資料](https://docs.aws.amazon.com/kinesis/latest/dev/building-consumers.html)。

**注意**  
Kinesis 會收取每個碎片的費用，以及從串流讀取資料的增強型散發。如需定價的詳細資訊，請參閱 [Amazon Kinesis 定價](https://aws.amazon.com/kinesis/data-streams/pricing)。

## 輪詢和批次處理串流
<a name="kinesis-polling-and-batching"></a>

Lambda 會從資料串流讀取記錄並透過包含串流記錄的事件[同步](invocation-sync.md)調用函數。Lambda 會讀取批次中的記錄並調用函數，以處理來自該批次的記錄。每個批次包含來自單一碎片/資料串流的記錄。

您的 Lambda 函數是適用於資料串流的取用者應用程式。其會從每個碎片中一次處理一個批次的記錄。您可以將 Lambda 函數對應至共用輸送量取用程式 (標準迭代程式)，或對應至具有增強散發功能的專用輸送量取用程式。
+ **標準迭代器：**Lambda 會輪詢 Kinesis 串流中的每個碎片，其記錄的基本速率為每秒一次。有更多記錄可用時，Lambda 會持續處理批次，直到函數掌握串流資訊。事件來源映射會與碎片的其他取用者共用讀取傳輸量。
+ **增強散發功能：**若要將延遲降至最低，並將讀取傳輸量增至最大，請建立具有[增強散發功能](https://docs.aws.amazon.com/streams/latest/dev/enhanced-consumers.html)的資料串流取用者。增強散發取用者會取得每個碎片的專用連線，其不會影響其他從串流讀取的應用程式。串流取用者會使用 HTTP/2 來減少延遲，方法為透過長期連線將記錄推送至 Lambda，以及透過壓縮請求標頭。您可以使用 Kinesis [RegisterStreamConsumer](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_RegisterStreamConsumer.html) API，建立串流取用者。

```
aws kinesis register-stream-consumer \
--consumer-name con1 \
--stream-arn arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream
```

您應該會看到下列輸出：

```
{
    "Consumer": {
        "ConsumerName": "con1",
        "ConsumerARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream/consumer/con1:1540591608",
        "ConsumerStatus": "CREATING",
        "ConsumerCreationTimestamp": 1540591608.0
    }
}
```

若要增加函數處理記錄的速度，[請將碎片新增至您的資料串流](https://repost.aws/knowledge-center/kinesis-data-streams-open-shards)。Lambda 會依序在每個碎片中處理記錄。如果您的函數傳回錯誤，則會停止處理碎片中的其他記錄。碎片越多，要一次處理的批次越多，這會降低錯誤對並行的影響。

如果您的函數無法擴展至可處理並行批次的總數，您可以[請求增加配額](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html)，或為您的函數[保留並行](configuration-concurrency.md)。

Lambda 預設會在記錄可用時立即調用函數。如果 Lambda 從事件來源中讀取的批次只有一筆記錄，Lambda 只會傳送一筆記錄至函數。為避免調用具有少量記錄的函數，您可設定*批次間隔*，請求事件來源緩衝記錄最長達五分鐘。調用函數之前，Lambda 會繼續從事件來源中讀取記錄，直到收集到完整批次、批次間隔到期或者批次達到 6 MB 的承載限制。如需更多詳細資訊，請參閱 [批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)。

**警告**  
Lambda 事件來源映射至少會處理每個事件一次，而且可能會重複處理記錄。為避免與重複事件相關的潛在問題，強烈建議您讓函數程式碼具有等冪性。如需詳細資訊，請參閱 AWS 知識中心中的[如何讓 Lambda 函數具有冪等性](https://repost.aws/knowledge-center/lambda-function-idempotent)。

Lambda 在傳送下一批進行處理前不會等待任何已設定的[擴充](lambda-extensions.md)完成。換句話說，當 Lambda 處理下一批記錄時，您的擴充功能可能會繼續執行。如果您違反任何帳戶的 [並行](lambda-concurrency.md) 設定或限制，便可能會產生限流的問題。若要偵測此是否為潛在問題，請監控您的函數，並確認您看到的 [並行指標](monitoring-concurrency.md#general-concurrency-metrics) 是否高於事件來源映射的預期值。由於兩次調用之間的時間很短，Lambda 可能會短暫報告比碎片數目更高的並行用量。即使對於沒有延伸項目的 Lambda 函數也可能如此。

設定 [ParallelizationFactor](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-ParallelizationFactor) 設定，同時使用多個 Lambda 調用來處理 Kinesis 資料串流的一個碎片。您可以透過從 1 (預設) 到 10 的並行化因子指定 Lambda 從碎片輪詢的並行批次數。例如，當 `ParallelizationFactor` 設定為 2 時，您最多可以有 200 個並行 Lambda 調用，來處理 100 個 Kinesis 資料碎片 (不過在實務中，`ConcurrentExecutions` 指標可能有不同值)。當資料量急劇波動並且 `IteratorAge` 高時，這有助於縱向擴展處理輸送量。如果增加每個碎片的並行批次數量，則 Lambda 仍會確保在分割區索引鍵層級進行順序處理。

您也可以搭配 Kinesis 彙總使用 `ParallelizationFactor`。事件來源映射的行為取決於您是否使用[增強型散發](https://docs.aws.amazon.com/streams/latest/dev/enhanced-consumers.html)：
+ **沒有使用增強型散發**：彙總事件內的所有事件都必須具有相同的分割區索引鍵。分割區索引鍵也必須與彙總事件的分割區索引鍵相符。如果彙總事件內的事件具有不同的分割區索引鍵，則 Lambda 無法保證依分割區索引鍵依序處理事件。
+ **使用增強型散發**：首先，Lambda 會將彙總的事件解碼為其個別事件。彙總的事件可以具有與其包含的事件不同的分割區索引鍵。不過，未對應至分割區索引鍵的事件會[遭到捨棄和遺失](https://github.com/awslabs/kinesis-aggregation/blob/master/potential_data_loss.md)。Lambda 不會處理這些事件，也不會將其傳送至設定的失敗目的地。

## 範例事件
<a name="services-kinesis-event-example"></a>

**Example**  

```
{
    "Records": [
        {
            "kinesis": {
                "kinesisSchemaVersion": "1.0",
                "partitionKey": "1",
                "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
                "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
                "approximateArrivalTimestamp": 1545084650.987
            },
            "eventSource": "aws:kinesis",
            "eventVersion": "1.0",
            "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
            "eventName": "aws:kinesis:record",
            "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role",
            "awsRegion": "us-east-2",
            "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream"
        },
        {
            "kinesis": {
                "kinesisSchemaVersion": "1.0",
                "partitionKey": "1",
                "sequenceNumber": "49590338271490256608559692540925702759324208523137515618",
                "data": "VGhpcyBpcyBvbmx5IGEgdGVzdC4=",
                "approximateArrivalTimestamp": 1545084711.166
            },
            "eventSource": "aws:kinesis",
            "eventVersion": "1.0",
            "eventID": "shardId-000000000006:49590338271490256608559692540925702759324208523137515618",
            "eventName": "aws:kinesis:record",
            "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role",
            "awsRegion": "us-east-2",
            "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream"
        }
    ]
}
```

# 使用 Lambda 處理 Amazon Kinesis Data Streams 記錄
<a name="services-kinesis-create"></a>

若要使用 Lambda 處理 Amazon Kinesis Data Streams 記錄，請建立 Lambda 事件來源映射。您可以將 Lambda 函式映射至標準迭代器或增強型散發取用者。如需詳細資訊，請參閱[輪詢和批次處理串流](with-kinesis.md#kinesis-polling-and-batching)。

## 建立 Kinesis 事件來源映射
<a name="services-kinesis-eventsourcemapping"></a>

若要使用資料串流中的記錄調用您的 Lambda 函數，請建立一個[事件來源映射](invocation-eventsourcemapping.md)。您可以建立多個事件來源映射，來使用多個 Lambda 函數處理相同資料，或使用單一函數處理來自多個資料串流的項目。處理來自多個串流的項目時，每個批次將僅包含來自單一碎片或串流的記錄。

您可以設定事件來源映射，以處理來自不同 AWS 帳戶中的串流的記錄。如需詳細資訊，請參閱 [建立跨帳戶事件來源映射](#services-kinesis-eventsourcemapping-cross-account)。

建立事件來源映射之前，您需要授予 Lambda 函數從 Kinesis 資料串流讀取的許可。Lambda 需要以下許可，才能管理與 Kinesis 資料串流相關的資源：
+ [kinesis:DescribeStream](https://docs.aws.amazon.com/lambda/latest/api/API_DescribeStream.html)
+ [kinesis:DescribeStreamSummary](https://docs.aws.amazon.com/lambda/latest/api/API_DescribeStreamSummary.html)
+ [kinesis:GetRecords](https://docs.aws.amazon.com/lambda/latest/api/API_GetRecords.html)
+ [kinesis:GetShardIterator](https://docs.aws.amazon.com/lambda/latest/api/API_GetShardIterator.html)
+ [kinesis:ListShards](https://docs.aws.amazon.com/lambda/latest/api/API_ListShards.html)
+ [kinesis:SubscribeToShard](https://docs.aws.amazon.com/lambda/latest/api/API_SubscribeToShard.html)

 AWS 受管政策 [AWSLambdaKinesisExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaKinesisExecutionRole.html) 包含這些許可。如下列程序所述，將此受管政策新增至您的函數。

**注意**  
無需 `kinesis:ListStreams` 許可，即可為 Kinesis 建立並管理事件來源映射。但是，如果您在主控台中建立事件來源映射卻並不具備此許可，將無法從下拉式清單中選取 Kinesis 串流，且主控台會顯示錯誤。若要建立事件來源映射，需要手動輸入串流的 Amazon Resource Name (ARN)。
Lambda 會在重試失敗的調用時發起 `kinesis:GetRecords` 與 `kinesis:GetShardIterator` API 呼叫。

------
#### [ AWS 管理主控台 ]

**若要將 Kinesis 許可新增至函數**

1. 開啟 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)，然後選取您的函數。

1. 在**組態**索引標籤中，選擇**許可**。

1. 在**執行角色**窗格的**角色名稱**下，選擇函數執行角色的連結。此連結會在 IAM 主控台中開啟該角色的頁面。

1. 在**許可政策**窗格中，選擇**新增許可**，然後選取**附接政策**。

1. 在搜尋欄位中輸入 **AWSLambdaKinesisExecutionRole**。

1. 選取政策旁邊的核取方塊，然後選擇**新增許可**。

------
#### [ AWS CLI ]

**若要將 Kinesis 許可新增至函數**
+ 執行下列 CLI 命令，將 `AWSLambdaKinesisExecutionRole` 政策新增至函數的執行角色：

  ```
  aws iam attach-role-policy \
  --role-name MyFunctionRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaKinesisExecutionRole
  ```

------
#### [ AWS SAM ]

**若要將 Kinesis 許可新增至函數**
+ 在函數定義中，新增 `Policies` 屬性，如下列範例所示：

  ```
  Resources:
    MyFunction:
      Type: AWS::Serverless::Function
      Properties:
        CodeUri: ./my-function/
        Handler: index.handler
        Runtime: nodejs24.x
        Policies:
          - AWSLambdaKinesisExecutionRole
  ```

------

設定需要的許可後，建立事件來源映射。

------
#### [ AWS 管理主控台 ]

**若要建立 Kinesis 事件來源映射**

1. 開啟 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)，然後選取您的函數。

1. 在**函數概觀**窗格中，選擇**新增觸發條件**。

1. 在**觸發條件組態**下，針對來源選取 **Kinesis**。

1. 選取您要為之建立事件來源映射的 Kinesis 串流，以及 (選用) 串流的取用者。

1. (選用) 編輯事件來源映射的**批次大小**、**開始位置**和**批次時段**。

1. 選擇**新增**。

當從主控台建立事件來源映射時，您的 IAM 角色必須有 [kinesis:ListStreams](https://docs.aws.amazon.com/lambda/latest/api/API_ListStreams.html) 和 [kinesis:ListStreamConsumers](https://docs.aws.amazon.com/lambda/latest/api/API_ListStreamConsumers.html) 許可。

------
#### [ AWS CLI ]

**若要建立 Kinesis 事件來源映射**
+ 執行下列 CLI 命令以建立 Kinesis 事件來源映射。根據您的使用案例，選擇您自己的批次大小和開始位置。

  ```
  aws lambda create-event-source-mapping \
  --function-name MyFunction \
  --event-source-arn arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream \
  --starting-position LATEST \
  --batch-size 100
  ```

若要指定批次處理時段，請新增 `--maximum-batching-window-in-seconds` 選項。如需使用此參數和其他參數的詳細資訊，請參閱《AWS CLI 命令參考》**中的 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html)。

------
#### [ AWS SAM ]

**若要建立 Kinesis 事件來源映射**
+ 在函數定義中，新增 `KinesisEvent` 屬性，如下列範例所示：

  ```
  Resources:
    MyFunction:
      Type: AWS::Serverless::Function
      Properties:
        CodeUri: ./my-function/
        Handler: index.handler
        Runtime: nodejs24.x
        Policies:
          - AWSLambdaKinesisExecutionRole
        Events:
          KinesisEvent:
            Type: Kinesis
            Properties:
              Stream: !GetAtt MyKinesisStream.Arn
              StartingPosition: LATEST
              BatchSize: 100
  
    MyKinesisStream:
      Type: AWS::Kinesis::Stream
      Properties:
        ShardCount: 1
  ```

若要進一步了解如何在 中建立 Kinesis Data Streams 的事件來源映射 AWS SAM，請參閱《 *AWS Serverless Application Model 開發人員指南*》中的 [Kinesis](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-kinesis.html)。

------

## 輪詢和串流開始位置
<a name="services-kinesis-stream-start-pos"></a>

請注意，建立和更新事件來源映射期間的串流輪詢最終會一致。
+ 在建立事件來源映射期間，從串流開始輪詢事件可能需要幾分鐘時間。
+ 在更新事件來源映射期間，從串流停止並重新開始輪詢事件可能需要幾分鐘時間。

這種行為表示如果您指定 `LATEST` 當作串流的開始位置，事件來源映射可能會在建立或更新期間遺漏事件。若要確保沒有遺漏任何事件，請將串流開始位置指定為 `TRIM_HORIZON` 或 `AT_TIMESTAMP`。

## 建立跨帳戶事件來源映射
<a name="services-kinesis-eventsourcemapping-cross-account"></a>

Amazon Kinesis Data Streams 支援[資源型政策](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html)。因此，您可以在另一個帳戶中 AWS 帳戶 使用 Lambda 函數處理擷取至串流的資料。

若要使用不同 Kinesis 串流為您的 Lambda 函數建立事件來源映射 AWS 帳戶，您必須使用資源型政策來設定串流，以授予 Lambda 函數讀取項目的許可。若要了解如何設定串流以允許跨帳戶存取，請參閱《*Amazon Kinesis Streams Developer 指南*》中的[使用跨帳戶 AWS Lambda 函數共用存取權](https://docs.aws.amazon.com/streams/latest/dev/resource-based-policy-examples.html#Resource-based-policy-examples-lambda)。

使用為您的 Lambda 函數提供所需許可的資源型政策設定串流後，使用上一節所述的任何方法建立事件來源映射。

如果您選擇使用 Lambda 主控台來建立事件來源映射，則請將串流的 ARN 直接貼入輸入欄位。如果您想要為串流指定取用者，則貼上取用者的 ARN 即會自動填入串流欄位。

# 使用 Kinesis Data Streams 和 Lambda 設定部分批次回應
<a name="services-kinesis-batchfailurereporting"></a>

取用和處理事件來源的串流資料時，依預設，只有在批次成功完成時，Lambda 檢查點才會到批次的最高序號。Lambda 會將所有其他結果視為完全失敗，並重試處理批次，直至達到重試限制。若要在處理串流的批次時允許部分成功，請開啟 `ReportBatchItemFailures`。允許部分成功有助於減少記錄的重試次數，但其不會完全消除在成功記錄中重試的可能性。

若要開啟 `ReportBatchItemFailures`，請在 [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionResponseTypes) 清單中包含枚舉值 **ReportBatchItemFailures**。此清單指示已為您的函數啟用哪些回應類型。您可以在[建立](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html)或[更新](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)事件來源映射時設定此清單。

**注意**  
即使函式程式碼傳回了部分批次失敗回應，除非針對事件來源映射明確啟用 `ReportBatchItemFailures` 功能，否則 Lambda 將不會處理這些回應。

## 報告語法
<a name="streams-batchfailurereporting-syntax"></a>

設定批次項目失敗的報告時，會傳回 `StreamsEventResponse` 類別，其中包含批次項目失敗的清單。您可以使用 `StreamsEventResponse` 物件，來傳回批次中第一個失敗記錄的序號。您還可以使用正確的回應語法，建立自己的自訂類別。下列 JSON 結構顯示所需的回應語法：

```
{ 
  "batchItemFailures": [ 
        {
            "itemIdentifier": "<SequenceNumber>"
        }
    ]
}
```

**注意**  
如果 `batchItemFailures` 陣列包含多個項目，則 Lambda 會使用具有最低序列號的記錄作為檢查點。然後，Lambda 會重試從該檢查點開始的所有記錄。

## 成功與失敗條件
<a name="streams-batchfailurereporting-conditions"></a>

如果您傳回下列任一項目，Lambda 會將批次視為完全成功：
+ 空白 `batchItemFailure` 清單
+ Null `batchItemFailure` 清單
+ 空白 `EventResponse`
+ Null `EventResponse`

如果您傳回下列任一項目，Lambda 會將批次視為完全失敗：
+ 空白字串 `itemIdentifier`
+ Null `itemIdentifier`
+ 具有錯誤金鑰名稱的 `itemIdentifier`

Lambda 會根據您的重試政策來重試失敗。

## 將批次平分
<a name="streams-batchfailurereporting-bisect"></a>

如果您的調用失敗且 `BisectBatchOnFunctionError` 已開啟，則無論您的 `ReportBatchItemFailures` 設定如何，批次都會被平分。

收到部分批次成功回應且 `BisectBatchOnFunctionError` 和 `ReportBatchItemFailures` 均開啟時，批次會依傳回的序號進行平分，並且 Lambda 僅會重試剩餘的記錄。

為了簡化部分批次回應邏輯的實作，請考慮使用 Powertools 中的 [Batch Processor 公用程式](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/) AWS Lambda，其會自動為您處理這些複雜性。

以下範例函數程式碼會傳回批次中失敗訊息 ID 的清單：

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 報告 Kinesis 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
﻿using System.Text;
using System.Text.Json.Serialization;
using Amazon.Lambda.Core;
using Amazon.Lambda.KinesisEvents;
using AWS.Lambda.Powertools.Logging;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace KinesisIntegration;

public class Function
{
    // Powertools Logger requires an environment variables against your function
    // POWERTOOLS_SERVICE_NAME
    [Logging(LogEvent = true)]
    public async Task<StreamsEventResponse> FunctionHandler(KinesisEvent evnt, ILambdaContext context)
    {
        if (evnt.Records.Count == 0)
        {
            Logger.LogInformation("Empty Kinesis Event received");
            return new StreamsEventResponse();
        }

        foreach (var record in evnt.Records)
        {
            try
            {
                Logger.LogInformation($"Processed Event with EventId: {record.EventId}");
                string data = await GetRecordDataAsync(record.Kinesis, context);
                Logger.LogInformation($"Data: {data}");
                // TODO: Do interesting work based on the new data
            }
            catch (Exception ex)
            {
                Logger.LogError($"An error occurred {ex.Message}");
                /* Since we are working with streams, we can return the failed item immediately.
                   Lambda will immediately begin to retry processing from this failed item onwards. */
                return new StreamsEventResponse
                {
                    BatchItemFailures = new List<StreamsEventResponse.BatchItemFailure>
                    {
                        new StreamsEventResponse.BatchItemFailure { ItemIdentifier = record.Kinesis.SequenceNumber }
                    }
                };
            }
        }
        Logger.LogInformation($"Successfully processed {evnt.Records.Count} records.");
        return new StreamsEventResponse();
    }

    private async Task<string> GetRecordDataAsync(KinesisEvent.Record record, ILambdaContext context)
    {
        byte[] bytes = record.Data.ToArray();
        string data = Encoding.UTF8.GetString(bytes);
        await Task.CompletedTask; //Placeholder for actual async work
        return data;
    }
}

public class StreamsEventResponse
{
    [JsonPropertyName("batchItemFailures")]
    public IList<BatchItemFailure> BatchItemFailures { get; set; }
    public class BatchItemFailure
    {
        [JsonPropertyName("itemIdentifier")]
        public string ItemIdentifier { get; set; }
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Go 搭配 Lambda 來報告 Kinesis 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"fmt"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context, kinesisEvent events.KinesisEvent) (map[string]interface{}, error) {
	batchItemFailures := []map[string]interface{}{}

	for _, record := range kinesisEvent.Records {
		curRecordSequenceNumber := ""

		// Process your record
		if /* Your record processing condition here */ {
			curRecordSequenceNumber = record.Kinesis.SequenceNumber
		}

		// Add a condition to check if the record processing failed
		if curRecordSequenceNumber != "" {
			batchItemFailures = append(batchItemFailures, map[string]interface{}{"itemIdentifier": curRecordSequenceNumber})
		}
	}

	kinesisBatchResponse := map[string]interface{}{
		"batchItemFailures": batchItemFailures,
	}
	return kinesisBatchResponse, nil
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
透過使用 Java 的 Lambda 報告 Kinesis 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class ProcessKinesisRecords implements RequestHandler<KinesisEvent, StreamsEventResponse> {

    @Override
    public StreamsEventResponse handleRequest(KinesisEvent input, Context context) {

        List<StreamsEventResponse.BatchItemFailure> batchItemFailures = new ArrayList<>();
        String curRecordSequenceNumber = "";

        for (KinesisEvent.KinesisEventRecord kinesisEventRecord : input.getRecords()) {
            try {
                //Process your record
                KinesisEvent.Record kinesisRecord = kinesisEventRecord.getKinesis();
                curRecordSequenceNumber = kinesisRecord.getSequenceNumber();

            } catch (Exception e) {
                /* Since we are working with streams, we can return the failed item immediately.
                   Lambda will immediately begin to retry processing from this failed item onwards. */
                batchItemFailures.add(new StreamsEventResponse.BatchItemFailure(curRecordSequenceNumber));
                return new StreamsEventResponse(batchItemFailures);
            }
        }
       
       return new StreamsEventResponse(batchItemFailures);   
    }
}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/blob/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Javascript 搭配 Lambda 報告 Kinesis 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const record of event.Records) {
    try {
      console.log(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      console.log(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      console.error(`An error occurred ${err}`);
      /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
      return {
        batchItemFailures: [{ itemIdentifier: record.kinesis.sequenceNumber }],
      };
    }
  }
  console.log(`Successfully processed ${event.Records.length} records.`);
  return { batchItemFailures: [] };
};

async function getRecordDataAsync(payload) {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```
使用 TypeScript 搭配 Lambda 報告 Kinesis 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import {
  KinesisStreamEvent,
  Context,
  KinesisStreamHandler,
  KinesisStreamRecordPayload,
  KinesisStreamBatchResponse,
} from "aws-lambda";
import { Buffer } from "buffer";
import { Logger } from "@aws-lambda-powertools/logger";

const logger = new Logger({
  logLevel: "INFO",
  serviceName: "kinesis-stream-handler-sample",
});

export const functionHandler: KinesisStreamHandler = async (
  event: KinesisStreamEvent,
  context: Context
): Promise<KinesisStreamBatchResponse> => {
  for (const record of event.Records) {
    try {
      logger.info(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      logger.info(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      logger.error(`An error occurred ${err}`);
      /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
      return {
        batchItemFailures: [{ itemIdentifier: record.kinesis.sequenceNumber }],
      };
    }
  }
  logger.info(`Successfully processed ${event.Records.length} records.`);
  return { batchItemFailures: [] };
};

async function getRecordDataAsync(
  payload: KinesisStreamRecordPayload
): Promise<string> {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 來報告 Kinesis 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Kinesis\KinesisEvent;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handle(mixed $event, Context $context): array
    {
        $kinesisEvent = new KinesisEvent($event);
        $this->logger->info("Processing records");
        $records = $kinesisEvent->getRecords();

        $failedRecords = [];
        foreach ($records as $record) {
            try {
                $data = $record->getData();
                $this->logger->info(json_encode($data));
                // TODO: Do interesting work based on the new data
            } catch (Exception $e) {
                $this->logger->error($e->getMessage());
                // failed processing the record
                $failedRecords[] = $record->getSequenceNumber();
            }
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");

        // change format for the response
        $failures = array_map(
            fn(string $sequenceNumber) => ['itemIdentifier' => $sequenceNumber],
            $failedRecords
        );

        return [
            'batchItemFailures' => $failures
        ];
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
透過使用 Python 的 Lambda 報告 Kinesis 批次項目失敗。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def handler(event, context):
    records = event.get("Records")
    curRecordSequenceNumber = ""
    
    for record in records:
        try:
            # Process your record
            curRecordSequenceNumber = record["kinesis"]["sequenceNumber"]
        except Exception as e:
            # Return failed record's sequence number
            return {"batchItemFailures":[{"itemIdentifier": curRecordSequenceNumber}]}

    return {"batchItemFailures":[]}
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 來報告 Kinesis 批次項目失敗。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
require 'aws-sdk'

def lambda_handler(event:, context:)
  batch_item_failures = []

  event['Records'].each do |record|
    begin
      puts "Processed Kinesis Event - EventID: #{record['eventID']}"
      record_data = get_record_data_async(record['kinesis'])
      puts "Record Data: #{record_data}"
      # TODO: Do interesting work based on the new data
    rescue StandardError => err
      puts "An error occurred #{err}"
      # Since we are working with streams, we can return the failed item immediately.
      # Lambda will immediately begin to retry processing from this failed item onwards.
      return { batchItemFailures: [{ itemIdentifier: record['kinesis']['sequenceNumber'] }] }
    end
  end

  puts "Successfully processed #{event['Records'].length} records."
  { batchItemFailures: batch_item_failures }
end

def get_record_data_async(payload)
  data = Base64.decode64(payload['data']).force_encoding('utf-8')
  # Placeholder for actual async work
  sleep(1)
  data
end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 來報告 Kinesis 批次項目失敗。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::{
    event::kinesis::KinesisEvent,
    kinesis::KinesisEventRecord,
    streams::{KinesisBatchItemFailure, KinesisEventResponse},
};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

async fn function_handler(event: LambdaEvent<KinesisEvent>) -> Result<KinesisEventResponse, Error> {
    let mut response = KinesisEventResponse {
        batch_item_failures: vec![],
    };

    if event.payload.records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(response);
    }

    for record in &event.payload.records {
        tracing::info!(
            "EventId: {}",
            record.event_id.as_deref().unwrap_or_default()
        );

        let record_processing_result = process_record(record);

        if record_processing_result.is_err() {
            response.batch_item_failures.push(KinesisBatchItemFailure {
                item_identifier: record.kinesis.sequence_number.clone(),
            });
            /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
            return Ok(response);
        }
    }

    tracing::info!(
        "Successfully processed {} records",
        event.payload.records.len()
    );

    Ok(response)
}

fn process_record(record: &KinesisEventRecord) -> Result<(), Error> {
    let record_data = std::str::from_utf8(record.kinesis.data.as_slice());

    if let Some(err) = record_data.err() {
        tracing::error!("Error: {}", err);
        return Err(Error::from(err));
    }

    let record_data = record_data.unwrap_or_default();

    // do something interesting with the data
    tracing::info!("Data: {}", record_data);

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

## 使用 Powertools 進行 AWS Lambda 批次處理器
<a name="services-kinesis-batchfailurereporting-powertools"></a>

Powertools for 的批次處理器公用程式 AWS Lambda 會自動處理部分批次回應邏輯，降低實作批次失敗報告的複雜性。以下是使用批次處理器的範例：

**Python**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)。
使用 AWS Lambda 批次處理器處理 Kinesis Data Streams 串流記錄。  

```
import json
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.batch import BatchProcessor, EventType, process_partial_response
from aws_lambda_powertools.utilities.data_classes import KinesisEvent
from aws_lambda_powertools.utilities.typing import LambdaContext

processor = BatchProcessor(event_type=EventType.KinesisDataStreams)
logger = Logger()

def record_handler(record):
    logger.info(record)
    # Your business logic here
    # Raise an exception to mark this record as failed
    
def lambda_handler(event, context: LambdaContext):
    return process_partial_response(
        event=event, 
        record_handler=record_handler, 
        processor=processor,
        context=context
    )
```

**TypeScript**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.aws.amazon.com/powertools/typescript/latest/features/batch/)。
使用 AWS Lambda 批次處理器處理 Kinesis Data Streams 串流記錄。  

```
import { BatchProcessor, EventType, processPartialResponse } from '@aws-lambda-powertools/batch';
import { Logger } from '@aws-lambda-powertools/logger';
import type { KinesisEvent, Context } from 'aws-lambda';

const processor = new BatchProcessor(EventType.KinesisDataStreams);
const logger = new Logger();

const recordHandler = async (record: any): Promise<void> => {
    logger.info('Processing record', { record });
    // Your business logic here
    // Throw an error to mark this record as failed
};

export const handler = async (event: KinesisEvent, context: Context) => {
    return processPartialResponse(event, recordHandler, processor, {
        context,
    });
};
```

**Java**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.powertools.aws.dev/lambda/java/latest/utilities/batch/)。
使用 AWS Lambda 批次處理器處理 Kinesis Data Streams 串流記錄。  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;
import software.amazon.lambda.powertools.batch.BatchMessageHandlerBuilder;
import software.amazon.lambda.powertools.batch.handler.BatchMessageHandler;

public class KinesisStreamBatchHandler implements RequestHandler<KinesisEvent, StreamsEventResponse> {

    private final BatchMessageHandler<KinesisEvent, StreamsEventResponse> handler;

    public KinesisStreamBatchHandler() {
        handler = new BatchMessageHandlerBuilder()
                .withKinesisBatchHandler()
                .buildWithRawMessageHandler(this::processMessage);
    }

    @Override
    public StreamsEventResponse handleRequest(KinesisEvent kinesisEvent, Context context) {
        return handler.processBatch(kinesisEvent, context);
    }

    private void processMessage(KinesisEvent.KinesisEventRecord kinesisEventRecord, Context context) {
        // Process the stream record
    }
}
```

**.NET**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.aws.amazon.com/powertools/dotnet/utilities/batch-processing/)。
使用 AWS Lambda 批次處理器處理 Kinesis Data Streams 串流記錄。  

```
using System;
using System.Threading;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.KinesisEvents;
using Amazon.Lambda.Serialization.SystemTextJson;
using AWS.Lambda.Powertools.BatchProcessing;

[assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))]

namespace HelloWorld;

public class OrderEvent
{
    public string? OrderId { get; set; }
    public string? CustomerId { get; set; }
    public decimal Amount { get; set; }
    public DateTime OrderDate { get; set; }
}

internal class TypedKinesisRecordHandler : ITypedRecordHandler<OrderEvent> 
{
    public async Task<RecordHandlerResult> HandleAsync(OrderEvent orderEvent, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(orderEvent.OrderId)) 
        {
            throw new ArgumentException("Order ID is required");
        }

        return await Task.FromResult(RecordHandlerResult.None); 
    }
}

public class Function
{
    [BatchProcessor(TypedRecordHandler = typeof(TypedKinesisRecordHandler))]
    public BatchItemFailuresResponse HandlerUsingTypedAttribute(KinesisEvent _)
    {
        return TypedKinesisStreamBatchProcessor.Result.BatchItemFailuresResponse; 
    }
}
```

# 在 Lambda 中保留 Kinesis Data Streams 事件來源的捨棄批次記錄
<a name="kinesis-on-failure-destination"></a>

Kinesis 事件來源映射的錯誤處理取決於錯誤是在調用函數之前還是在調用函數期間發生：
+ **調用前：**如果 Lambda 事件來源映射因為限流或其他問題而無法調用函數，它會重試，直到記錄過期或超過事件來源映射上設定的最長存留期 ([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))。
+ **在調用期間：**如果調用函數但傳回錯誤，Lambda 會重試，直到記錄過期、超過最長存留期 ([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))，或達到設定的重試配額 ([MaximumRetryAttempts](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRetryAttempts))。對於函數錯誤，您也可以設定 [BisectBatchOnFunctionError](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-response-BisectBatchOnFunctionError)，將失敗的批次分割為兩個較小的批次，隔離錯誤的記錄並避免逾時。分割批次不會消耗重試配額。

如果錯誤處理措施失敗，Lambda 會捨棄相應記錄，並繼續處理串流中的批次。使用預設設定時，這表示不良的記錄可能會封鎖受影響碎片上的處理長達一週。若要避免此情況，在設定函數的事件來源映射時，請使用合理的重試次數和符合您使用案例的記錄最大保留期。

## 設定失敗調用的目的地
<a name="kinesis-on-failure-destination-console"></a>

若要保留失敗的事件來源映射調用記錄，請將目標地新增到函數的事件來源映射中。傳送至該目的地的每筆記錄都是包含失敗調用之中繼資料的 JSON 文件。對於 Amazon S3 目的地，Lambda 還會將整個調用記錄與中繼資料一起傳送。您可以設定任何 Amazon SNS 主題、Amazon SQS 佇列、Amazon S3 儲存貯體或 Kafka 做為目的地。

透過 Amazon S3 目的地，您可以使用 [Amazon S3 事件通知](https://docs.aws.amazon.com/)功能，在物件上傳至您的目的地 S3 儲存貯體時接收通知。您也可以設定 S3 事件通知來調用另一個 Lambda 函數，以對失敗的批次執行自動處理。

執行角色必須具有目的地的許可：
+ **對於 SQS 目的地：**[sqs：SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)
+ **對於 SNS 目的地：**[sns：Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html)
+ **對於 S3 目的地：**[s3：PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 和 [s3：ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/ListObjectsV2.html)
+ **對於 Kafka 目的地：**[kafka-cluster：WriteData](https://docs.aws.amazon.com/msk/latest/developerguide/kafka-actions.html)

您可以將 Kafka 主題設定為 Kafka 事件來源映射的失敗時目的地。當 Lambda 在耗盡重試嘗試後或記錄超過最長存留期後無法處理記錄時，Lambda 會將失敗的記錄傳送至指定的 Kafka 主題，以供稍後處理。請參閱[使用 Kafka 主題做為失敗時的目的地](kafka-on-failure-destination.md)。

如果您已使用自己的 KMS 金鑰為 S3 目的地啟用加密，則函數的執行角色也必須具有呼叫 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) 的許可。如果 KMS 金鑰和 S3 儲存貯體目的地與 Lambda 函數和執行角色位於不同的帳戶中，請將 KMS 金鑰設定為信任執行角色以允許 kms:GenerateDataKey。

若要使用主控台設定失敗時的目的地，請依照下列步驟執行：

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇一個函數。

1. 在**函數概觀下**，選擇**新增目的地**。

1. 針對**來源**，請選擇**事件來源映射調用**。

1. 對於**事件來源映射**，請選擇針對此函數設定的事件來源。

1. 對於**條件**，選取**失敗時**。對於事件來源映射調用，這是唯一可接受的條件。

1. 對於**目標類型**，請選擇 Lambda 將調用記錄傳送至的目標類型。

1. 對於**目的地**，請選擇一個資源。

1. 選擇**儲存**。

您也可以使用 AWS Command Line Interface () 設定失敗時的目的地AWS CLI。例如，下列 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 命令會將具有 SQS 失敗時的目的地的事件來源映射新增至 `MyFunction`：

```
aws lambda create-event-source-mapping \
--function-name "MyFunction" \
--event-source-arn arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sqs:us-east-1:123456789012:dest-queue"}}'
```

下列 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 命令會更新事件來源映射，以在嘗試兩次重試後，或在記錄超過一小時時，將失敗的調用記錄傳送至 SNS 目的地。

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--maximum-retry-attempts 2 \
--maximum-record-age-in-seconds 3600 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sns:us-east-1:123456789012:dest-topic"}}'
```

系統會以非同步的方式套用更新的設定，在處理完成之前不會反映在輸出中。使用 [get-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) 命令檢視目前的狀態。

若要移除目的地，請提供空白字串作為 `destination-config` 參數的引數：

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": ""}}'
```

### Amazon S3 目的地的安全最佳實務
<a name="kinesis-s3-destination-security"></a>

刪除已設定為目的地的 S3 儲存貯體而不從函數的組態中移除目的地，可能會產生安全風險。如果其他使用者知道目的地儲存貯體的名稱，他們可以在其 AWS 帳戶中重新建立儲存貯體。失敗調用的記錄會被傳送到其儲存貯體，可能公開來自您函數的資料。

**警告**  
為了確保無法將來自函數的調用記錄傳送到另一個 中的 S3 儲存貯體 AWS 帳戶，請將條件新增至函數的執行角色，以限制您帳戶中儲存貯體的`s3:PutObject`許可。

下列範例顯示的 IAM 政策，將函數的 `s3:PutObject` 許可限制為帳戶中的儲存貯體。此政策也為 Lambda 提供了使用 S3 儲存貯體做為目的地所需的 `s3:ListBucket` 許可。

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "S3BucketResourceAccountWrite",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::*/*",
                "arn:aws:s3:::*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:ResourceAccount": "111122223333"
                }
            }
        }
    ]
}
```

若要使用 AWS 管理主控台 或 將許可政策新增至函數的執行角色 AWS CLI，請參閱下列程序中的指示：

------
#### [ Console ]

**若要將許可政策新增至函數的執行角色 (主控台)**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選取您要修改其執行角色的 Lambda 函數。

1. 在**組態**索引標籤中，選擇**許可**。

1. 在**執行角色**索引標籤中，選取函數的**角色名稱**，以開啟角色的 IAM 主控台頁面。

1. 透過下列步驟將許可政策新增至角色：

   1. 在**許可政策**窗格中，選擇**新增許可** ，然後選取**建立內嵌政策**。

   1. 在**政策編輯器**中，選取 **JSON**。

   1. 將您要新增的政策貼入編輯器 (取代現有的 JSON)，然後選擇**下一步**。

   1. 在**政策詳細資訊**下，輸入**政策名稱**。

   1. 選擇**建立政策**。

------
#### [ AWS CLI ]

**若要將許可政策新增至函數的執行角色 (CLI)**

1. 建立具有所需許可的 JSON 政策文件，並將其儲存在本機目錄中。

1. 使用 IAM `put-role-policy` CLI 命令，將許可新增至函數的執行角色。從您儲存 JSON 政策文件的目錄執行下列命令，並將角色名稱、政策名稱和政策文件取代為您自己的值。

   ```
   aws iam put-role-policy \
   --role-name my_lambda_role \
   --policy-name LambdaS3DestinationPolicy \
   --policy-document file://my_policy.json
   ```

------

### Amazon SNS 和 Amazon SQS 調用記錄範例
<a name="kinesis-on-failure-destination-example-sns-sqs"></a>

下列範例顯示 Lambda 針對失敗的 Kinesis 事件來源調用而傳送至 SQS 佇列或 SNS 主題。由於 Lambda 只會傳送這些目標類型的中繼資料，因此請使用 `streamArn`、`shardId`、`startSequenceNumber` 和 `endSequenceNumber` 欄位來取得完整的原始記錄。`KinesisBatchInfo` 屬性中顯示的所有欄位一律都會存在。

```
{
    "requestContext": {
        "requestId": "c9b8fa9f-5a7f-xmpl-af9c-0c604cde93a5",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KinesisBatchInfo": {
        "shardId": "shardId-000000000001",
        "startSequenceNumber": "49601189658422359378836298521827638475320189012309704722",
        "endSequenceNumber": "49601189658422359378836298522902373528957594348623495186",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:38:04.835Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:38:05.580Z",
        "batchSize": 500,
        "streamArn": "arn:aws:kinesis:us-east-2:123456789012:stream/mystream"
    }
}
```

您可以使用此資訊來從串流擷取受影響的記錄，以進行疑難排解。實際的記錄不包含在內，因此您必須處理此記錄，並在因過期而遺失之前從資料串流中擷取它們。

### Amazon S3 調用記錄範例
<a name="kinesis-on-failure-destination-example-sns-sqs-s3"></a>

下列範例顯示 Lambda 針對失敗的 Kinesis 事件來源調用而傳送至 Amazon S3 儲存貯體的內容。除了上一個 SQS 和 SNS 目的地範例中的所有欄位之外，此 `payload` 欄位還包含原始調用記錄做為逸出 JSON 字串。

```
{
    "requestContext": {
        "requestId": "c9b8fa9f-5a7f-xmpl-af9c-0c604cde93a5",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KinesisBatchInfo": {
        "shardId": "shardId-000000000001",
        "startSequenceNumber": "49601189658422359378836298521827638475320189012309704722",
        "endSequenceNumber": "49601189658422359378836298522902373528957594348623495186",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:38:04.835Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:38:05.580Z",
        "batchSize": 500,
        "streamArn": "arn:aws:kinesis:us-east-2:123456789012:stream/mystream"
    },
    "payload": "<Whole Event>" // Only available in S3
}
```

包含調用記錄的 S3 物件使用以下命名慣例：

```
aws/lambda/<ESM-UUID>/<shardID>/YYYY/MM/DD/YYYY-MM-DDTHH.MM.SS-<Random UUID>
```

# 在 Lambda 中實作有狀態的 Kinesis 資料串流處理
<a name="services-kinesis-windows"></a>

Lambda 函數可執行持續串流處理應用程式。串流表示持續在應用程式中流動的無限制資料。若要分析此持續更新輸入中的資訊，您可以使用定義的時段來限制包含的記錄。

輪轉時段是定期開啟和關閉的不同時段。依預設，Lambda 調用是無狀態的，您無法在沒有外部資料庫的情況下，將其用於處理多個持續調用的資料。然而，使用輪轉時段，您可以在不同的調用間維護狀態。此狀態包含之前為目前時段處理之訊息的彙總結果。狀態可以是每個分區最多 1 MB。如果超過該大小，則 Lambda 會提前終止時段。

串流中的每個記錄都屬於一個特定時段。Lambda 至少會處理一次每筆記錄，但不保證每筆記錄只會處理一次。在極少數情況下，例如錯誤處理，某些記錄可能會處理多次。第一次時一律會依序處理記錄。如果多次處理記錄，則可能不會按順序處理。

## 彙總與處理
<a name="streams-tumbling-processing"></a>

調用您的使用者管理函數進行彙總，以及處理該彙總的最終結果。Lambda 會彙總時段中接收的所有記錄。您可以在多個批次中接收這些記錄，各自作為單獨的調用。每次調用會收到一個狀態。因此，當使用輪轉時段時，您的 Lambda 函數回應必須包含 `state` 屬性。如果回應不包含 `state` 屬性，Lambda 會將此視為失敗的調用。為了滿足此條件，您的函數可以返回一個 `TimeWindowEventResponse` 物件，它具有下列 JSON 形狀：

**Example `TimeWindowEventResponse` 值**  

```
{
    "state": {
        "1": 282,
        "2": 715
    },
    "batchItemFailures": []
}
```

**注意**  
對於 Java 函數，我們建議使用 `Map<String, String>` 來表示狀態。

在時段結束時，標記 `isFinalInvokeForWindow` 會設定為 `true` 以指示這是最終狀態，並且可隨時進行處理。處理完成後，時段結束並完成最終調用，然後丟棄該狀態。

在時段結束時，Lambda 會針對彙總結果上的動作使用最終處理。您的最終處理將同步調用。成功調用後，您的函數檢查點序號和串流處理將會繼續。如果調用失敗，則您的 Lambda 函數會暫停進一步處理，直至成功調用。

**Example KinesisTimeWindowEvent**  

```
{
    "Records": [
        {
            "kinesis": {
                "kinesisSchemaVersion": "1.0",
                "partitionKey": "1",
                "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
                "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
                "approximateArrivalTimestamp": 1607497475.000
            },
            "eventSource": "aws:kinesis",
            "eventVersion": "1.0",
            "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
            "eventName": "aws:kinesis:record",
            "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-kinesis-role",
            "awsRegion": "us-east-1",
            "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/lambda-stream"
        }
    ],
    "window": {
        "start": "2020-12-09T07:04:00Z",
        "end": "2020-12-09T07:06:00Z"
    },
    "state": {
        "1": 282,
        "2": 715
    },
    "shardId": "shardId-000000000006",
    "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/lambda-stream",
    "isFinalInvokeForWindow": false,
    "isWindowTerminatedEarly": false
}
```

## Configuration
<a name="streams-tumbling-config"></a>

您可以在建立或更新事件來源對映時設定輪轉時段。若要設定輪轉時段，請以秒為單位指定時段 ([TumblingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-TumblingWindowInSeconds))。下列 example AWS Command Line Interface (AWS CLI) 命令會建立輪轉時段為 120 秒的串流事件來源映射。針對彙總與處理定義的 Lambda 函數命名為 `tumbling-window-example-function`。

```
aws lambda create-event-source-mapping \
--event-source-arn arn:aws:kinesis:us-east-1:123456789012:stream/lambda-stream \
--function-name tumbling-window-example-function \
--starting-position TRIM_HORIZON \
--tumbling-window-in-seconds 120
```

Lambda 根據記錄插入串流的時間，確定輪轉時段邊界。所有記錄都有 Lambda 在邊界確定中使用的近似時間戳記。

輪轉時段彙總不支援重新分區。分區結束後，Lambda 會考慮關閉目前時段，並且任何子分區會以全新的狀態開始自己的時段。當沒有新記錄新增至目前的時段時，Lambda 會等待最多 2 分鐘，然後假設該時段已結束。這有助於確保函數讀取目前時段中的所有記錄，即使記錄是間歇性新增的。

輪轉時段完全支援現有的重試政策 `maxRetryAttempts` 和 `maxRecordAge`。

**Example Handler.py - 彙總與處理**  
下列 Python 函數示範了如何彙總，然後處理您的最終狀態：  

```
def lambda_handler(event, context):
    print('Incoming event: ', event)
    print('Incoming state: ', event['state'])

#Check if this is the end of the window to either aggregate or process.
    if event['isFinalInvokeForWindow']:
        # logic to handle final state of the window
        print('Destination invoke')
    else:
        print('Aggregate invoke')

#Check for early terminations
    if event['isWindowTerminatedEarly']:
        print('Window terminated early')

    #Aggregation logic
    state = event['state']
    for record in event['Records']:
        state[record['kinesis']['partitionKey']] = state.get(record['kinesis']['partitionKey'], 0) + 1

    print('Returning state: ', state)
    return {'state': state}
```

# 適用於 Amazon Kinesis Data Streams 事件來源映射的 Lambda 參數
<a name="services-kinesis-parameters"></a>

所有 Lambda 事件來源映射都會共用相同的 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 和 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 操作。但是，只有一些參數適用於 Kinesis。


| 參數 | 必要 | 預設 | 備註 | 
| --- | --- | --- | --- | 
|  [BatchSize](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-BatchSize)  |  否  |  100  |  上限：10,000  | 
|  [BisectBatchOnFunctionError](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-BisectBatchOnFunctionError)  |  N  |  false  |  無 | 
|  [DestinationConfig](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-DestinationConfig)  |  N  | N/A |  捨棄記錄的 Amazon SQS 佇列或 Amazon SNS 主題目標。如需更多詳細資訊，請參閱 [設定失敗調用的目的地](kinesis-on-failure-destination.md#kinesis-on-failure-destination-console)。  | 
|  [已啟用](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-Enabled)   |  N  |  true  |  無 | 
|  [EventSourceArn](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-EventSourceArn)  |  是  | N/A |  資料串流或串流消費者的 ARN  | 
|  [FunctionName](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionName)  |  是  | N/A |  無 | 
|  [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionResponseTypes)  |  N  |  N/A |  若要讓函數報告批次中的特定失敗，請將值 `ReportBatchItemFailures` 包含在 `FunctionResponseTypes` 中。如需更多詳細資訊，請參閱 [使用 Kinesis Data Streams 和 Lambda 設定部分批次回應](services-kinesis-batchfailurereporting.md)。  | 
|  [MaximumBatchingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumBatchingWindowInSeconds)  |  N  |  0  |  無 | 
|  [MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds)  |  N  |  -1  |  -1 表示無限：Lambda 不會捨棄記錄 ([Kinesis Data Streams 資料保留設定](https://docs.aws.amazon.com/streams/latest/dev/kinesis-extended-retention.html)仍然適用) 下限：-1 上限：604,800  | 
|  [MaximumRetryAttempts](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRetryAttempts)  |  N  |  -1  |  -1 代表無限：系統會重試失敗的記錄，直到記錄過期為止 下限：-1 上限：10,000  | 
|  [ParallelizationFactor](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-ParallelizationFactor)  |  N  |  1  |  上限：10  | 
|  [StartingPosition](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPosition)  |  是  |  N/A |  AT\$1TIMESTAMP、TRIM\$1HORIZON 或 LATEST  | 
|  [StartingPositionTimestamp](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPositionTimestamp)  |  N  |  N/A |  僅當 StartingPosition 設定為 AT\$1TIMESTAMP 時才有效。這是開始讀取的時間 (以 Unix 時間秒為單位)  | 
|  [TumblingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-TumblingWindowInSeconds)  |  N  |  N/A |  下限：0 上限：900  | 

# 搭配 Kinesis 事件來源使用事件篩選
<a name="with-kinesis-filtering"></a>

您可以使用事件篩選來控制 Lambda 將哪些記錄從串流或佇列中傳送至函數。如需事件篩選運作方式的一般資訊，請參閱[控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)。

本節重點介紹 Kinesis 事件來源的事件篩選。

**注意**  
Kinesis 事件來源映射僅支援依據 `data` 鍵進行篩選。

**Topics**
+ [

## Kinesis 事件篩選基本概念
](#filtering-kinesis)
+ [

## 篩選 Kinesis 彙總記錄
](#filtering-kinesis-efo)

## Kinesis 事件篩選基本概念
<a name="filtering-kinesis"></a>

假設生產者將 JSON 格式的資料放入您的 Kinesis 資料串流中。範例記錄如下所示，JSON 資料在 `data` 欄位中會轉換為 Base64 編碼字串。

```
{
    "kinesis": {
        "kinesisSchemaVersion": "1.0",
        "partitionKey": "1",
        "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
        "data": "eyJSZWNvcmROdW1iZXIiOiAiMDAwMSIsICJUaW1lU3RhbXAiOiAieXl5eS1tbS1kZFRoaDptbTpzcyIsICJSZXF1ZXN0Q29kZSI6ICJBQUFBIn0=",
        "approximateArrivalTimestamp": 1545084650.987
        },
    "eventSource": "aws:kinesis",
    "eventVersion": "1.0",
    "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
    "eventName": "aws:kinesis:record",
    "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role",
    "awsRegion": "us-east-2",
    "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream"
}
```

只要生產者放入串流中的資料是有效的 JSON，您就可以使用事件篩選透過 `data` 索引鍵來篩選記錄。假設生產者以下列 JSON 格式將記錄放入 Kinesis 串流中。

```
{
    "record": 12345,
    "order": {
        "type": "buy",
        "stock": "ANYCO",
        "quantity": 1000
        }
}
```

若僅篩選訂單類型為「購買」的記錄，`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"data\" : { \"order\" : { \"type\" : [ \"buy\" ] } } }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "data": {
        "order": {
            "type": [ "buy" ]
            }
      }
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "data" : { "order" : { "type" : [ "buy" ] } } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:kinesis:us-east-2:123456789012:stream/my-stream \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"order\" : { \"type\" : [ \"buy\" ] } } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"order\" : { \"type\" : [ \"buy\" ] } } }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "data" : { "order" : { "type" : [ "buy" ] } } }'
```

------

若要正確篩選來自 Kinesis 來源的事件，資料欄位和資料欄位的篩選條件標準都必須是有效的 JSON 格式。如果其中一個欄位不是有效的 JSON 格式，則 Lambda 會捨棄訊息或擲回例外狀況。下表摘要說明特定行為：


| 傳入資料格式 | 資料屬性的篩選條件模式格式 | 產生的動作 | 
| --- | --- | --- | 
|  有效的 JSON  |  有效的 JSON  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 
|  有效的 JSON  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  非 JSON  |  Lambda 會在事件來源映射建立或更新時擲回例外狀況。資料屬性的篩選條件模式必須是有效的 JSON 格式。  | 
|  非 JSON  |  有效的 JSON  |  Lambda 捨棄記錄。  | 
|  非 JSON  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  非 JSON  |  非 JSON  |  Lambda 會在事件來源映射建立或更新時擲回例外狀況。資料屬性的篩選條件模式必須是有效的 JSON 格式。  | 

## 篩選 Kinesis 彙總記錄
<a name="filtering-kinesis-efo"></a>

使用 Kinesis，可以將多個記錄彙總到單一 Kinesis 資料串流記錄中，以提高資料輸送量。Lambda 只會在您使用 Kinesis [增強型展開傳送](https://docs.aws.amazon.com/streams/latest/dev/enhanced-consumers.html)時，將篩選條件標準套用至彙總記錄。不支援使用標準 Kinesis 篩選彙總記錄。使用增強型展開傳送時，您可以設定 Kinesis 專用輸送量取用程式，以充當 Lambda 函數的觸發條件。Lambda 接著會篩選彙總記錄，並僅傳遞符合篩選條件標準的記錄。

若要進一步了解 Kinesis 記錄彙總，請參閱「Kinesis Producer Library (KPL) 主要概念」頁面上的[彙總](https://docs.aws.amazon.com/streams/latest/dev/kinesis-kpl-concepts.html#kinesis-kpl-concepts-aggretation)部分。若要進一步了解如何搭配使用 Lambda 與 Kinesis 增強型展開傳送，請參閱 AWS 運算部落格上的[使用 Amazon Kinesis Data Streams 增強型展開傳送和 AWS Lambda 來提高即時串流處理效能](https://aws.amazon.com/blogs/compute/increasing-real-time-stream-processing-performance-with-amazon-kinesis-data-streams-enhanced-fan-out-and-aws-lambda/)。

# 教學課程：搭配 Kinesis Data Streams 使用 Lambda
<a name="with-kinesis-example"></a>

在本教學課程中，您會建立 Lambda 函數，以取用 Amazon Kinesis 資料串流中的事件。

1. 自訂應用程式將記錄寫入串流。

1. AWS Lambda 會輪詢串流，並在偵測到串流中的新記錄時，叫用您的 Lambda 函數。

1. AWS Lambda 會透過擔任您在建立 Lambda 函數時指定的執行角色來執行 Lambda 函數。

## 先決條件
<a name="with-kinesis-prepare"></a>

### 安裝 AWS Command Line Interface
<a name="install_aws_cli"></a>

如果您尚未安裝 AWS Command Line Interface，請依照[安裝或更新最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)中的步驟進行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中，使用您偏好的 Shell 和套件管理工具。

**注意**  
在 Windows 中，作業系統的內建終端不支援您常與 Lambda 搭配使用的某些 Bash CLI 命令 (例如 `zip`)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本，請[安裝適用於 Linux 的 Windows 子系統](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。

## 建立執行角色
<a name="with-kinesis-example-create-iam-role"></a>

建立 [執行角色](lambda-intro-execution-role.md)，授予函數存取 AWS 資源的許可。

**若要建立執行角色**

1. 在 IAM 主控台中開啟[角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇建**立角色**。

1. 建立具備下列屬性的角色。
   + **信任實體** – **AWS Lambda**。
   + **Permissions (許可)** - **AWSLambdaKinesisExecutionRole**。
   + **角色名稱** – **lambda-kinesis-role**。

**AWSLambdaKinesisExecutionRole** 政策具備函數自 Kinesis 讀取項目以及寫入日誌到 CloudWatch Logs 時所需的許可。

## 建立函數
<a name="with-kinesis-example-create-function"></a>

建立可處理 Kinesis 訊息的 Lambda 函數。函數程式碼會將 Kinesis 記錄的事件 ID 和事件資料記錄到 CloudWatch Logs 中。

本教學課程使用 Node.js 24 執行時間，但我們也提供其他執行時間語言的範例程式碼。您可以在下列方塊中選取索引標籤，查看您感興趣的執行期程式碼。此步驟要使用的 JavaScript 程式碼，位於 **JavaScript** 索引標籤中顯示的第一個範例。

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 來使用 Kinesis 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
﻿using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.KinesisEvents;
using AWS.Lambda.Powertools.Logging;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace KinesisIntegrationSampleCode;

public class Function
{
    // Powertools Logger requires an environment variables against your function
    // POWERTOOLS_SERVICE_NAME
    [Logging(LogEvent = true)]
    public async Task FunctionHandler(KinesisEvent evnt, ILambdaContext context)
    {
        if (evnt.Records.Count == 0)
        {
            Logger.LogInformation("Empty Kinesis Event received");
            return;
        }

        foreach (var record in evnt.Records)
        {
            try
            {
                Logger.LogInformation($"Processed Event with EventId: {record.EventId}");
                string data = await GetRecordDataAsync(record.Kinesis, context);
                Logger.LogInformation($"Data: {data}");
                // TODO: Do interesting work based on the new data
            }
            catch (Exception ex)
            {
                Logger.LogError($"An error occurred {ex.Message}");
                throw;
            }
        }
        Logger.LogInformation($"Successfully processed {evnt.Records.Count} records.");
    }

    private async Task<string> GetRecordDataAsync(KinesisEvent.Record record, ILambdaContext context)
    {
        byte[] bytes = record.Data.ToArray();
        string data = Encoding.UTF8.GetString(bytes);
        await Task.CompletedTask; //Placeholder for actual async work
        return data;
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 Go 搭配 Lambda 來使用 Kinesis 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"log"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context, kinesisEvent events.KinesisEvent) error {
	if len(kinesisEvent.Records) == 0 {
		log.Printf("empty Kinesis event received")
		return nil
	}

	for _, record := range kinesisEvent.Records {
		log.Printf("processed Kinesis event with EventId: %v", record.EventID)
		recordDataBytes := record.Kinesis.Data
		recordDataText := string(recordDataBytes)
		log.Printf("record data: %v", recordDataText)
		// TODO: Do interesting work based on the new data
	}
	log.Printf("successfully processed %v records", len(kinesisEvent.Records))
	return nil
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 Java 搭配 Lambda 來使用 Kinesis 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;

public class Handler implements RequestHandler<KinesisEvent, Void> {
    @Override
    public Void handleRequest(final KinesisEvent event, final Context context) {
        LambdaLogger logger = context.getLogger();
        if (event.getRecords().isEmpty()) {
            logger.log("Empty Kinesis Event received");
            return null;
        }
        for (KinesisEvent.KinesisEventRecord record : event.getRecords()) {
            try {
                logger.log("Processed Event with EventId: "+record.getEventID());
                String data = new String(record.getKinesis().getData().array());
                logger.log("Data:"+ data);
                // TODO: Do interesting work based on the new data
            }
            catch (Exception ex) {
                logger.log("An error occurred:"+ex.getMessage());
                throw ex;
            }
        }
        logger.log("Successfully processed:"+event.getRecords().size()+" records");
        return null;
    }

}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/blob/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 來使用 Kinesis 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const record of event.Records) {
    try {
      console.log(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      console.log(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      console.error(`An error occurred ${err}`);
      throw err;
    }
  }
  console.log(`Successfully processed ${event.Records.length} records.`);
};

async function getRecordDataAsync(payload) {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```
使用 TypeScript 搭配 Lambda 來使用 Kinesis 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import {
  KinesisStreamEvent,
  Context,
  KinesisStreamHandler,
  KinesisStreamRecordPayload,
} from "aws-lambda";
import { Buffer } from "buffer";
import { Logger } from "@aws-lambda-powertools/logger";

const logger = new Logger({
  logLevel: "INFO",
  serviceName: "kinesis-stream-handler-sample",
});

export const functionHandler: KinesisStreamHandler = async (
  event: KinesisStreamEvent,
  context: Context
): Promise<void> => {
  for (const record of event.Records) {
    try {
      logger.info(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      logger.info(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      logger.error(`An error occurred ${err}`);
      throw err;
    }
    logger.info(`Successfully processed ${event.Records.length} records.`);
  }
};

async function getRecordDataAsync(
  payload: KinesisStreamRecordPayload
): Promise<string> {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 來使用 Kinesis 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Kinesis\KinesisEvent;
use Bref\Event\Kinesis\KinesisHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler extends KinesisHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handleKinesis(KinesisEvent $event, Context $context): void
    {
        $this->logger->info("Processing records");
        $records = $event->getRecords();
        foreach ($records as $record) {
            $data = $record->getData();
            $this->logger->info(json_encode($data));
            // TODO: Do interesting work based on the new data

            // Any exception thrown will be logged and the invocation will be marked as failed
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 Python 搭配 Lambda 來使用 Kinesis 事件。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
import base64
def lambda_handler(event, context):

    for record in event['Records']:
        try:
            print(f"Processed Kinesis Event - EventID: {record['eventID']}")
            record_data = base64.b64decode(record['kinesis']['data']).decode('utf-8')
            print(f"Record Data: {record_data}")
            # TODO: Do interesting work based on the new data
        except Exception as e:
            print(f"An error occurred {e}")
            raise e
    print(f"Successfully processed {len(event['Records'])} records.")
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 來使用 Kinesis 事件。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
require 'aws-sdk'

def lambda_handler(event:, context:)
  event['Records'].each do |record|
    begin
      puts "Processed Kinesis Event - EventID: #{record['eventID']}"
      record_data = get_record_data_async(record['kinesis'])
      puts "Record Data: #{record_data}"
      # TODO: Do interesting work based on the new data
    rescue => err
      $stderr.puts "An error occurred #{err}"
      raise err
    end
  end
  puts "Successfully processed #{event['Records'].length} records."
end

def get_record_data_async(payload)
  data = Base64.decode64(payload['data']).force_encoding('UTF-8')
  # Placeholder for actual async work
  # You can use Ruby's asynchronous programming tools like async/await or fibers here.
  return data
end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 來使用 Kinesis 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::event::kinesis::KinesisEvent;
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

async fn function_handler(event: LambdaEvent<KinesisEvent>) -> Result<(), Error> {
    if event.payload.records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(());
    }

    event.payload.records.iter().for_each(|record| {
        tracing::info!("EventId: {}",record.event_id.as_deref().unwrap_or_default());

        let record_data = std::str::from_utf8(&record.kinesis.data);

        match record_data {
            Ok(data) => {
                // log the record data
                tracing::info!("Data: {}", data);
            }
            Err(e) => {
                tracing::error!("Error: {}", e);
            }
        }
    });

    tracing::info!(
        "Successfully processed {} records",
        event.payload.records.len()
    );

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

**建立函數**

1. 建立專案的目錄，然後切換至該目錄。

   ```
   mkdir kinesis-tutorial
   cd kinesis-tutorial
   ```

1. 將範例 JavaScript 程式碼複製到名為 `index.js` 的新檔案。

1. 建立部署套件。

   ```
   zip function.zip index.js
   ```

1. 使用 `create-function` 命令建立一個 Lambda 函數。

   ```
   aws lambda create-function --function-name ProcessKinesisRecords \
   --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
   --role arn:aws:iam::111122223333:role/lambda-kinesis-role
   ```

## 測試 Lambda 函數
<a name="walkthrough-kinesis-events-adminuser-create-test-function-upload-zip-test-manual-invoke"></a>

使用 `invoke` AWS Lambda CLI 命令和範例 Kinesis 事件手動叫用 Lambda 函數。

**測試 Lambda 函數**

1. 將以下 JSON 複製到一個檔案中並儲存為 `input.txt`。

   ```
   {
       "Records": [
           {
               "kinesis": {
                   "kinesisSchemaVersion": "1.0",
                   "partitionKey": "1",
                   "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
                   "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
                   "approximateArrivalTimestamp": 1545084650.987
               },
               "eventSource": "aws:kinesis",
               "eventVersion": "1.0",
               "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
               "eventName": "aws:kinesis:record",
               "invokeIdentityArn": "arn:aws:iam::111122223333:role/lambda-kinesis-role",
               "awsRegion": "us-east-2",
               "eventSourceARN": "arn:aws:kinesis:us-east-2:111122223333:stream/lambda-stream"
           }
       ]
   }
   ```

1. 使用 `invoke` 命令來傳送事件到函數。

   ```
   aws lambda invoke --function-name ProcessKinesisRecords \
   --cli-binary-format raw-in-base64-out \
   --payload file://input.txt outputfile.txt
   ```

   如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

   回應已儲存至 `out.txt`。

## 建立 Kinesis 串流
<a name="with-kinesis-example-configure-event-source-create"></a>

使用 `create-stream ` 命令來建立串流。

```
aws kinesis create-stream --stream-name lambda-stream --shard-count 1
```

執行下列 `describe-stream` 命令以取得串流 ARN。

```
aws kinesis describe-stream --stream-name lambda-stream
```

您應該會看到下列輸出：

```
{
    "StreamDescription": {
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "StartingHashKey": "0",
                    "EndingHashKey": "340282366920746074317682119384634633455"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49591073947768692513481539594623130411957558361251844610"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:us-east-1:111122223333:stream/lambda-stream",
        "StreamName": "lambda-stream",
        "StreamStatus": "ACTIVE",
        "RetentionPeriodHours": 24,
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "EncryptionType": "NONE",
        "KeyId": null,
        "StreamCreationTimestamp": 1544828156.0
    }
}
```

在下一個步驟中，您會使用串流 ARN 與您的 Lambda 函數的串流建立關聯。

## 在 中新增事件來源 AWS Lambda
<a name="with-kinesis-example-configure-event-source-add-event-source"></a>

執行下列 AWS CLI `add-event-source` 命令。

```
aws lambda create-event-source-mapping --function-name ProcessKinesisRecords \
--event-source  arn:aws:kinesis:us-east-1:111122223333:stream/lambda-stream \
--batch-size 100 --starting-position LATEST
```

記下映射 ID 以供後續使用。您可以執行 `list-event-source-mappings` 命令來取得事件來源映射的清單。

```
aws lambda list-event-source-mappings --function-name ProcessKinesisRecords \
--event-source arn:aws:kinesis:us-east-1:111122223333:stream/lambda-stream
```

在回應中，您可以確認狀態值為 `enabled`。您可以停用事件來源映射來暫時暫停輪詢，而不會遺失任何記錄。

## 測試設定
<a name="with-kinesis-example-configure-event-source-test-end-to-end"></a>

若要測試事件來源映射，請新增事件記錄到您的 Kinesis 串流。`--data` 值是一個字串，CLI 會先將該字串編碼為 base64，再將它傳送到 Kinesis。您可以執行相同命令一次以上，以新增多筆記錄到串流中。

```
aws kinesis put-record --stream-name lambda-stream --partition-key 1 \
--data "Hello, this is a test."
```

Lambda 使用執行角色自串流讀取記錄。接著，它調用您的 Lambda 函數，以記錄批次來傳遞。函數會解碼來自每個記錄的資料並加以記錄，將輸出傳送至 CloudWatch Logs。在 [CloudWatch 主控台](https://console.aws.amazon.com/cloudwatch)中檢視日誌。

## 清除您的資源
<a name="cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇 **刪除** 。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇 **刪除** 。

**刪除 Kinesis 串流**

1. 登入 AWS 管理主控台 並開啟位於 https：//[https://console.aws.amazon.com/kinesis](https://console.aws.amazon.com/kinesis) 的 Kinesis 主控台。

1. 選取您建立的串流。

1. 選擇 **動作**、**刪除**。

1. 在文字輸入欄位中輸入 **delete**。

1. 選擇 **刪除** 。

# 搭配 Kubernetes 使用 Lambda
<a name="with-kubernetes"></a>

您可以使用 [Kubernetes 專用 AWS 控制器 (ACK)](https://aws-controllers-k8s.github.io/community/docs/community/overview/) 或 [Crossplane](https://docs.crossplane.io/latest/packages/providers/)，透過 Kubernetes API 來部署和管理 Lambda 函數。

## Kubernetes 專用 AWS 控制器 (ACK)
<a name="kubernetes-ack"></a>

您可以使用 ACK，從 Kubernetes API 部署和管理 AWS 資源。透過 ACK，AWS 提供諸如以下 AWS 服務專用的開放原始碼自訂控制器：Lambda、Amazon Elastic Container Registry (Amazon ECR)、Amazon Simple Storage Service (Amazon S3) 和 Amazon SageMaker AI。每個支援的 AWS 服務都有專屬自訂控制器。在您的 Kubernetes 叢集中，為每個要使用的 AWS 服務安裝控制器。接著建立[自訂資源定義 (CRD)](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/)以定義 AWS 資源。

建議您使用 [Helm 3.8 或更新版本](https://helm.sh/docs/intro/install/)，安裝 ACK 控制器。每個 ACK 控制器都有專屬 Helm Chart，這會安裝控制器、CRD 和 Kubernetes RBAC 規則。如需詳細資訊，請參閱 ACK 文件中的 [Install an ACK Controller](https://aws-controllers-k8s.github.io/community/docs/user-docs/install/)。

建立 ACK 自訂資源之後，您可以像使用任何其他內建 Kubernetes 物件一樣加以使用。例如，您可以使用偏好的 Kubernetes 工具鏈 (包括 [kubectl](https://kubernetes.io/docs/reference/kubectl/))，部署和管理 Lambda 函數。

以下是一些透過 ACK 佈建 Lambda 函數的範例使用案例：
+ 您的組織使用[角色型存取控制 (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) 和[服務帳戶的 IAM 角色](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)，建立許可界限。您可以使用 ACK，為 Lambda 重複使用此安全模型，不須建立新的使用者和政策。
+ 您的組織有 DevOps 程序，可使用 Kubernetes 清單檔案，將資源部署到 Amazon Elastic Kubernetes Service (Amazon EKS) 叢集中。您可以透過 ACK，使用清單檔案佈建 Lambda 函數，不須建立另外的基礎設施即程式碼範本。

如需使用 ACK 的詳細資訊，請參閱 [ACK 文件中的 Lambda 教學課程](https://aws-controllers-k8s.github.io/community/docs/tutorials/lambda-oci-example/)。

## Crossplane
<a name="kubernetes-crossplane"></a>

[Crossplane](https://docs.crossplane.io/latest/packages/providers/) 是開放原始碼雲端原生運算基金會 (CNCF) 專案，使用 Kubernetes 來管理雲端基礎設施資源。開發人員可以透過 Crossplane 請求基礎設施，不須了解其複雜性。平台團隊保留基礎設施佈建和管理方式的控制權。

您可以使用 Crossplane，透過偏好的 Kubernetes 工具鏈 (例如 [kubectl](https://kubernetes.io/docs/reference/kubectl/)) 以及任何可將清單檔案部署到 Kubernetes 的 CI/CD 管道，部署和管理 Lambda 函數。以下是一些透過 Crossplane 佈建 Lambda 函數的範例使用案例：
+ 您的組織希望確保 Lambda 函數具有正確[標籤](configuration-tags.md)來強制遵循法規。平台團隊可以使用 [Crossplane 组合](https://docs.crossplane.io/latest/get-started/get-started-with-composition/)，透過 API 抽象來定義此政策。開發人員隨後可以使用這些抽象來部署具標籤的 Lambda 函數。
+ 您的專案搭配 Kubernetes 使用 GITOps。在此模型中，Kubernetes 會持續協調 git 儲存庫 (所需狀態) 與叢集內執行的資源 (目前狀態)。如果有差異，GITOps 程序會自動變更叢集。您可以搭配 Kubernetes 使用 GITOps，利用諸如 [CRD](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/) 和[控制器](https://kubernetes.io/docs/concepts/architecture/controller/)的熟悉 Kubernetes 工具和概念，透過 Crossplane 來部署和管理 Lambda 函數。

若要進一步了解如何搭配 Lambda 使用 Crossplane，請參閱下列內容：
+ [AWS Blueprints for Crossplane](https://github.com/awslabs/crossplane-on-eks/blob/main/examples/upbound-aws-provider/README.md#deploy-the-examples)：此儲存庫包括如何使用 Crossplane 部署 AWS 資源 (包括 Lambda 函數) 的範例。
**注意**  
目前正在積極開發 AWS Blueprints for Crossplane，因此不得用於生產環境。
+ [使用 Amazon EKS 和 Crossplane 部署 Lambda](https://www.youtube.com/watch?v=m-9KLq29K4k)：此影片展示透過 Crossplane 部署 AWS 無伺服器架構的進階範例，並從開發人員和平台的角度探索設計。

# 搭配使用 Lambda 與 Amazon MQ
<a name="with-mq"></a>

**注意**  
如要將資料傳送到 Lambda 函數以外的目標，或在傳送資料之前讓資料更豐富，請參閱 [Amazon EventBridge Pipes](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes.html)。

Amazon MQ 是一項受管訊息代理程式服務，適用於 [Apache ActiveMQ](https://activemq.apache.org/) 和 [RabbitMQ](https://www.rabbitmq.com)。*訊息代理程式*透過主題或佇列事件目的地，允許軟體應用程式和元件使用各種程式設計語言、作業系統和正式簡訊協定來進行通訊。

Amazon MQ 還可以透過安裝 ActiveMQ 或 RabbitMQ 代理程式，並提供不同的網路拓撲和其他基礎架構需求，來代表您管理 Amazon Elastic Compute Cloud (Amazon EC2) 執行個體。

您可以使用 Lambda 函數來處理您的 Amazon MQ 訊息代理程式中的記錄。Lambda 透過[事件來源映射](invocation-eventsourcemapping.md)叫用函數，這是從您的代理程式讀取訊息並[同步](invocation-sync.md)叫用函數的 Lambda 資源。

**警告**  
Lambda 事件來源映射至少會處理每個事件一次，而且可能會重複處理記錄。為避免與重複事件相關的潛在問題，強烈建議您讓函數程式碼具有等冪性。若要進一步了解，請參閱 AWS 知識中心中的[如何使 Lambda 函數具有等冪性](https://repost.aws/knowledge-center/lambda-function-idempotent)。

Amazon MQ 事件來源映射具有下列組態限制：
+ 並行：使用 Amazon MQ 事件來源映射的 Lambda 函數具有預設[並行](lambda-concurrency.md)上限設定。若使用 ActiveMQ，Lambda 服務會將並行執行環境的數量上限設為每個 Amazon MQ 事件來源映射 5 個。若使用 RabbitMQ，並行執行環境的數量上限為每個 Amazon MQ 事件來源映射 1 個。即使您變更函數的保留或佈建並行設定，Lambda 服務還是無法提供更多可用的執行環境。若要請求增加單一 Amazon MQ 事件來源映射的預設並行上限， 支援 請聯絡事件來源映射 UUID 以及 區域。由於增加會套用在特定事件來源映射層級，而不是帳戶或區域層級，因此您需要為每個事件來源映射手動請求擴展增加。
+ 跨帳戶 - Lambda 不支援跨帳戶處理。您無法用 Lambda 處理來自不同 AWS 帳戶中 Amazon MQ 訊息代理程式的記錄。
+ 身分驗證支援 - 對於 ActiveMQ，僅支援 ActiveMQ [SimpleAuthenticationPlugin](https://activemq.apache.org/security#simple-authentication-plugin)。對於 RabbitMQ，僅支援 [PLAIN](https://www.rabbitmq.com/access-control.html#mechanisms) 身分驗證機制。使用者必須使用 AWS Secrets Manager 來管理其登入資料。如需 ActiveMQ 身分驗證的詳細資訊，請參閱 *Amazon MQ 開發人員指南*中的[將 ActiveMQ 代理程式與 LDAP 整合](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/security-authentication-authorization.html)。
+ 連線配額 - 代理程式每個線路層級協定允許的連線數量上限。此配額以代理程式執行個體類型為基礎。如需詳細資訊，請參閱 *Amazon MQ 開發人員指南*中的 **Amazon MQ 中的配額**的[代理程式](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-limits.html#broker-limits)。
+ 連線 - 您可以在公有或私有 Virtual Private Cloud (VPC) 中建立代理程式。若是私有 VPC，您的 Lambda 函數需要存取 VPC 才能接收訊息。如需詳細資訊，請參閱本節稍後的[設定網路安全](process-mq-messages-with-lambda.md#process-mq-messages-with-lambda-networkconfiguration)。
+ 事件目的地 - 僅支援佇列目的地。然而，您可以使用虛擬主題，當作為佇列與 Lambda 互動時，其行為在內部可作為主題。如需詳細資訊，請參閱 Apache ActiveMQ 網站上的[虛擬目的地](https://activemq.apache.org/virtual-destinations)，以及 RabbitMQ 網站上的[虛擬主機](https://www.rabbitmq.com/vhosts.html)。
+ 網路拓撲 - 對於 ActiveMQ，每個事件來源映射僅支援單一執行個體或待命代理程式。對於 RabbitMQ，每個事件來源映射僅支援單一執行個體代理程式或叢集部署。單一執行個體代理程式需要容錯移轉端點。如需這些代理程式部署模式的詳細資訊，請參閱 *Amazon MQ 開發人員指南*中的 [ActiveMQ 代理程式架構](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-broker-architecture.html)和 [Rabbit MQ 代理程式架構](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/rabbitmq-broker-architecture.html)。
+ 協定 - 支援的協定取決於 Amazon MQ 整合的類型。
  + 對於 ActiveMQ 整合，Lambda 會使用 OpenWire/Java Message Service (JMS) 協定來取用訊息。不支援透過其他協定來取用訊息。在 JMS 協定中，僅支援 [https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.6.0/html/classactivemq_1_1commands_1_1_active_m_q_text_message.html](https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.6.0/html/classactivemq_1_1commands_1_1_active_m_q_text_message.html) 和 [https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.9.0/html/classactivemq_1_1commands_1_1_active_m_q_bytes_message.html](https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.9.0/html/classactivemq_1_1commands_1_1_active_m_q_bytes_message.html)。Lambda 也支援 JMS 自訂屬性。如需有關 OpenWire 協定的詳細資訊，請參閱 Apache ActiveMQ 網站上的 [OpenWire](https://activemq.apache.org/openwire.html)。
  + 對於 RabbitMQ 整合，Lambda 透過 AMQP 0-9-1 協定來取用訊息。不支援透過其他協定來取用訊息。如需 RabbitMQ 實作 AMQP 0-9-1 協定的詳細資訊，請參閱 RabbitMQ 網站上的 [AMQP 0-9-1 完整參考指南](https://www.rabbitmq.com/amqp-0-9-1-reference.html)。

Lambda 會自動支援 Amazon MQ 支援的最新版 ActiveMQ 和 RabbitMQ。如需支援的最新版，請參閱 *Amazon MQ 開發人員指南*中的 [Amazon MQ 版本備註](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-release-notes.html)。

**注意**  
根據預設，Amazon MQ 具有每週代理程式維護時段。代理程式在該時段不可用。若是無待命狀態的代理程式，則 Lambda 無法在該時段處理任何訊息。

**Topics**
+ [

## 了解 Amazon MQ 的 Lambda 取用者群組
](#services-mq-configure)
+ [

# 設定 Lambda 的 Amazon MQ 事件來源
](process-mq-messages-with-lambda.md)
+ [

# 事件來源映射參數
](services-mq-params.md)
+ [

# 從 Amazon MQ 事件來源篩選事件
](with-mq-filtering.md)
+ [

# 對 Amazon MQ 事件來源映射錯誤進行疑難排解
](services-mq-errors.md)

## 了解 Amazon MQ 的 Lambda 取用者群組
<a name="services-mq-configure"></a>

若要與 Amazon MQ 互動，Lambda 會建立可以從您的 Amazon MQ 代理程式讀取的取用者群體。建立取用者群組時，會使用與事件來源映射 UUID 相同的 ID。

對於 Amazon MQ 事件來源，Lambda 會批次處理記錄，並在單個承載中將它們傳送到您的函數。要控制行為，您可以設定批次間隔和批次大小。Lambda 會提取訊息，直到它處理最大為 6 MB 的承載大小、批次間隔過期或記錄數達到完整批次大小。如需詳細資訊，請參閱[批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)。

取用者群組會將訊息擷取為位元組 BLOB，並透過 base64 將其編碼成單一 JSON 承載，然後調用您的函數。如果函數針對批次中的任何訊息傳回錯誤，Lambda 會重試整個批次的訊息，直至處理成功或訊息過期。

**注意**  
雖然 Lambda 函數的逾時上限通常為 15 分鐘，但 Amazon MSK、自我管理的 Apache Kafka、Amazon DocumentDB 以及 Amazon MQ for ActiveMQ 和 Amazon MQ for RabbitMQ 的事件來源映射只支援 14 分鐘逾時限制上限的函數。此限制條件可確保事件來源映射能夠正確處理函數錯誤和重試。

您可以使用 Amazon CloudWatch 中的 `ConcurrentExecutions` 指標，監控指定函數的並行用量。如需並行的詳細資訊，請參閱[設定函數的預留並行](configuration-concurrency.md)。

**Example Amazon MQ 記錄事件**  

```
{
   "eventSource": "aws:mq",
   "eventSourceArn": "arn:aws:mq:us-east-2:111122223333:broker:test:b-9bcfa592-423a-4942-879d-eb284b418fc8",
   "messages": [
      { 
        "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-east-2.amazonaws.com.rproxy.goskope.com-37557-1234520418293-4:1:1:1:1", 
        "messageType": "jms/text-message",
        "deliveryMode": 1,
        "replyTo": null,
        "type": null,
        "expiration": "60000",
        "priority": 1,
        "correlationId": "myJMSCoID",
        "redelivered": false,
        "destination": { 
          "physicalName": "testQueue" 
        },
        "data":"QUJDOkFBQUE=",
        "timestamp": 1598827811958,
        "brokerInTime": 1598827811958, 
        "brokerOutTime": 1598827811959, 
        "properties": {
          "index": "1",
          "doAlarm": "false",
          "myCustomProperty": "value"
        }
      },
      { 
        "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-east-2.amazonaws.com.rproxy.goskope.com-37557-1234520418293-4:1:1:1:1",
        "messageType": "jms/bytes-message",
        "deliveryMode": 1,
        "replyTo": null,
        "type": null,
        "expiration": "60000",
        "priority": 2,
        "correlationId": "myJMSCoID1",
        "redelivered": false,
        "destination": { 
          "physicalName": "testQueue" 
        },
        "data":"LQaGQ82S48k=",
        "timestamp": 1598827811958,
        "brokerInTime": 1598827811958, 
        "brokerOutTime": 1598827811959, 
        "properties": {
          "index": "1",
          "doAlarm": "false",
          "myCustomProperty": "value"
        }
      }
   ]
}
```

```
{
  "eventSource": "aws:rmq",
  "eventSourceArn": "arn:aws:mq:us-east-2:111122223333:broker:pizzaBroker:b-9bcfa592-423a-4942-879d-eb284b418fc8",
  "rmqMessagesByQueue": {
    "pizzaQueue::/": [
      {
        "basicProperties": {
          "contentType": "text/plain",
          "contentEncoding": null,
          "headers": {
            "header1": {
              "bytes": [
                118,
                97,
                108,
                117,
                101,
                49
              ]
            },
            "header2": {
              "bytes": [
                118,
                97,
                108,
                117,
                101,
                50
              ]
            },
            "numberInHeader": 10
          },
          "deliveryMode": 1,
          "priority": 34,
          "correlationId": null,
          "replyTo": null,
          "expiration": "60000",
          "messageId": null,
          "timestamp": "Jan 1, 1970, 12:33:41 AM",
          "type": null,
          "userId": "AIDACKCEVSQ6C2EXAMPLE",
          "appId": null,
          "clusterId": null,
          "bodySize": 80
        },
        "redelivered": false,
        "data": "eyJ0aW1lb3V0IjowLCJkYXRhIjoiQ1pybWYwR3c4T3Y0YnFMUXhENEUifQ=="
      }
    ]
  }
}
```
在 RabbitMQ 範例中，`pizzaQueue` 是 RabbitMQ 佇列的名稱，`/` 是虛擬主機的名稱。接收訊息時，事件來源會在 `pizzaQueue::/` 列出訊息。

# 設定 Lambda 的 Amazon MQ 事件來源
<a name="process-mq-messages-with-lambda"></a>

**Topics**
+ [

## 設定網路安全
](#process-mq-messages-with-lambda-networkconfiguration)
+ [

## 建立事件來源映射
](#services-mq-eventsourcemapping)

## 設定網路安全
<a name="process-mq-messages-with-lambda-networkconfiguration"></a>

若要透過事件來源映射授予 Lambda 對 Amazon MQ 的完整存取權，您的代理程式必須使用公有端點 (公有 IP 位址)，或者您必須提供建立代理程式之 Amazon VPC 的存取權。

當您將 Amazon MQ 與 Lambda 搭配使用時，請建立 [AWS PrivateLink VPC 端點](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html)，為您的函數提供 Amazon VPC 中資源的存取權。

**注意**  
AWS PrivateLink 具有使用事件輪詢器預設 （隨需） 模式之事件來源映射的函數需要 VPC 端點。如果您的事件來源映射使用[佈建模式](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)，則不需要設定 AWS PrivateLink VPC 端點。

建立端點以提供對下列資源的存取權：
+  Lambda：為 Lambda 服務主體建立端點。
+  AWS STS — 為 建立端點， AWS STS 以便服務主體代表您擔任角色。
+  Secrets Manager：如果您的代理程式使用 Secrets Manager 來儲存憑證，則請為 Secrets Manager 建立端點。

或者，在 Amazon VPC 中的每個公有子網路上設定一個 NAT 閘道。如需詳細資訊，請參閱[啟用 VPC 連線的 Lambda 函數的網際網路存取](configuration-vpc-internet.md)。

當您為 Amazon MQ 建立事件來源映射時，Lambda 會檢查是否已存在彈性網絡介面 (ENI)，適用於為您的 Amazon VPC 設定的子網路和安全群組。如果 Lambda 找到現有的 ENI，則它會嘗試重複使用它們。否則，Lambda 會建立新的 ENI 以連線至事件來源並調用您的函數。

**注意**  
Lambda 函數一律會在 Lambda 服務所擁有的 VPC 內執行。函數的 VPC 組態不會影響事件來源映射。只有事件來源的聯網組態會決定 Lambda 如何連線至您的事件來源。

為包含代理程式的 Amazon VPC 設定安全群組。根據預設，Amazon MQ 會使用下列連接埠：`61617` (Amazon MQ for ActiveMQ) 和 `5671` (Amazon MQ for RabbitMQ)。
+ 傳入規則：允許與事件來源相關聯之安全群組的預設代理程式連接埠上的所有流量。或者，您可使用自我參照安全群組規則，允許來自同一安全群組內其他執行個體的存取。
+ 傳出規則 – 如果您的函數需要與服務通訊`443`，允許外部目的地連接埠上的所有流量 AWS 。或者，如果您不需要與其他 AWS 服務通訊，您也可以使用自我參考安全群組規則來限制對代理程式的存取。
+ Amazon VPC 端點傳入規則：如果您使用的是 Amazon VPC 端點，與您的 Amazon VPC 端點相關聯的安全群組必須允許來自代理程式安全群組的連接埠 `443` 上的傳入流量。

如果代理程式使用身分驗證，也可以限制 Secrets Manager 端點的端點政策。若要呼叫 Secrets Manager API，Lambda 會使用您的函數角色，而不是 Lambda 服務主體。

**Example VPC 端點政策 — Secrets Manager 端點**  

```
{
      "Statement": [
          {
              "Action": "secretsmanager:GetSecretValue",
              "Effect": "Allow",
              "Principal": {
                  "AWS": [
                      "arn:aws::iam::123456789012:role/my-role"
                  ]
              },
              "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
          }
      ]
  }
```

當您使用 Amazon VPC 端點時， 會使用端點的彈性網路界面 (ENI) AWS 路由您的 API 呼叫來叫用函數。Lambda 服務主體需要在使用這些 ENI 的任何角色和函數上呼叫 `lambda:InvokeFunction`。

根據預設，Amazon VPC 端點具有開放的 IAM 政策，允許廣泛存取資源。最佳實務是限制這些政策，以使用該端點執行所需的動作。為了確保事件來源映射能夠調用 Lambda 函數，VPC 端點政策必須允許 Lambda 服務主體呼叫 `sts:AssumeRole` 和 `lambda:InvokeFunction`。限制您的 VPC 端點政策以僅允許源自您組織內部的 API 呼叫，可阻止事件來源映射正常運作，因此在這些政策中需要 `"Resource": "*"`。

下列範例 VPC 端點政策展示了如何授予 Lambda 服務主體對 AWS STS 和 Lambda 端點的必要存取權。

**Example VPC 端點政策 — AWS STS 端點**  

```
{
      "Statement": [
          {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
    }
```

**Example VPC 端點政策 – Lambda 端點**  

```
{
      "Statement": [
          {
              "Action": "lambda:InvokeFunction",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
  }
```

## 建立事件來源映射
<a name="services-mq-eventsourcemapping"></a>

建立[事件來源映射](invocation-eventsourcemapping.md)，指示 Lambda 將記錄從 Amazon MQ 代理程式傳送至 Lambda 函數。您可以建立多個事件來源映射，來使用多個函數處理相同資料，或使用單一函數處理來自多個來源的項目。

若要設定您的函數以從 Amazon MQ 讀取，請新增必要的許可，並在 Lambda 主控台中建立 **MQ** 觸發條件。

若要從 Amazon MQ 代理程式讀取記錄，您的 Lambda 函數需要將下列許可。您可以透過將許可陳述式新增至您的函數[執行角色](lambda-intro-execution-role.md)，授予 Lambda 許可，以與您的 Amazon MQ 代理程式及其基礎資源互動：
+ [mq:DescribeBroker](https://docs.aws.amazon.com/amazon-mq/latest/api-reference/brokers-broker-id.html#brokers-broker-id-http-methods)
+ [secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)
+ [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
+ [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
+ [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
+ [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
+ [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
+ [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
+ [logs:CreateLogGroup](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
+ [logs:CreateLogStream](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html)
+ [日誌：PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)

**注意**  
使用加密的客戶管理金鑰時，也請新增 `[kms:Decrypt](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn-bootstrap-brokers.html#clusters-clusterarn-bootstrap-brokersget)` 許可。

**若要新增許可並建立觸發條件**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函數的名稱。

1. 依序選擇 **Configuration** (組態) 索引標籤和 **Permissions** (許可)。

1. 在**角色名稱**下面，選擇執行角色連結。此連結會在 IAM 主控台中開啟該角色。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/execution-role.png)

1. 選擇**新增許可**，然後選擇**建立內嵌政策**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/inline-policy.png)

1. 在**政策編輯器**中，選擇 **JSON**。輸入下列政策。您的函數需要這些許可才能從 Amazon MQ 代理程式讀取。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
         {
           "Effect": "Allow",
           "Action": [
             "mq:DescribeBroker",
             "secretsmanager:GetSecretValue",
             "ec2:CreateNetworkInterface",
             "ec2:DeleteNetworkInterface",
             "ec2:DescribeNetworkInterfaces", 
             "ec2:DescribeSecurityGroups",
             "ec2:DescribeSubnets",
             "ec2:DescribeVpcs",
             "logs:CreateLogGroup",
             "logs:CreateLogStream", 
             "logs:PutLogEvents"		
           ],
           "Resource": "*"
         }
       ]
     }
   ```

------
**注意**  
使用加密的客戶管理金鑰時，還必須新增 `kms:Decrypt` 許可。

1. 選擇**下一步**。輸入政策名稱，然後選擇**建立政策**。

1. 在 Lambda 主控台中返回您的 Lambda 函數。在**函數概觀**下，選擇**新增觸發條件**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/add-trigger.png)

1. 選擇 **MQ** 觸發條件類型。

1. 設定需要的選項，然後選擇**新增**。

Lambda 支援 Amazon MQ 事件來源的下列選項：
+ **MQ broker (MQ 代理程式)** – 選取 Amazon MQ 代理程式。
+ **Batch size (批次大小)** - 設定單一批次中要擷取的訊息數目上限。
+ **Queue name (佇列名稱)** - 輸入要取用的 Amazon MQ 佇列。
+ **Source access configuration (來源存取組態)** - 輸入儲存您代理程式憑證的虛擬主機資訊和 Secrets Manager 機密。
+ **Enable trigger (啟用觸發條件)** - 停用觸發條件以停止處理記錄。

若要啟用或停用觸發條件 (或將其刪除)，請在設計工具中選擇 **MQ** 觸發條件。若要重新設定觸發條件，請使用事件來源映射 API 操作。

# 事件來源映射參數
<a name="services-mq-params"></a>

所有 Lambda 事件來源類型都會共用相同的 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 和 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 操作。但是，只有一些參數適用於 Amazon MQ 和 RabbitMQ。


| 參數 | 必要 | 預設 | 備註 | 
| --- | --- | --- | --- | 
|  BatchSize  |  否  |  100  |  上限：10,000  | 
|  已啟用  |  N  |  true  | 無 | 
|  FunctionName  |  是  | N/A  | 無 | 
|  FilterCriteria  |  N  |  N/A   |  [控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)  | 
|  MaximumBatchingWindowInSeconds  |  N  |  500 毫秒  |  [批次處理行為](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)  | 
|  佇列  |  N  | N/A |  要使用的 Amazon MQ 代理程式目的地佇列的名稱。  | 
|  SourceAccessConfigurations  |  N  | N/A  |  若為 ActiveMQ，可使用 BASIC\$1AUTH 憑證。若為 RabbitMQ，可同時包含 BASIC\$1AUTH 憑證和 VIRTUAL\$1HOST 資訊。  | 

# 從 Amazon MQ 事件來源篩選事件
<a name="with-mq-filtering"></a>

您可以使用事件篩選來控制 Lambda 將哪些記錄從串流或佇列中傳送至函數。如需事件篩選運作方式的一般資訊，請參閱[控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)。

本節重點介紹 Amazon MQ 事件來源的事件篩選。

**注意**  
Amazon MQ 事件來源映射僅支援依據 `data` 鍵進行篩選。

**Topics**
+ [

## Amazon MQ 事件篩選基本概念
](#filtering-AMQ)

## Amazon MQ 事件篩選基本概念
<a name="filtering-AMQ"></a>

假設您的 Amazon MQ 訊息佇列包含有效 JSON 格式或純字串的訊息。範例記錄如下所示，資料在 `data` 欄位中會轉換為 Base64 編碼字串。

------
#### [ ActiveMQ ]

```
{ 
    "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-east-2.amazonaws.com.rproxy.goskope.com-37557-1234520418293-4:1:1:1:1", 
    "messageType": "jms/text-message",
    "deliveryMode": 1,
    "replyTo": null,
    "type": null,
    "expiration": "60000",
    "priority": 1,
    "correlationId": "myJMSCoID",
    "redelivered": false,
    "destination": { 
      "physicalName": "testQueue" 
    },
    "data":"QUJDOkFBQUE=",
    "timestamp": 1598827811958,
    "brokerInTime": 1598827811958, 
    "brokerOutTime": 1598827811959, 
    "properties": {
      "index": "1",
      "doAlarm": "false",
      "myCustomProperty": "value"
    }
}
```

------
#### [ RabbitMQ ]

```
{
    "basicProperties": {
        "contentType": "text/plain",
        "contentEncoding": null,
        "headers": {
            "header1": {
                "bytes": [
                  118,
                  97,
                  108,
                  117,
                  101,
                  49
                ]
            },
            "header2": {
                "bytes": [
                  118,
                  97,
                  108,
                  117,
                  101,
                  50
                ]
            },
            "numberInHeader": 10
        },
        "deliveryMode": 1,
        "priority": 34,
        "correlationId": null,
        "replyTo": null,
        "expiration": "60000",
        "messageId": null,
        "timestamp": "Jan 1, 1970, 12:33:41 AM",
        "type": null,
        "userId": "AIDACKCEVSQ6C2EXAMPLE",
        "appId": null,
        "clusterId": null,
        "bodySize": 80
        },
    "redelivered": false,
    "data": "eyJ0aW1lb3V0IjowLCJkYXRhIjoiQ1pybWYwR3c4T3Y0YnFMUXhENEUifQ=="
}
```

------

對於 Active MQ 和 Rabbit MQ 代理程式，您可以使用事件篩選透過 `data` 索引鍵來篩選記錄。假設您的 Amazon MQ 佇列包含以下 JSON 格式的訊息。

```
{
    "timeout": 0,
    "IPAddress": "203.0.113.254"
}
```

若要僅篩選 `timeout` 欄位大於 0 的記錄，`FilterCriteria` 物件將如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0] } } ] } }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "data": {
        "timeout": [ { "numeric": [ ">", 0 ] } ]
        }
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "data" : { "timeout" : [ { "numeric": [ ">", 0 ] } ] } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:mq:us-east-2:123456789012:broker:my-broker:b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0 ] } ] } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0 ] } ] } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0 ] } ] } }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "data" : { "timeout" : [ { "numeric": [ ">", 0 ] } ] } }'
```

------

使用 Amazon MQ，您也可以篩選訊息為純字串的記錄。假設您只想處理訊息以「結果：」開頭的記錄。`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"data\" : [ { \"prefix\": \"Result: \" } ] }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "data": [
        {
        "prefix": "Result: "
        }
    ]
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "data" : [ { "prefix": "Result: " } ] }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:mq:us-east-2:123456789012:broker:my-broker:b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : [ { \"prefix\": \"Result: \" } ] }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : [ { \"prefix\": \"Result: \" } ] }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "data" : [ { "prefix": "Result " } ] }'
```

------

Amazon MQ 訊息必須是 UTF-8 編碼的字串，可以是純字串或 JSON 格式。這是因為 Lambda 會在套用篩選條件之前，將 Amazon MQ 位元組陣列解碼成 UTF-8。如果您的訊息使用其他編碼方式 (例如 UTF-16 或 ASCII)，或者訊息格式與 `FilterCriteria` 格式不相符，則 Lambda 只會處理中繼資料篩選條件。下表摘要說明特定行為：


| 傳入訊息 格式 | 訊息屬性的篩選條件模式格式 | 產生的動作 | 
| --- | --- | --- | 
|  純文字的字串  |  純文字的字串  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 
|  純文字的字串  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  純文字的字串  |  有效的 JSON  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  純文字的字串  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  有效的 JSON  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 
|  非 UTF-8 編碼字串  |  JSON、純字串或沒有模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 

# 對 Amazon MQ 事件來源映射錯誤進行疑難排解
<a name="services-mq-errors"></a>

當 Lambda 函數遇到無法復原的錯誤時，您的 Amazon MQ 取用者將停止處理記錄。任何其他取用者可能會繼續處理，只要他們沒有遇到相同的錯誤。若要判斷停止 `StateTransitionReason` 取用者的潛在原因，請檢查傳回詳細資料中的 `EventSourceMapping` 欄位，以取得下列其中一個程式碼：

**`ESM_CONFIG_NOT_VALID`**  
事件來源對應組態無效。

**`EVENT_SOURCE_AUTHN_ERROR`**  
Lambda 驗證事件來源失敗。

**`EVENT_SOURCE_AUTHZ_ERROR`**  
Lambda 沒有存取事件來源所需的許可。

**`FUNCTION_CONFIG_NOT_VALID`**  
該函數的配置無效。

如果記錄因大小而遭 Lambda 棄置，則也將不會得到處理。Lambda 記錄的大小限制為 6MB。若要在函數錯誤時重新傳遞訊息，您可以使用無效字母佇列 (DLQ)。如需詳細資訊，請參閱 Apache ActiveMQ 網站上的[訊息重新傳遞和 DLQ 處理](https://activemq.apache.org/message-redelivery-and-dlq-handling)，以及 RabbitMQ 網站上的[可靠性指南](https://www.rabbitmq.com/reliability.html)。

**注意**  
Lambda 不支援自訂重新傳遞政策，相反，Lambda 會使用具有來自 Apache ActiveMQ 網站[重新傳遞政策](https://activemq.apache.org/redelivery-policy)頁面中之預設值的政策，並將 `maximumRedeliveries` 設定為 6。

# AWS Lambda 搭配 Amazon RDS 使用
<a name="services-rds"></a>

您可以直接或透過 Amazon RDS Proxy 將 Lambda 函數連線到 Amazon Relational Database Service (Amazon RDS)。直接連線適用於簡單的案例，生產環境則建議使用代理。資料庫代理管理許多共用資料庫連線，讓函數在不耗盡資料庫連線的情況下達到高並行層級。

我們建議將 Amazon RDS Proxy 用於 Lambda 函數，這些函數會頻繁進行短資料庫連線，或是開啟和關閉大量資料庫連線。如需詳細資訊，請參閱《Amazon Relational Database Service 開發人員指南》中的 [Automatically connecting a Lambda function and a DB instance](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/lambda-rds-connect.html) 一節。

**提示**  
若要將 Lambda 函式快速連線至 Amazon RDS 資料庫，您可以使用主控台內的引導精靈。若要開啟精靈，請執行下列操作：  
開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。
選取您要連接資料庫的函數。
在**組態**索引標籤，選取 **RDS 資料庫**。
選擇**連接至 RDS 資料庫**。
將函數連接至資料庫之後，您可以選擇**新增代理**來建立代理。

## 設定函數以使用 RDS 資源
<a name="rds-configuration"></a>

在 Lambda 主控台中，您可以佈建和設定 Amazon RDS 資料庫執行個體和代理資源。您可以在**組態**索引標籤下導覽至 **RDS 資料庫**來執行此操作。或者，您也可以在 Amazon RDS 主控台中建立與設定 Lambda 函數的連線。設定 RDS 資料庫執行個體以與 Lambda 搭配使用時，請注意以下條件：
+ 若要連線到資料庫，您的函數必須位於資料庫執行所在的相同 Amazon VPC 內。
+ 您可以搭配 MySQL、MariaDB、PostgreSQL 或 Microsoft SQL Server 引擎，使用 Amazon RDS 資料庫。
+ 您也可以搭配 MySQL 或 PostgreSQL 引擎，使用 Aurora DB 叢集。
+ 您需要提供 Secrets Manager 秘密以用於資料庫身分驗證。
+ IAM 角色必須提供使用秘密的許可，而受信任的政策必須允許 Amazon RDS 擔任該角色。
+  使用主控台設定 Amazon RDS 資源，並將其連線至函數的 IAM 主體必須具有下列許可：

### 許可政策範例
<a name="rds-lambda-permissions"></a>

**注意**  
 只有在您設定 Amazon RDS Proxy 來管理資料庫連線集區時，才需要這些 Amazon RDS Proxy 許可。

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateSecurityGroup",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeSubnets",
        "ec2:DescribeVpcs",
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:AuthorizeSecurityGroupEgress",
        "ec2:RevokeSecurityGroupEgress",
        "ec2:CreateNetworkInterface",
        "ec2:DeleteNetworkInterface",
        "ec2:DescribeNetworkInterfaces"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "rds-db:connect",
        "rds:CreateDBProxy",
        "rds:CreateDBInstance",
        "rds:CreateDBSubnetGroup",
        "rds:DescribeDBClusters",
        "rds:DescribeDBInstances",
        "rds:DescribeDBSubnetGroups",
        "rds:DescribeDBProxies",
        "rds:DescribeDBProxyTargets",
        "rds:DescribeDBProxyTargetGroups",
        "rds:RegisterDBProxyTargets",
        "rds:ModifyDBInstance",
        "rds:ModifyDBProxy"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "lambda:CreateFunction",
        "lambda:ListFunctions",
        "lambda:UpdateFunctionConfiguration"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:AttachRolePolicy",
        "iam:CreateRole",
        "iam:CreatePolicy"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds",
        "secretsmanager:CreateSecret"
      ],
      "Resource": "*"
    }
  ]
}
```

------

Amazon RDS 會按資料庫執行個體大小收取代理程式的小時費率，請參閱 [RDS 代理定價](https://aws.amazon.com/rds/proxy/pricing/)以了解詳細資訊。如需代理連線的一般詳細資訊，請參閱《Amazon RDS 使用者指南》中的[使用 Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html)。

### Amazon RDS 連線的 SSL/TLS 要求
<a name="rds-lambda-certificates"></a>

若要對 Amazon RDS 資料庫執行個體進行安全的 SSL/TLS 連線，您的 Lambda 函式必須使用信任的憑證來驗證資料庫伺服器的身分。Lambda 會根據您的部署套件類型，採用不同方式處理這些憑證：
+ [.zip 壓縮檔](configuration-function-zip.md)：憑證處理方式會因執行時期而異：
  + **Node.js 18 及更早版本**：Lambda 會自動包含 CA 憑證與 RDS 憑證。
  + **Node.js 20 及更新版本**：Lambda 預設不再載入額外的 CA 憑證。將 `NODE_EXTRA_CA_CERTS` 環境變數設為 `/var/runtime/ca-cert.pem`。

   AWS 區域 將新的 Amazon RDS 憑證新增至 Lambda 受管執行期最多可能需要 4 週的時間。
+ [容器映像](images-create.md)： AWS 基礎映像僅包含 CA 憑證。如果您的函式需連線至 Amazon RDS 資料庫執行個體，必須在容器映像中包含對應的憑證。在您的 Dockerfile 中，下載[與您託管資料庫 AWS 區域 的 對應的憑證套件。](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesDownload)範例：

  ```
  RUN curl https://truststore.pki.rds.amazonaws.com/us-east-1/us-east-1-bundle.pem -o /us-east-1-bundle.pem
  ```

此命令會下載 Amazon RDS 憑證套件，並將其儲存在容器根目錄中的絕對路徑 `/us-east-1-bundle.pem`。在函式程式碼中設定資料庫連線時，必須參考此確切路徑。範例：

------
#### [ Node.js ]

由於 Node.js 資料庫用戶端需要記憶體中的實際憑證內容，而不只是憑證檔案的路徑，因此 `readFileSync` 函式為必要項目。如果沒有 `readFileSync` 函式，用戶端會將路徑字串解譯為憑證內容，導致「憑證鏈中存在自我簽署憑證」錯誤。

**Example OCI 函式的 Node.js 連線組態**  

```
import { readFileSync } from 'fs';

// ...

let connectionConfig = {
    host: process.env.ProxyHostName,
    user: process.env.DBUserName,
    password: token,
    database: process.env.DBName,
    ssl: {
        ca: readFileSync('/us-east-1-bundle.pem') // Load RDS certificate content from file into memory
    }
};
```

------
#### [ Python ]

**Example OCI 函式的 Python 連線組態**  

```
connection = pymysql.connect(
    host=proxy_host_name,
    user=db_username,
    password=token,
    db=db_name,
    port=port,
    ssl={'ca': '/us-east-1-bundle.pem'}  #Path to the certificate in container
)
```

------
#### [ Java ]

對於使用 JDBC 連線的 Java 函式，連線字串必須包含：
+ `useSSL=true`
+ `requireSSL=true`
+ 指向容器映像中 Amazon RDS 憑證位置的 `sslCA` 參數

**Example OCI 函式的 Java 連線字串**  

```
// Define connection string
String connectionString = String.format("jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true&sslCA=/us-east-1-bundle.pem", // Path to the certificate in container
        System.getenv("ProxyHostName"),
        System.getenv("Port"),
        System.getenv("DBName"));
```

------
#### [ .NET ]

**Example OCI 函式中 MySQL 連線的 .NET 連線字串**  

```
/// Build the Connection String with the Token 
string connectionString = $"Server={Environment.GetEnvironmentVariable("RDS_ENDPOINT")};" +
                         $"Port={Environment.GetEnvironmentVariable("RDS_PORT")};" +
                         $"Uid={Environment.GetEnvironmentVariable("RDS_USERNAME")};" +
                         $"Pwd={authToken};" +
                         "SslMode=Required;" +
                         "SslCa=/us-east-1-bundle.pem";  // Path to the certificate in container
```

------
#### [ Go ]

對於使用 MySQL 連線的 Go 函式，請將 Amazon RDS 憑證載入憑證集區，並向 MySQL 驅動程式註冊該憑證。連線字串隨後必須透過 `tls` 參數引用此組態。

**Example OCI 函式中 MySQL 連線的 Go 程式碼**  

```
import (
    "crypto/tls"
    "crypto/x509"
    "os"
    "github.com/go-sql-driver/mysql"
)

...

// Create certificate pool and register TLS config
rootCertPool := x509.NewCertPool()
pem, err := os.ReadFile("/us-east-1-bundle.pem")  // Path to the certificate in container
if err != nil {
    panic("failed to read certificate file: " + err.Error())
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    panic("failed to append PEM")
}

mysql.RegisterTLSConfig("custom", &tls.Config{
    RootCAs: rootCertPool,
})

dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?allowCleartextPasswords=true&tls=custom",
    dbUser, authenticationToken, dbEndpoint, dbName,
)
```

------
#### [ Ruby ]

**Example OCI 函式的 Ruby 連線組態**  

```
conn = Mysql2::Client.new(
    host: endpoint,
    username: user,
    password: token,
    port: port,
    database: db_name,
    sslca: '/us-east-1-bundle.pem',  # Path to the certificate in container
    sslverify: true
)
```

------

## 連線至 Lambda 函數中的 Amazon RDS 資料庫
<a name="rds-connection"></a>

以下程式碼範例示範如何實作連線至 Amazon RDS 資料庫的 Lambda 函式。該函數會提出簡單的資料庫請求並傳回結果。

**注意**  
這些程式碼範例僅適用於 [.zip 部署套件](configuration-function-zip.md)。如果使用[容器映像](images-create.md)部署函式，您必須在函式程式碼中指定 Amazon RDS 憑證檔案，如[上一節](#oci-certificate)所述。

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 .NET 連線至 Lambda 函式中的 Amazon RDS 資料庫。  

```
using System.Data;
using System.Text.Json;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using MySql.Data.MySqlClient;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace aws_rds;

public class InputModel
{
    public string key1 { get; set; }
    public string key2 { get; set; }
}

public class Function
{
    /// <summary>
    // Handles the Lambda function execution for connecting to RDS using IAM authentication.
    /// </summary>
    /// <param name="input">The input event data passed to the Lambda function</param>
    /// <param name="context">The Lambda execution context that provides runtime information</param>
    /// <returns>A response object containing the execution result</returns>

    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        // Sample Input: {"body": "{\"key1\":\"20\", \"key2\":\"25\"}"}
        var input = JsonSerializer.Deserialize<InputModel>(request.Body);

        /// Obtain authentication token
        var authToken = RDSAuthTokenGenerator.GenerateAuthToken(
            Environment.GetEnvironmentVariable("RDS_ENDPOINT"),
            Convert.ToInt32(Environment.GetEnvironmentVariable("RDS_PORT")),
            Environment.GetEnvironmentVariable("RDS_USERNAME")
        );

        /// Build the Connection String with the Token 
        string connectionString = $"Server={Environment.GetEnvironmentVariable("RDS_ENDPOINT")};" +
                                  $"Port={Environment.GetEnvironmentVariable("RDS_PORT")};" +
                                  $"Uid={Environment.GetEnvironmentVariable("RDS_USERNAME")};" +
                                  $"Pwd={authToken};";


        try
        {
            await using var connection = new MySqlConnection(connectionString);
            await connection.OpenAsync();

            const string sql = "SELECT @param1 + @param2 AS Sum";

            await using var command = new MySqlCommand(sql, connection);
            command.Parameters.AddWithValue("@param1", int.Parse(input.key1 ?? "0"));
            command.Parameters.AddWithValue("@param2", int.Parse(input.key2 ?? "0"));

            await using var reader = await command.ExecuteReaderAsync();
            if (await reader.ReadAsync())
            {
                int result = reader.GetInt32("Sum");

                //Sample Response: {"statusCode":200,"body":"{\"message\":\"The sum is: 45\"}","isBase64Encoded":false}
                return new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = JsonSerializer.Serialize(new { message = $"The sum is: {result}" })
                };
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }

        return new APIGatewayProxyResponse
        {
            StatusCode = 500,
            Body = JsonSerializer.Serialize(new { error = "Internal server error" })
        };
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 Go 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
/*
Golang v2 code here.
*/

package main

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"os"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/feature/rds/auth"
	_ "github.com/go-sql-driver/mysql"
)

type MyEvent struct {
	Name string `json:"name"`
}

func HandleRequest(event *MyEvent) (map[string]interface{}, error) {

	var dbName string = os.Getenv("DatabaseName")
	var dbUser string = os.Getenv("DatabaseUser")
	var dbHost string = os.Getenv("DBHost") // Add hostname without https
	var dbPort int = os.Getenv("Port")      // Add port number
	var dbEndpoint string = fmt.Sprintf("%s:%d", dbHost, dbPort)
	var region string = os.Getenv("AWS_REGION")

	cfg, err := config.LoadDefaultConfig(context.TODO())
	if err != nil {
		panic("configuration error: " + err.Error())
	}

	authenticationToken, err := auth.BuildAuthToken(
		context.TODO(), dbEndpoint, region, dbUser, cfg.Credentials)
	if err != nil {
		panic("failed to create authentication token: " + err.Error())
	}

	dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true&allowCleartextPasswords=true",
		dbUser, authenticationToken, dbEndpoint, dbName,
	)

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	var sum int
	err = db.QueryRow("SELECT ?+? AS sum", 3, 2).Scan(&sum)
	if err != nil {
		panic(err)
	}
	s := fmt.Sprint(sum)
	message := fmt.Sprintf("The selected sum is: %s", s)

	messageBytes, err := json.Marshal(message)
	if err != nil {
		return nil, err
	}

	messageString := string(messageBytes)
	return map[string]interface{}{
		"statusCode": 200,
		"headers":    map[string]string{"Content-Type": "application/json"},
		"body":       messageString,
	}, nil
}

func main() {
	lambda.Start(HandleRequest)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 Java 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.rdsdata.RdsDataClient;
import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementRequest;
import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementResponse;
import software.amazon.awssdk.services.rdsdata.model.Field;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class RdsLambdaHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Override
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) {
        APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();

        try {
            // Obtain auth token
            String token = createAuthToken();

            // Define connection configuration
            String connectionString = String.format("jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true",
                    System.getenv("ProxyHostName"),
                    System.getenv("Port"),
                    System.getenv("DBName"));

            // Establish a connection to the database
            try (Connection connection = DriverManager.getConnection(connectionString, System.getenv("DBUserName"), token);
                 PreparedStatement statement = connection.prepareStatement("SELECT ? + ? AS sum")) {

                statement.setInt(1, 3);
                statement.setInt(2, 2);

                try (ResultSet resultSet = statement.executeQuery()) {
                    if (resultSet.next()) {
                        int sum = resultSet.getInt("sum");
                        response.setStatusCode(200);
                        response.setBody("The selected sum is: " + sum);
                    }
                }
            }

        } catch (Exception e) {
            response.setStatusCode(500);
            response.setBody("Error: " + e.getMessage());
        }

        return response;
    }

    private String createAuthToken() {
        // Create RDS Data Service client
        RdsDataClient rdsDataClient = RdsDataClient.builder()
                .region(Region.of(System.getenv("AWS_REGION")))
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build();

        // Define authentication request
        ExecuteStatementRequest request = ExecuteStatementRequest.builder()
                .resourceArn(System.getenv("ProxyHostName"))
                .secretArn(System.getenv("DBUserName"))
                .database(System.getenv("DBName"))
                .sql("SELECT 'RDS IAM Authentication'")
                .build();

        // Execute request and obtain authentication token
        ExecuteStatementResponse response = rdsDataClient.executeStatement(request);
        Field tokenField = response.records().get(0).get(0);

        return tokenField.stringValue();
    }
}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 JavaScript 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/* 
Node.js code here.
*/
// ES6+ example
import { Signer } from "@aws-sdk/rds-signer";
import mysql from 'mysql2/promise';

async function createAuthToken() {
  // Define connection authentication parameters
  const dbinfo = {

    hostname: process.env.ProxyHostName,
    port: process.env.Port,
    username: process.env.DBUserName,
    region: process.env.AWS_REGION,

  }

  // Create RDS Signer object
  const signer = new Signer(dbinfo);

  // Request authorization token from RDS, specifying the username
  const token = await signer.getAuthToken();
  return token;
}

async function dbOps() {

  // Obtain auth token
  const token = await createAuthToken();
  // Define connection configuration
  let connectionConfig = {
    host: process.env.ProxyHostName,
    user: process.env.DBUserName,
    password: token,
    database: process.env.DBName,
    ssl: 'Amazon RDS'
  }
  // Create the connection to the DB
  const conn = await mysql.createConnection(connectionConfig);
  // Obtain the result of the query
  const [res,] = await conn.execute('select ?+? as sum', [3, 2]);
  return res;

}

export const handler = async (event) => {
  // Execute database flow
  const result = await dbOps();
  // Return result
  return {
    statusCode: 200,
    body: JSON.stringify("The selected sum is: " + result[0].sum)
  }
};
```
使用 TypeScript 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
import { Signer } from "@aws-sdk/rds-signer";
import mysql from 'mysql2/promise';

// RDS settings
// Using '!' (non-null assertion operator) to tell the TypeScript compiler that the DB settings are not null or undefined,
const proxy_host_name = process.env.PROXY_HOST_NAME!
const port = parseInt(process.env.PORT!)
const db_name = process.env.DB_NAME!
const db_user_name = process.env.DB_USER_NAME!
const aws_region = process.env.AWS_REGION!


async function createAuthToken(): Promise<string> {

    // Create RDS Signer object
    const signer = new Signer({
        hostname: proxy_host_name,
        port: port,
        region: aws_region,
        username: db_user_name
    });

    // Request authorization token from RDS, specifying the username
    const token = await signer.getAuthToken();
    return token;
}

async function dbOps(): Promise<mysql.QueryResult | undefined> {
    try {
        // Obtain auth token
        const token = await createAuthToken();
        const conn = await mysql.createConnection({
            host: proxy_host_name,
            user: db_user_name,
            password: token,
            database: db_name,
            ssl: 'Amazon RDS' // Ensure you have the CA bundle for SSL connection
        });
        const [rows, fields] = await conn.execute('SELECT ? + ? AS sum', [3, 2]);
        console.log('result:', rows);
        return rows;
    }
    catch (err) {
        console.log(err);
    }
}

export const lambdaHandler = async (event: any): Promise<{ statusCode: number; body: string }> => {
    // Execute database flow
    const result = await dbOps();

    // Return error is result is undefined
    if (result == undefined)
        return {
            statusCode: 500,
            body: JSON.stringify(`Error with connection to DB host`)
        }

    // Return result
    return {
        statusCode: 200,
        body: JSON.stringify(`The selected sum is: ${result[0].sum}`)
    };
};
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 PHP 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
<?php
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;
use Aws\Rds\AuthTokenGenerator;
use Aws\Credentials\CredentialProvider;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }


    private function getAuthToken(): string {
        // Define connection authentication parameters
        $dbConnection = [
            'hostname' => getenv('DB_HOSTNAME'),
            'port' => getenv('DB_PORT'),
            'username' => getenv('DB_USERNAME'),
            'region' => getenv('AWS_REGION'),
        ];

        // Create RDS AuthTokenGenerator object
        $generator = new AuthTokenGenerator(CredentialProvider::defaultProvider());

        // Request authorization token from RDS, specifying the username
        return $generator->createToken(
            $dbConnection['hostname'] . ':' . $dbConnection['port'],
            $dbConnection['region'],
            $dbConnection['username']
        );
    }

    private function getQueryResults() {
        // Obtain auth token
        $token = $this->getAuthToken();

        // Define connection configuration
        $connectionConfig = [
            'host' => getenv('DB_HOSTNAME'),
            'user' => getenv('DB_USERNAME'),
            'password' => $token,
            'database' => getenv('DB_NAME'),
        ];

        // Create the connection to the DB
        $conn = new PDO(
            "mysql:host={$connectionConfig['host']};dbname={$connectionConfig['database']}",
            $connectionConfig['user'],
            $connectionConfig['password'],
            [
                PDO::MYSQL_ATTR_SSL_CA => '/path/to/rds-ca-2019-root.pem',
                PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
            ]
        );

        // Obtain the result of the query
        $stmt = $conn->prepare('SELECT ?+? AS sum');
        $stmt->execute([3, 2]);

        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * @param mixed $event
     * @param Context $context
     * @return array
     */
    public function handle(mixed $event, Context $context): array
    {
        $this->logger->info("Processing query");

        // Execute database flow
        $result = $this->getQueryResults();

        return [
            'sum' => $result['sum']
        ];
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 Python 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
import json
import os
import boto3
import pymysql

# RDS settings
proxy_host_name = os.environ['PROXY_HOST_NAME']
port = int(os.environ['PORT'])
db_name = os.environ['DB_NAME']
db_user_name = os.environ['DB_USER_NAME']
aws_region = os.environ['AWS_REGION']


# Fetch RDS Auth Token
def get_auth_token():
    client = boto3.client('rds')
    token = client.generate_db_auth_token(
        DBHostname=proxy_host_name,
        Port=port
        DBUsername=db_user_name
        Region=aws_region
    )
    return token

def lambda_handler(event, context):
    token = get_auth_token()
    try:
        connection = pymysql.connect(
            host=proxy_host_name,
            user=db_user_name,
            password=token,
            db=db_name,
            port=port,
            ssl={'ca': 'Amazon RDS'}  # Ensure you have the CA bundle for SSL connection
        )
        
        with connection.cursor() as cursor:
            cursor.execute('SELECT %s + %s AS sum', (3, 2))
            result = cursor.fetchone()

        return result
        
    except Exception as e:
        return (f"Error: {str(e)}")  # Return an error message if an exception occurs
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 Ruby 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
# Ruby code here.

require 'aws-sdk-rds'
require 'json'
require 'mysql2'

def lambda_handler(event:, context:)
  endpoint = ENV['DBEndpoint'] # Add the endpoint without https"
  port = ENV['Port']           # 3306
  user = ENV['DBUser']
  region = ENV['DBRegion']     # 'us-east-1'
  db_name = ENV['DBName']

  credentials = Aws::Credentials.new(
    ENV['AWS_ACCESS_KEY_ID'],
    ENV['AWS_SECRET_ACCESS_KEY'],
    ENV['AWS_SESSION_TOKEN']
  )
  rds_client = Aws::RDS::AuthTokenGenerator.new(
    region: region, 
    credentials: credentials
  )

  token = rds_client.auth_token(
    endpoint: endpoint+ ':' + port,
    user_name: user,
    region: region
  )

  begin
    conn = Mysql2::Client.new(
      host: endpoint,
      username: user,
      password: token,
      port: port,
      database: db_name,
      sslca: '/var/task/global-bundle.pem', 
      sslverify: true,
      enable_cleartext_plugin: true
    )
    a = 3
    b = 2
    result = conn.query("SELECT #{a} + #{b} AS sum").first['sum']
    puts result
    conn.close
    {
      statusCode: 200,
      body: result.to_json
    }
  rescue => e
    puts "Database connection failed due to #{e}"
  end
end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam)儲存庫中設定和執行。
使用 Rust 連線至 Lambda 函數中的 Amazon RDS 資料庫。  

```
use aws_config::BehaviorVersion;
use aws_credential_types::provider::ProvideCredentials;
use aws_sigv4::{
    http_request::{sign, SignableBody, SignableRequest, SigningSettings},
    sign::v4,
};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use serde_json::{json, Value};
use sqlx::postgres::PgConnectOptions;
use std::env;
use std::time::{Duration, SystemTime};

const RDS_CERTS: &[u8] = include_bytes!("global-bundle.pem");

async fn generate_rds_iam_token(
    db_hostname: &str,
    port: u16,
    db_username: &str,
) -> Result<String, Error> {
    let config = aws_config::load_defaults(BehaviorVersion::v2024_03_28()).await;

    let credentials = config
        .credentials_provider()
        .expect("no credentials provider found")
        .provide_credentials()
        .await
        .expect("unable to load credentials");
    let identity = credentials.into();
    let region = config.region().unwrap().to_string();

    let mut signing_settings = SigningSettings::default();
    signing_settings.expires_in = Some(Duration::from_secs(900));
    signing_settings.signature_location = aws_sigv4::http_request::SignatureLocation::QueryParams;

    let signing_params = v4::SigningParams::builder()
        .identity(&identity)
        .region(&region)
        .name("rds-db")
        .time(SystemTime::now())
        .settings(signing_settings)
        .build()?;

    let url = format!(
        "https://{db_hostname}:{port}/?Action=connect&DBUser={db_user}",
        db_hostname = db_hostname,
        port = port,
        db_user = db_username
    );

    let signable_request =
        SignableRequest::new("GET", &url, std::iter::empty(), SignableBody::Bytes(&[]))
            .expect("signable request");

    let (signing_instructions, _signature) =
        sign(signable_request, &signing_params.into())?.into_parts();

    let mut url = url::Url::parse(&url).unwrap();
    for (name, value) in signing_instructions.params() {
        url.query_pairs_mut().append_pair(name, &value);
    }

    let response = url.to_string().split_off("https://".len());

    Ok(response)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    run(service_fn(handler)).await
}

async fn handler(_event: LambdaEvent<Value>) -> Result<Value, Error> {
    let db_host = env::var("DB_HOSTNAME").expect("DB_HOSTNAME must be set");
    let db_port = env::var("DB_PORT")
        .expect("DB_PORT must be set")
        .parse::<u16>()
        .expect("PORT must be a valid number");
    let db_name = env::var("DB_NAME").expect("DB_NAME must be set");
    let db_user_name = env::var("DB_USERNAME").expect("DB_USERNAME must be set");

    let token = generate_rds_iam_token(&db_host, db_port, &db_user_name).await?;

    let opts = PgConnectOptions::new()
        .host(&db_host)
        .port(db_port)
        .username(&db_user_name)
        .password(&token)
        .database(&db_name)
        .ssl_root_cert_from_pem(RDS_CERTS.to_vec())
        .ssl_mode(sqlx::postgres::PgSslMode::Require);

    let pool = sqlx::postgres::PgPoolOptions::new()
        .connect_with(opts)
        .await?;

    let result: i32 = sqlx::query_scalar("SELECT $1 + $2")
        .bind(3)
        .bind(2)
        .fetch_one(&pool)
        .await?;

    println!("Result: {:?}", result);

    Ok(json!({
        "statusCode": 200,
        "content-type": "text/plain",
        "body": format!("The selected sum is: {result}")
    }))
}
```

------

## 處理來自 Amazon RDS 的事件通知
<a name="rds-events"></a>

您可以使用 Lambda 來處理 Amazon RDS 資料庫的事件通知。Amazon RDS 會將通知傳送到 Amazon Simple Notification Service (Amazon SNS) 主題，您可以進行設定，透過該主題叫用 Lambda 函數。Amazon SNS 會將來自 Amazon RDS 的訊息包裝在自己的事件文件中，並將其傳送到函數。

如需設定 Amazon RDS 資料庫以傳送通知的詳細資訊，請參閱[使用 Amazon RDS 事件通知](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html)。

**Example Amazon SNS 事件中的 Amazon RDS 訊息**  

```
{
        "Records": [
          {
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:us-east-2:123456789012:rds-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
            "EventSource": "aws:sns",
            "Sns": {
              "SignatureVersion": "1",
              "Timestamp": "2023-01-02T12:45:07.000Z",
              "Signature": "tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==",
              "SigningCertUrl": "https://sns.us-east-2.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem",
              "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
              "Message": "{\"Event Source\":\"db-instance\",\"Event Time\":\"2023-01-02 12:45:06.000\",\"Identifier Link\":\"https://console.aws.amazon.com/rds/home?region=eu-west-1#dbinstance:id=dbinstanceid\",\"Source ID\":\"dbinstanceid\",\"Event ID\":\"http://docs.amazonwebservices.com/AmazonRDS/latest/UserGuide/USER_Events.html#RDS-EVENT-0002\",\"Event Message\":\"Finished DB Instance backup\"}",
              "MessageAttributes": {},
              "Type": "Notification",
              "UnsubscribeUrl": "https://sns.us-east-2.amazonaws.com/?Action=Unsubscribe&amp;SubscriptionArn=arn:aws:sns:us-east-2:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
              "TopicArn":"arn:aws:sns:us-east-2:123456789012:sns-lambda",
              "Subject": "RDS Notification Message"
            }
          }
        ]
      }
```

## 完成 Lambda 和 Amazon RDS 教學課程
<a name="rds-database-samples"></a>
+ [使用 Lambda 函數來存取 Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-lambda-tutorial.html)：在《Amazon RDS 誰用著指南》中，學習如何使用 Lambda 函數並透過 Amazon RDS Proxy 將資料寫入 Amazon RDS 資料庫。每當新增訊息，您的 Lambda 函數將從 Amazon SQS 佇列中讀取記錄，然後將新項目寫入資料庫中的資料表。

# 為基於 Lambda 的應用程式選擇資料庫服務
<a name="ddb-rds-database-decision"></a>

許多無伺服器應用程式需要存放和擷取資料。 AWS 提供多種資料庫選項，可與 Lambda 函數搭配使用。最熱門的兩個選擇是 NoSQL 資料庫服務 Amazon DynamoDB，以及傳統的關聯式資料庫解決方案 Amazon RDS。下列各節介紹了這兩種服務與 Lambda 搭配使用時的主要差異，並協助您為無伺服器應用程式選擇合適的資料庫服務。

若要進一步了解 提供的其他資料庫服務 AWS，以及更普遍地了解其使用案例和權衡，請參閱[選擇 AWS 資料庫服務](https://docs.aws.amazon.com/decision-guides/latest/databases-on-aws-how-to-choose/databases-on-aws-how-to-choose.html)。所有 AWS 資料庫服務都與 Lambda 相容，但並非所有資料庫服務都適合自身特定使用案例。

## 選取與 Lambda 搭配使用的資料庫服務時，您有哪些選擇？
<a name="w2aad101d101c19b9"></a>

AWS 提供多個資料庫服務。對於無伺服器應用程式，最熱門的兩個選擇是 DynamoDB 和 Amazon RDS。
+ **DynamoDB** 是一種全受管 NoSQL 資料庫服務，針對無伺服器應用程式進行了最佳化。該服務可在任何規模下提供無縫擴展且穩定的個位數毫秒級效能。
+ **Amazon RDS** 是一種受管關聯式資料庫服務，支援包括 MySQL 與 PostgreSQL 在內的多種資料庫引擎。該服務透過受管基礎結構提供熟悉的 SQL 功能。

## 您已知道自己需求時的建議
<a name="w2aad101d101c19c11"></a>

如果您已經清楚自己的需求，以下是基本建議：

對於需要穩定低延遲效能、自動擴展且不涉及複雜聯結或交易的無伺服器應用程式，建議選擇 [DynamoDB](with-ddb.md)。由於其無伺服器特性，該服務特別適合基於 Lambda 的應用程式。

若需複雜的 SQL 查詢、聯結操作，或是現有應用程式已使用關聯式資料庫時，[Amazon RDS](services-rds.md) 是更佳選擇。但請注意，將 Lambda 函式連線至 Amazon RDS 需要額外的組態，並且可能會影響冷啟動時間。

## 選取資料庫服務時應考量的事項
<a name="w2aad101d101c19c13"></a>

為 Lambda 應用程式選取 DynamoDB 或是 Amazon RDS 時，建議考量下列因素：
+ 連線管理與冷啟動
+ 資料存取模式
+ 查詢複雜性
+ 資料一致性需求
+ 擴展特性
+ 成本模型

透過了解這些因素，您可以選取最符合自身特定使用案例需求的選項。

### 連線管理與冷啟動
<a name="w2aad101d101c19c13b9b1"></a>
+ DynamoDB 對所有操作均使用 HTTP API。Lambda 函式無需維護連線即可發出即時請求，具備更佳的冷啟動效能。每個請求都會使用 AWS 登入資料進行身分驗證，而不會產生連線額外負荷。
+ 由於 Amazon RDS 使用的是傳統資料庫連線，因此需要管理連線集區。這可能會影響冷啟動，因為新的 Lambda 執行個體需要建立連線。您需實作連線集區策略，並且可能要使用 [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html) 來有效管理連線。請注意，使用 Amazon RDS Proxy 會額外產生費用。

### 資料存取模式
<a name="w2aad101d101c19c13b9b3"></a>
+ DynamoDB 最適用於已知的存取模式和單一資料表設計。其非常適合需要根據主索引鍵或次要索引，以穩定低延遲方式存取資料的 Lambda 應用程式。
+ Amazon RDS 具備彈性，能因應複雜查詢與多變的存取模式。當您的 Lambda 函式需要跨多個資料表執行獨特的客製化查詢或複雜的跨表聯結時，其適用性更佳。

### 查詢複雜性
<a name="w2aad101d101c19c13b9b5"></a>
+ DynamoDB 在基於鍵值的簡易操作及預先定義的存取模式方面表現出色。複雜的查詢必須圍繞索引結構進行設計，並且必須在應用程式程式碼中處理聯結。
+ Amazon RDS 支援包含聯結、子查詢與彙總運算的複雜 SQL 查詢。當需要複雜的資料操作時，此優勢可以簡化您的 Lambda 函式程式碼。

### 資料一致性需求
<a name="w2aad101d101c19c13b9b7"></a>
+ DynamoDB 提供最終一致性與強一致性選項，其中強一致性適用於單一項目讀取。雖然支援交易功能，但存在部分限制。
+ Amazon RDS 提供完整的原子性、一致性、隔離性與持久性 (ACID) 合規保障，支援複雜交易。如果您的 Lambda 函式需要複雜的交易或跨多筆記錄的強一致性，Amazon RDS 可能更加合適。

### 擴展特性
<a name="w2aad101d101c19c13b9b9"></a>
+ DynamoDB 會根據您的工作負載自動擴展。其無需預先佈建，即可處理 Lambda 函式中的流量突增情況。您可以使用隨需容量模式，僅需為所使用的容量付費，完全符合 Lambda 的擴展模型。
+ Amazon RDS 會根據您選擇的執行個體規格，提供固定的容量。如果多個 Lambda 函式同時嘗試連線，則可能會超過連線配額。您需謹慎管理連線集區，並可能要實作重試邏輯。

### 成本模型
<a name="w2aad101d101c19c13b9c11"></a>
+ DynamoDB 的定價模式與無伺服器應用程式高度契合。若使用隨需容量，您只需為 Lambda 函式執行的實際讀取與寫入作業付費。閒置時間不收取任何費用。
+ Amazon RDS 會針對執行中的執行個體收費，無論用量如何。對於無伺服器應用程式中典型的零星工作負載，這可能較不具成本效益。不過，對於輸送量高且用量穩定的工作負載，其可能更經濟實惠。

## 開始使用所選資料庫服務
<a name="w2aad101d101c19c15"></a>

您已了解在 DynamoDB 和 Amazon RDS 之間進行選擇的標準，以及二者之間的主要差異。接下來，您可以選取最符合自身需求的選項，並使用下列資源來協助自己開始使用所選的資料庫服務。

------
#### [ DynamoDB ]

**透過下列資源開始使用 DynamoDB**
+ 如需 DynamoDB 服務的簡介，請參閱 *Amazon DynamoDB Developer Guide* 中的 [What is DynamoDB?](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) 部分。
+ 請依照[搭配 API Gateway 使用 Lambda](services-apigateway-tutorial.md) 教學課程，了解如何透過 Lambda 函式在回應 API 請求時，對 DynamoDB 資料表執行 CRUD 操作的範例。
+ 請參閱《Amazon [ DynamoDB 開發人員指南》中的使用 DynamoDB 和 AWS SDKs 進行程式設計](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.html)，以進一步了解如何使用其中一個 SDK 從 Lambda 函數內存取 AWS SDKs DynamoDB。 * DynamoDB * 

------
#### [ Amazon RDS ]

**透過下列資源開始使用 Amazon RDS**
+ 如需 Amazon RDS 服務簡介，請參閱 *Amazon Relational Database Service User Guide* 中的 [What is Amazon Relational Database Service (Amazon RDS)?](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html) 部分。
+ 請依照 *Amazon Relational Database Service User Guide* 中的教學課程 [Using a Lambda function to access an Amazon RDS database](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-lambda-tutorial.html) 執行操作。
+ 請參閱 [AWS Lambda 搭配 Amazon RDS 使用](services-rds.md)，了解有關搭配 Amazon RDS 使用 Lambda 的詳細資訊。

------

# 使用 Lambda 處理 Amazon S3 事件通知
<a name="with-s3"></a>

您可以使用 Lambda 來處理來自 Amazon Simple Storage Service 的[事件通知](https://docs.aws.amazon.com/AmazonS3/latest/userguide/NotificationHowTo.html)。建立或刪除物件時，Amazon S3 可以將事件傳送至 Lambda 函數。您在儲存貯體上設定通知設定，並授予 Amazon S3 許可以在函數以資源為基礎的許可政策上叫用函數。

**警告**  
如果 Lambda 函數使用的是觸發的相同儲存貯體，這可能會造成函數在迴圈中執行。例如，如果儲存貯體在物件每次上傳時都觸發函數，且該函數會將物件上傳至儲存貯體，則函數會間接地觸發本身。若要避免此狀況，請使用兩個儲存貯體，或將觸發設定為僅套用至傳入物件所用的字首。

Amazon S3 使用包含物件詳細資訊的事件以[非同步](invocation-async.md)方式叫用您的函數。以下範例顯示當部署套裝服務上傳至 Amazon S3 時，Amazon S3 傳送的事件。

**Example Amazon S3 通知事件**  

```
{
  "Records": [
    {
      "eventVersion": "2.1",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-2",
      "eventTime": "2019-09-03T19:37:27.192Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "AWS:AIDAINPONIXQXHT3IKHL2"
      },
      "requestParameters": {
        "sourceIPAddress": "205.255.255.255"
      },
      "responseElements": {
        "x-amz-request-id": "D82B88E5F771F645",
        "x-amz-id-2": "vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo="
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "828aa6fc-f7b5-4305-8584-487c791949c1",
        "bucket": {
          "name": "amzn-s3-demo-bucket",
          "ownerIdentity": {
            "principalId": "A3I5XTEXAMAI3E"
          },
          "arn": "arn:aws:s3:::lambda-artifacts-deafc19498e3f2df"
        },
        "object": {
          "key": "b21b84d653bb07b05b1e6b33684dc11b",
          "size": 1305107,
          "eTag": "b21b84d653bb07b05b1e6b33684dc11b",
          "sequencer": "0C0F6F405D6ED209E1"
        }
      }
    }
  ]
}
```

若要叫用您的函數，Amazon S3 需要該函數[以資源為基礎政策](access-control-resource-based.md)的許可。當您在 Lambda 主控台中設定 Amazon S3 觸發條件時，主控台會修改以資源為基礎的政策，讓 Amazon S3 在儲存貯體名稱與帳戶 ID 相符時叫用該函數。如果您在 Amazon S3 中設定通知，您要使用 Lambda API 更新政策。您也可以使用 Lambda API 將許可授予另一個帳戶，或將許可限制為指定的別名。

如果您的函數使用 AWS SDK 來管理 Amazon S3 資源，則其[執行角色](lambda-intro-execution-role.md)也需要 Amazon S3 許可。

**Topics**
+ [

# 教學課程：使用 Amazon S3 觸發條件調用 Lambda 函數
](with-s3-example.md)
+ [

# 教學課程：使用 Amazon S3 觸發條件建立縮圖影像
](with-s3-tutorial.md)

# 教學課程：使用 Amazon S3 觸發條件調用 Lambda 函數
<a name="with-s3-example"></a>

在本教學課程中，您將使用主控台建立 Lambda 函數，並設定 Amazon Simple Storage Service (Amazon S3) 儲存貯體的觸發條件。每當有物件新增至 Amazon S3 儲存貯體，該函數都會執行，然後將物件類型輸出至 Amazon CloudWatch Logs。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3_tut_config.png)


本教學課程示範如何。

1. 建立 Amazon S3 儲存貯體。

1. 建立一個 Lambda 函數，用於傳回 Amazon S3 儲存貯體物件的物件類型。

1. 設定一個 Lambda 觸發條件，用於在有物件上傳至儲存貯體時調用函數。

1. 先使用虛擬事件測試函數，再使用觸發條件進行測試。

完成這些步驟後，您將了解如何設定 Lambda 函數，讓函數在 Amazon S3 儲存貯體中有物件新增或刪除時執行。您只能使用  AWS 管理主控台 來完成本教學課程。

## 建立 Amazon S3 儲存貯體
<a name="with-s3-example-create-bucket"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps1.png)


**建立 Amazon S3 儲存貯體**

1. 開啟 [Amazon S3 主控台](https://console.aws.amazon.com/s3)，然後選取**一般用途儲存貯體**頁面。

1. 選取最 AWS 區域 接近您地理位置的 。可使用螢幕頂端的下拉式清單來變更區域。在本教學課程稍後的階段，您必須在同一區域中建立 Lambda 函數。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/console_region_select.png)

1. 選擇**建立儲存貯體**。

1. 在 **General configuration (一般組態)** 下，執行下列動作：

   1. 在**儲存貯體類型**欄位中，選取**一般用途**。

   1. 在**儲存貯體名稱**欄位中，輸入符合 Amazon S3 [儲存貯體命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)的全域唯一名稱。儲存貯體名稱只能包含小寫字母、數字、句點 (.) 和連字號 (-)。

1. 其他所有選項維持設為預設值，然後選擇**建立儲存貯體**。

## 將測試物件上傳至儲存貯體
<a name="with-s3-example-upload-test-object"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps2.png)


**上傳測試物件**

1. 開啟 Amazon S3 主控台的[儲存貯體](https://console.aws.amazon.com/s3/buckets)頁面，然後選擇您在上一個步驟中建立的儲存貯體。

1. 選擇**上傳**。

1. 選擇**新增檔案**，然後選取要上傳的物件。您可以選取任何檔案 (例如 `HappyFace.jpg`)。

1. 選擇**開啟**，然後選擇**上傳**。

在本教學課程的稍後部分，您將使用此物件測試 Lambda 函數。

## 建立許可政策
<a name="with-s3-example-create-policy"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps3.png)


建立許可政策，以允許 Lambda 從 Amazon S3 儲存貯體取得物件，以及寫入 Amazon CloudWatch Logs。

**建立政策**

1. 開啟 IAM 主控台中的[政策頁面](https://console.aws.amazon.com/iam/home#/policies)。

1. 選擇**建立政策**。

1. 選擇 **JSON** 索引標籤，然後將下列政策貼到 JSON 編輯器。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:PutLogEvents",
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream"
               ],
               "Resource": "arn:aws:logs:*:*:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           }
       ]
   }
   ```

------

1. 選擇下**一步：標籤**。

1. 選擇下**一步：檢閱**。

1. 在**檢閱政策下**，針對政策**名稱**，輸入 **s3-trigger-tutorial**。

1. 選擇**建立政策**。

## 建立執行角色
<a name="with-s3-example-create-role"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps4.png)


[執行角色](lambda-intro-execution-role.md)是授予 Lambda 函數存取 AWS 服務 和資源許可的 AWS Identity and Access Management (IAM) 角色。在此步驟中，使用您在上一個步驟中建立的許可政策來建立執行角色。

**建立執行角色並附加自訂許可政策**

1. 開啟 IAM 主控台中的[角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇 **建立角色**。

1. 信任的實體類型請選擇 **AWS 服務**，使用案例則選擇 **Lambda**。

1. 選擇**下一步**。

1. 在政策搜尋方塊中，輸入 **s3-trigger-tutorial**。

1. 在搜尋結果中，選取您建立的政策 (`s3-trigger-tutorial`)，然後選擇**下一步**。

1. 在**角色詳細資料**底下，**角色名稱**請輸入 **lambda-s3-trigger-role**，然後選擇**建立角色**。

## 建立 Lambda 函式
<a name="with-s3-example-create-function"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps5.png)


使用 Python 3.14 執行時間在主控台中建立 Lambda 函數。

**建立 Lambda 函數**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 請確定您使用 AWS 區域 與建立 Amazon S3 儲存貯體相同的 。您可使用螢幕頂端的下拉式清單來變更區域。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/console_region_select.png)

1. 選擇**建立函數**。

1. 選擇**從頭開始撰寫**

1. 在**基本資訊**下，請執行下列動作：

   1. 在**函數名稱**輸入 `s3-trigger-tutorial`

   1. 針對**執行期**，選擇 **Python 3.14。**

   1. 對於 **Architecture** (架構)，選擇 **x86\$164**。

1. 在**變更預設執行角色**索引標籤中，執行下列操作：

   1. 展開索引標籤，然後選擇**使用現有角色**。

   1. 選擇您之前建立的 `lambda-s3-trigger-role`。

1. 選擇**建立函數**。

## 部署函數程式碼
<a name="with-s3-example-deploy-code"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps6.png)


本教學課程使用 Python 3.14 執行時間，但我們也提供其他執行時間的範例程式碼檔案。您可以在下列方塊中選取索引標籤，查看您感興趣的執行期程式碼。

該 Lambda 函數收到 Amazon S3 傳來的 `event` 參數後，會從該參數擷取上傳物件的金鑰名稱以及儲存貯體的名稱。然後，函數會使用 中的 [get\$1object](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3/client/get_object.html) 方法 適用於 Python (Boto3) 的 AWS SDK 擷取物件的中繼資料，包括上傳物件的內容類型 (MIME 類型）。

**部署函數程式碼**

1. 在以下方塊中選擇 **Python** 索引標籤，然後複製程式碼。

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 來使用 S3 事件。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   ﻿using System.Threading.Tasks;
   using Amazon.Lambda.Core;
   using Amazon.S3;
   using System;
   using Amazon.Lambda.S3Events;
   using System.Web;
   
   // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
   [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
   
   namespace S3Integration
   {
       public class Function
       {
           private static AmazonS3Client _s3Client;
           public Function() : this(null)
           {
           }
   
           internal Function(AmazonS3Client s3Client)
           {
               _s3Client = s3Client ?? new AmazonS3Client();
           }
   
           public async Task<string> Handler(S3Event evt, ILambdaContext context)
           {
               try
               {
                   if (evt.Records.Count <= 0)
                   {
                       context.Logger.LogLine("Empty S3 Event received");
                       return string.Empty;
                   }
   
                   var bucket = evt.Records[0].S3.Bucket.Name;
                   var key = HttpUtility.UrlDecode(evt.Records[0].S3.Object.Key);
   
                   context.Logger.LogLine($"Request is for {bucket} and {key}");
   
                   var objectResult = await _s3Client.GetObjectAsync(bucket, key);
   
                   context.Logger.LogLine($"Returning {objectResult.Key}");
   
                   return objectResult.Key;
               }
               catch (Exception e)
               {
                   context.Logger.LogLine($"Error processing request - {e.Message}");
   
                   return string.Empty;
               }
           }
       }
   }
   ```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 Go 搭配 Lambda 來使用 S3 事件。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   package main
   
   import (
   	"context"
   	"log"
   
   	"github.com/aws/aws-lambda-go/events"
   	"github.com/aws/aws-lambda-go/lambda"
   	"github.com/aws/aws-sdk-go-v2/config"
   	"github.com/aws/aws-sdk-go-v2/service/s3"
   )
   
   func handler(ctx context.Context, s3Event events.S3Event) error {
   	sdkConfig, err := config.LoadDefaultConfig(ctx)
   	if err != nil {
   		log.Printf("failed to load default config: %s", err)
   		return err
   	}
   	s3Client := s3.NewFromConfig(sdkConfig)
   
   	for _, record := range s3Event.Records {
   		bucket := record.S3.Bucket.Name
   		key := record.S3.Object.URLDecodedKey
   		headOutput, err := s3Client.HeadObject(ctx, &s3.HeadObjectInput{
   			Bucket: &bucket,
   			Key:    &key,
   		})
   		if err != nil {
   			log.Printf("error getting head of object %s/%s: %s", bucket, key, err)
   			return err
   		}
   		log.Printf("successfully retrieved %s/%s of type %s", bucket, key, *headOutput.ContentType)
   	}
   
   	return nil
   }
   
   func main() {
   	lambda.Start(handler)
   }
   ```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 Java 搭配 Lambda 來使用 S3 事件。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   package example;
   
   import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
   import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
   import software.amazon.awssdk.services.s3.S3Client;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import com.amazonaws.services.lambda.runtime.events.S3Event;
   import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3EventNotificationRecord;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   public class Handler implements RequestHandler<S3Event, String> {
       private static final Logger logger = LoggerFactory.getLogger(Handler.class);
       @Override
       public String handleRequest(S3Event s3event, Context context) {
           try {
             S3EventNotificationRecord record = s3event.getRecords().get(0);
             String srcBucket = record.getS3().getBucket().getName();
             String srcKey = record.getS3().getObject().getUrlDecodedKey();
   
             S3Client s3Client = S3Client.builder().build();
             HeadObjectResponse headObject = getHeadObject(s3Client, srcBucket, srcKey);
   
             logger.info("Successfully retrieved " + srcBucket + "/" + srcKey + " of type " + headObject.contentType());
   
             return "Ok";
           } catch (Exception e) {
             throw new RuntimeException(e);
           }
       }
   
       private HeadObjectResponse getHeadObject(S3Client s3Client, String bucket, String key) {
           HeadObjectRequest headObjectRequest = HeadObjectRequest.builder()
                   .bucket(bucket)
                   .key(key)
                   .build();
           return s3Client.headObject(headObjectRequest);
       }
   }
   ```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 來使用 S3 事件。  

   ```
   import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
   
   const client = new S3Client();
   
   export const handler = async (event, context) => {
   
       // Get the object from the event and show its content type
       const bucket = event.Records[0].s3.bucket.name;
       const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
   
       try {
           const { ContentType } = await client.send(new HeadObjectCommand({
               Bucket: bucket,
               Key: key,
           }));
   
           console.log('CONTENT TYPE:', ContentType);
           return ContentType;
   
       } catch (err) {
           console.log(err);
           const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
           console.log(message);
           throw new Error(message);
       }
   };
   ```
使用 TypeScript 搭配 Lambda 來使用 S3 事件。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   import { S3Event } from 'aws-lambda';
   import { S3Client, HeadObjectCommand } from '@aws-sdk/client-s3';
   
   const s3 = new S3Client({ region: process.env.AWS_REGION });
   
   export const handler = async (event: S3Event): Promise<string | undefined> => {
     // Get the object from the event and show its content type
     const bucket = event.Records[0].s3.bucket.name;
     const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
     const params = {
       Bucket: bucket,
       Key: key,
     };
     try {
       const { ContentType } = await s3.send(new HeadObjectCommand(params));
       console.log('CONTENT TYPE:', ContentType);
       return ContentType;
     } catch (err) {
       console.log(err);
       const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
       console.log(message);
       throw new Error(message);
     }
   };
   ```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 來使用 S3 事件。  

   ```
   <?php
   
   use Bref\Context\Context;
   use Bref\Event\S3\S3Event;
   use Bref\Event\S3\S3Handler;
   use Bref\Logger\StderrLogger;
   
   require __DIR__ . '/vendor/autoload.php';
   
   
   class Handler extends S3Handler 
   {
       private StderrLogger $logger;
       public function __construct(StderrLogger $logger)
       {
           $this->logger = $logger;
       }
       
       public function handleS3(S3Event $event, Context $context) : void
       {
           $this->logger->info("Processing S3 records");
   
           // Get the object from the event and show its content type
           $records = $event->getRecords();
           
           foreach ($records as $record) 
           {
               $bucket = $record->getBucket()->getName();
               $key = urldecode($record->getObject()->getKey());
   
               try {
                   $fileSize = urldecode($record->getObject()->getSize());
                   echo "File Size: " . $fileSize . "\n";
                   // TODO: Implement your custom processing logic here
               } catch (Exception $e) {
                   echo $e->getMessage() . "\n";
                   echo 'Error getting object ' . $key . ' from bucket ' . $bucket . '. Make sure they exist and your bucket is in the same region as this function.' . "\n";
                   throw $e;
               }
           }
       }
   }
   
   $logger = new StderrLogger();
   return new Handler($logger);
   ```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 Python 搭配 Lambda 來使用 S3 事件。  

   ```
   # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   # SPDX-License-Identifier: Apache-2.0
   import json
   import urllib.parse
   import boto3
   
   print('Loading function')
   
   s3 = boto3.client('s3')
   
   
   def lambda_handler(event, context):
       #print("Received event: " + json.dumps(event, indent=2))
   
       # Get the object from the event and show its content type
       bucket = event['Records'][0]['s3']['bucket']['name']
       key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
       try:
           response = s3.get_object(Bucket=bucket, Key=key)
           print("CONTENT TYPE: " + response['ContentType'])
           return response['ContentType']
       except Exception as e:
           print(e)
           print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
           raise e
   ```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 來使用 S3 事件。  

   ```
   require 'json'
   require 'uri'
   require 'aws-sdk'
   
   puts 'Loading function'
   
   def lambda_handler(event:, context:)
     s3 = Aws::S3::Client.new(region: 'region') # Your AWS region
     # puts "Received event: #{JSON.dump(event)}"
   
     # Get the object from the event and show its content type
     bucket = event['Records'][0]['s3']['bucket']['name']
     key = URI.decode_www_form_component(event['Records'][0]['s3']['object']['key'], Encoding::UTF_8)
     begin
       response = s3.get_object(bucket: bucket, key: key)
       puts "CONTENT TYPE: #{response.content_type}"
       return response.content_type
     rescue StandardError => e
       puts e.message
       puts "Error getting object #{key} from bucket #{bucket}. Make sure they exist and your bucket is in the same region as this function."
       raise e
     end
   end
   ```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 來使用 S3 事件。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   use aws_lambda_events::event::s3::S3Event;
   use aws_sdk_s3::{Client};
   use lambda_runtime::{run, service_fn, Error, LambdaEvent};
   
   
   /// Main function
   #[tokio::main]
   async fn main() -> Result<(), Error> {
       tracing_subscriber::fmt()
           .with_max_level(tracing::Level::INFO)
           .with_target(false)
           .without_time()
           .init();
   
       // Initialize the AWS SDK for Rust
       let config = aws_config::load_from_env().await;
       let s3_client = Client::new(&config);
   
       let res = run(service_fn(|request: LambdaEvent<S3Event>| {
           function_handler(&s3_client, request)
       })).await;
   
       res
   }
   
   async fn function_handler(
       s3_client: &Client,
       evt: LambdaEvent<S3Event>
   ) -> Result<(), Error> {
       tracing::info!(records = ?evt.payload.records.len(), "Received request from SQS");
   
       if evt.payload.records.len() == 0 {
           tracing::info!("Empty S3 event received");
       }
   
       let bucket = evt.payload.records[0].s3.bucket.name.as_ref().expect("Bucket name to exist");
       let key = evt.payload.records[0].s3.object.key.as_ref().expect("Object key to exist");
   
       tracing::info!("Request is for {} and object {}", bucket, key);
   
       let s3_get_object_result = s3_client
           .get_object()
           .bucket(bucket)
           .key(key)
           .send()
           .await;
   
       match s3_get_object_result {
           Ok(_) => tracing::info!("S3 Get Object success, the s3GetObjectResult contains a 'body' property of type ByteStream"),
           Err(_) => tracing::info!("Failure with S3 Get Object request")
       }
   
       Ok(())
   }
   ```

------

1. 在 Lambda 主控台的**程式碼來源**窗格中，將程式碼貼到程式碼編輯器中，取代 Lambda 建立的程式碼。

1. 在 **DEPLOY** 區段中，選擇**部署**以更新函數的程式碼：  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## 建立 Amazon S3 觸發條件
<a name="with-s3-example-create-trigger"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps7.png)


**若要建立 Amazon S3 觸發條件**

1. 在**函數概觀**窗格中，選擇**新增觸發條件**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/overview-trigger.png)

1. 選取 **S3**。

1. 在**儲存貯體**下，選取您在本教學課程中稍早建立的儲存貯體。

1. 在**事件類型**下，選取**所有物件建立事件**。

1. 在**遞迴調用**下，選取核取方塊，確認您了解不建議使用相同的 Amazon S3 儲存貯體進行輸入和輸出作業。

1. 選擇**新增**。

**注意**  
當您使用 Lambda 主控台為 Lambda 函數建立 Amazon S3 觸發條件時，Amazon S3 會在您指定的儲存貯體上設定[事件通知](https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventNotifications.html)。在設定此事件通知之前，Amazon S3 會執行一系列檢查，以確認該事件目的地存在，且具有所需的 IAM 政策。Amazon S3 也會對針對為該儲存貯體設定的任何其他事件通知執行這些測試。  
由於此檢查的存在，如果儲存貯體先前已為不再存在的資源設定事件目的地，或為沒有必要許可政策的資源設定事件目的地，則 Amazon S3 將無法建立新的事件通知。您將看到以下錯誤訊息，指出無法建立觸發條件：  

```
An error occurred when creating the trigger: Unable to validate the following destination configurations.
```
如果您先前已使用相同的儲存貯體為另一個 Lambda 函數設定觸發條件，且在之後刪除了相關函數或修改了其許可政策，則會顯示此錯誤。

## 使用虛擬事件來測試 Lambda 函數
<a name="with-s3-example-test-dummy-event"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps8.png)


**使用虛擬事件來測試 Lambda 函數**

1. 在函數的 Lambda 主控台頁面中，選擇**測試**索引標籤。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/test-tab.png)

1. **事件名稱**輸入 `MyTestEvent`。

1. 在**事件 JSON** 中，貼上以下測試事件。務必取代這些值：
   + 將 `us-east-1` 取代為您用來建立 Amazon S3 儲存貯體的區域。
   + 將 `amzn-s3-demo-bucket` 的兩個執行個體取代為您的 Amazon S3 儲存貯體名稱。
   + 將 `test%2FKey` 取代為您之前上傳到儲存貯體的測試物件名稱 (例如 `HappyFace.jpg`)。

   ```
   {
     "Records": [
       {
         "eventVersion": "2.0",
         "eventSource": "aws:s3",
         "awsRegion": "us-east-1",
         "eventTime": "1970-01-01T00:00:00.000Z",
         "eventName": "ObjectCreated:Put",
         "userIdentity": {
           "principalId": "EXAMPLE"
         },
         "requestParameters": {
           "sourceIPAddress": "127.0.0.1"
         },
         "responseElements": {
           "x-amz-request-id": "EXAMPLE123456789",
           "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
         },
         "s3": {
           "s3SchemaVersion": "1.0",
           "configurationId": "testConfigRule",
           "bucket": {
             "name": "amzn-s3-demo-bucket",
             "ownerIdentity": {
               "principalId": "EXAMPLE"
             },
             "arn": "arn:aws:s3:::amzn-s3-demo-bucket"
           },
           "object": {
             "key": "test%2Fkey",
             "size": 1024,
             "eTag": "0123456789abcdef0123456789abcdef",
             "sequencer": "0A1B2C3D4E5F678901"
           }
         }
       }
     ]
   }
   ```

1. 選擇**儲存**。

1. 選擇**測試**。

1. 如果函數成功運作，您會在**執行結果**索引標籤中看到類似以下內容的輸出。

   ```
   Response
   "image/jpeg"
   
   Function Logs
   START RequestId: 12b3cae7-5f4e-415e-93e6-416b8f8b66e6 Version: $LATEST
   2021-02-18T21:40:59.280Z    12b3cae7-5f4e-415e-93e6-416b8f8b66e6    INFO    INPUT BUCKET AND KEY:  { Bucket: 'amzn-s3-demo-bucket', Key: 'HappyFace.jpg' }
   2021-02-18T21:41:00.215Z    12b3cae7-5f4e-415e-93e6-416b8f8b66e6    INFO    CONTENT TYPE: image/jpeg
   END RequestId: 12b3cae7-5f4e-415e-93e6-416b8f8b66e6
   REPORT RequestId: 12b3cae7-5f4e-415e-93e6-416b8f8b66e6    Duration: 976.25 ms    Billed Duration: 977 ms    Memory Size: 128 MB    Max Memory Used: 90 MB    Init Duration: 430.47 ms        
   
   Request ID
   12b3cae7-5f4e-415e-93e6-416b8f8b66e6
   ```

### 使用 Amazon S3 觸發條件測試 Lambda 函數
<a name="with-s3-example-test-s3-trigger"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps9.png)


若要使用已設定的觸發條件來測試函數，需使用主控台將物件上傳至 Amazon S3 儲存貯體。若要確認 Lambda 函數如預期執行，請使用 CloudWatch Logs 來檢視函數的輸出。

**將物件上傳至 Amazon S3 儲存貯體**

1. 開啟 Amazon S3 主控台的[儲存貯體](https://console.aws.amazon.com/s3/buckets)頁面，然後選擇您稍早建立的儲存貯體。

1. 選擇**上傳**。

1. 選擇**新增檔案**，然後使用檔案選擇器選擇您要上傳的物件。此物件可以是您自選的任何檔案。

1. 選擇**開啟**，然後選擇**上傳**。

**若要使用 CloudWatch Logs 驗證函數調用**

1. 開啟 [CloudWatch 主控台](https://console.aws.amazon.com/cloudwatch/home)。

1. 請確定您在 AWS 區域 建立 Lambda 函數的相同 中工作。您可使用螢幕頂端的下拉式清單來變更區域。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/console_region_select.png)

1. 選擇**日誌**，然後選擇**日誌群組**。

1. 為函數 (`/aws/lambda/s3-trigger-tutorial`) 選擇日誌群組名稱。

1. 在**日誌串流**下，選擇最新的日誌串流。

1. 如果系統已正確調用函數以回應 Amazon S3 觸發條件，您會看到類似以下內容的輸出。您看到的 `CONTENT TYPE` 取決於您上傳到儲存貯體的檔案類型。

   ```
   2022-05-09T23:17:28.702Z	0cae7f5a-b0af-4c73-8563-a3430333cc10	INFO	CONTENT TYPE: image/jpeg
   ```

## 清除您的資源
<a name="cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇**刪除**。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇**刪除**。

**刪除 S3 儲存貯體**

1. 開啟 [Amazon S3 主控台](https://console.aws.amazon.com//s3/home#)。

1. 選擇您建立的儲存貯體。

1. 選擇 **刪除** 。

1. 在文字輸入欄位中輸入儲存貯體的名稱。

1. 選擇**刪除儲存貯體**。

## 後續步驟
<a name="next-steps"></a>

在 [教學課程：使用 Amazon S3 觸發條件建立縮圖影像](with-s3-tutorial.md) 中，Amazon S3 觸發條件會調用函數，為上傳至 S3 儲存貯體的每個影像檔建立縮圖影像。本教學課程需要中等程度的 AWS 和 Lambda 網域知識。它示範如何使用 AWS Command Line Interface (AWS CLI) 建立資源，以及如何為函數及其相依性建立 .zip 檔案封存部署套件。

# 教學課程：使用 Amazon S3 觸發條件建立縮圖影像
<a name="with-s3-tutorial"></a>

在本教學課程中，您將建立和設定 Lambda 函數，它會調整新增至 Amazon Simple Storage Service (Amazon S3) 儲存貯體的映像。當您將映像檔案新增至儲存貯體時，Amazon S3 會調用 Lambda 函數。然後，函數會建立映像的縮圖版本，並將其輸出到不同 Amazon S3 儲存貯體。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_resources.png)


請執行下列步驟以完成本教學課程：

1. 建立來源和目的地 Amazon S3 儲存貯體，並上傳範例映像。

1. 建立可調整映像大小並將縮圖輸出到 Amazon S3 儲存貯體的 Lambda 函數。

1. 設定一個 Lambda 觸發條件，在物件上傳至來源儲存貯體時調用函數。

1. 首先使用虛擬事件測試函數，然後透過將映像上傳到來源儲存貯體來測試函數。

完成這些步驟後，將了解如何使用 Lambda 在新增至 Amazon S3 儲存貯體的物件上執行檔案處理任務。您可以使用 AWS Command Line Interface (AWS CLI) 或 來完成本教學課程 AWS 管理主控台。

如果您正在尋找更簡單的範例來學習如何為 Lambda 設定 Amazon S3 觸發條件，則可以嘗試[教學課程：使用 Amazon S3 觸發條件調用 Lambda 函數](https://docs.aws.amazon.com/lambda/latest/dg/with-s3-example.html)。

**Topics**
+ [

## 先決條件
](#with-s3-example-prereqs)
+ [

## 建立兩個 Amazon S3 儲存貯體
](#with-s3-tutorial-prepare-create-buckets)
+ [

## 將測試映像上傳到來源儲存貯體
](#with-s3-tutorial-test-image)
+ [

## 建立許可政策
](#with-s3-tutorial-create-policy)
+ [

## 建立執行角色
](#with-s3-tutorial-create-execution-role)
+ [

## 建立函數部署套件
](#with-s3-tutorial-create-function-package)
+ [

## 建立 Lambda 函式
](#with-s3-tutorial-create-function-createfunction)
+ [

## 設定 Amazon S3 以調用函數
](#with-s3-tutorial-configure-s3-trigger)
+ [

## 使用虛擬事件來測試 Lambda 函數
](#with-s3-tutorial-dummy-test)
+ [

## 使用 Amazon S3 觸發條件測試函數
](#with-s3-tutorial-test-s3)
+ [

## 清除您的資源
](#s3-tutorial-cleanup)

## 先決條件
<a name="with-s3-example-prereqs"></a>

如果您想要使用 AWS CLI 來完成教學課程，請安裝[最新版本的 AWS Command Line Interface]()。

對於 Lambda 函數程式碼，您可以使用 Python 或 Node.js。為您想要使用的語言安裝語言支援工具和套件管理工具。

### 安裝 AWS Command Line Interface
<a name="install_aws_cli"></a>

如果您尚未安裝 AWS Command Line Interface，請依照[安裝或更新最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)中的步驟進行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中，使用您偏好的 Shell 和套件管理工具。

**注意**  
在 Windows 中，作業系統的內建終端不支援您常與 Lambda 搭配使用的某些 Bash CLI 命令 (例如 `zip`)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本，請[安裝適用於 Linux 的 Windows 子系統](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。

## 建立兩個 Amazon S3 儲存貯體
<a name="with-s3-tutorial-prepare-create-buckets"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps1.png)


首先建立兩個 Amazon S3 儲存貯體。第一個儲存貯體是將接收映像上傳的來源儲存貯體。當您調用函數時，Lambda 會使用第二個儲存貯體來儲存已調整大小的縮圖。

------
#### [ AWS 管理主控台 ]

**建立 Amazon S3 儲存貯體 (主控台)**

1. 開啟 [Amazon S3 主控台](https://console.aws.amazon.com/s3)，然後選取**一般用途儲存貯體**頁面。

1. 選取最 AWS 區域 接近您地理位置的 。可使用螢幕頂端的下拉式清單來變更區域。在本教學課程稍後的階段，您必須在同一區域中建立 Lambda 函數。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/console_region_select.png)

1. 選擇**建立儲存貯體**。

1. 在 **General configuration (一般組態)** 下，執行下列動作：

   1. 在**儲存貯體類型**欄位中，選取**一般用途**。

   1. 在**儲存貯體名稱**欄位中，輸入符合 Amazon S3 [儲存貯體命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)的全域唯一名稱。儲存貯體名稱只能包含小寫字母、數字、句點 (.) 和連字號 (-)。

1. 其他所有選項維持設為預設值，然後選擇**建立儲存貯體**。

1. 重複步驟 1 到 5 來建立目的地儲存貯體。對於**儲存貯體名稱**，輸入 `amzn-s3-demo-source-bucket-resized`，其中 `amzn-s3-demo-source-bucket` 是您剛才建立的來源儲存貯體名稱。

------
#### [ AWS CLI ]

**建立 Amazon S3 儲存貯體 (AWS CLI)**

1. 執行下列 CLI 命令以建立來源儲存貯體。您為儲存貯體選擇的名稱必須是全域唯一的，並遵循 Amazon S3 [儲存貯體命名規則](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)。名稱只能包含小寫字母、數字、句點 (.) 和連字號 (-)。對於 `region` 和 `LocationConstraint`，請選擇最接近您地理位置的 [AWS 區域](https://docs.aws.amazon.com/general/latest/gr/lambda-service.html)。

   ```
   aws s3api create-bucket --bucket amzn-s3-demo-source-bucket --region us-east-1 \
   --create-bucket-configuration LocationConstraint=us-east-1
   ```

   稍後在教學課程中，您必須在與來源儲存貯體 AWS 區域 相同的 中建立 Lambda 函數，因此請記下您選擇的區域。

1. 執行下列命令以建立目的地儲存貯體。對於儲存貯體名稱，必須使用 `amzn-s3-demo-source-bucket-resized`，其中 `amzn-s3-demo-source-bucket` 是您在步驟 1 中建立的來源儲存貯體名稱。針對 `region`和 `LocationConstraint`，選擇 AWS 區域 您用來建立來源儲存貯體的相同 。

   ```
   aws s3api create-bucket --bucket amzn-s3-demo-source-bucket-resized --region us-east-1 \
   --create-bucket-configuration LocationConstraint=us-east-1
   ```

------

## 將測試映像上傳到來源儲存貯體
<a name="with-s3-tutorial-test-image"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps2.png)


稍後在教學課程中，您將使用 AWS CLI 或 Lambda 主控台叫用 Lambda 函數來測試 Lambda 函數。若要確認函数運作正常，來源儲存貯體需要包含測試映像。此映像可以是您選擇的任何 JPG 或 PNG 檔案。

------
#### [ AWS 管理主控台 ]

**將測試映像上傳到來源儲存貯體 (主控台)**

1. 開啟 Amazon S3 主控台的[儲存貯體](https://console.aws.amazon.com/s3/buckets)頁面。

1. 選取您在上一個步驟所建立的來源儲存貯體。

1. 選擇**上傳**。

1. 選擇**新增檔案**，然後使用檔案選擇器選擇您要上傳的物件。

1. 選擇**開啟**，然後選擇**上傳**。

------
#### [ AWS CLI ]

**將測試映像上傳到來源儲存貯體 (AWS CLI)**
+ 從包含要上傳之映像的目錄中，執行下列 CLI 命令。將 `--bucket` 參數取代為來源儲存貯體名稱。對於 `--key` 和 `--body` 參數，請使用測試映像的檔案名稱。

  ```
  aws s3api put-object --bucket amzn-s3-demo-source-bucket --key HappyFace.jpg --body ./HappyFace.jpg
  ```

------

## 建立許可政策
<a name="with-s3-tutorial-create-policy"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps3.png)


建立 Lambda 函數的第一個步驟是建立許可政策。此政策為您的函數提供存取其他 AWS 資源所需的許可。在本教學課程中，該政策為 Lambda 提供了 Amazon S3 儲存貯體的讀取和寫入許可，並允許其寫入到 Amazon CloudWatch Logs 日誌。

------
#### [ AWS 管理主控台 ]

**建立政策 (主控台)**

1. 開啟 AWS Identity and Access Management (IAM) 主控台[的政策](https://console.aws.amazon.com/iamv2/home#policies)頁面。

1. 選擇**建立政策**。

1. 選擇 **JSON** 索引標籤，然後將下列政策貼到 JSON 編輯器。  
****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:PutLogEvents",
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream"
               ],
               "Resource": "arn:aws:logs:*:*:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:PutObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           }
       ]
   }
   ```

1. 選擇**下一步**。

1. 在**政策詳細資訊**下，針對政策**政策名稱** ，輸入 `LambdaS3Policy`。

1. 選擇**建立政策**。

------
#### [ AWS CLI ]

**建立政策 (AWS CLI)**

1. 將下面的 JSON 儲存在名為 `policy.json` 的檔案中。  
****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:PutLogEvents",
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream"
               ],
               "Resource": "arn:aws:logs:*:*:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:PutObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           }
       ]
   }
   ```

1. 在儲存 JSON 政策文件的目錄中執行下列 CLI 命令。

   ```
   aws iam create-policy --policy-name LambdaS3Policy --policy-document file://policy.json
   ```

------

## 建立執行角色
<a name="with-s3-tutorial-create-execution-role"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps4.png)


執行角色是授予 Lambda 函數存取 AWS 服務 和資源許可的 IAM 角色。若要為函數提供 Amazon S3 儲存貯體的讀取和寫入存取權，請連接您在上個步驟建立的許可政策。

------
#### [ AWS 管理主控台 ]

**建立執行角色並連接許可政策 (主控台)**

1. 開啟 (IAM) 主控台的[角色](https://console.aws.amazon.com/iamv2/home#roles)頁面。

1. 選擇建**立角色**。

1. 對於**可信實體類型**，選取 **AWS 服務**，然後針對**使用案例**選取 **Lambda**。

1. 選擇**下一步**。

1. 執行下列動作，新增您在上個步驟中建立的許可政策：

   1. 在政策搜尋方塊中，輸入 `LambdaS3Policy`。

   1. 在搜尋結果中，選取 `LambdaS3Policy` 的核取方塊。

   1. 選擇**下一步**。

1. 在**角色詳細資訊**下，針對**角色名稱**，輸入 `LambdaS3Role`。

1. 選擇建**立角色**。

------
#### [ AWS CLI ]

**建立執行角色並連接許可政策 (AWS CLI)**

1. 將下面的 JSON 儲存在名為 `trust-policy.json` 的檔案中。此信任政策允許 Lambda 透過授予服務主體呼叫 AWS Security Token Service (AWS STS) `AssumeRole`動作的許可來使用角色的`lambda.amazonaws.com`許可。  
****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "lambda.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

1. 在儲存 JSON 信任政策文件的目錄中，執行下列 CLI 命令，建立執行角色。

   ```
   aws iam create-role --role-name LambdaS3Role --assume-role-policy-document file://trust-policy.json
   ```

1. 執行下列 CLI 命令，連接您在上個步驟中建立的許可政策。將政策 ARN 中的 AWS 帳戶 號碼取代為您自己的帳戶號碼。

   ```
   aws iam attach-role-policy --role-name LambdaS3Role --policy-arn arn:aws:iam::123456789012:policy/LambdaS3Policy
   ```

------

## 建立函數部署套件
<a name="with-s3-tutorial-create-function-package"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps5.png)


要建立函數，需建立包含函數程式碼和其相依項的*部署套件*。對於此 `CreateThumbnail` 函數，函數程式碼使用單獨的程式庫來調整映像大小。依照所選語言的指示，建立包含所需程式庫的部署套件。

------
#### [ Node.js ]

**建立部署套件 (Node.js)**

1. 為函數程式碼和相依項建立名為 `lambda-s3` 的目錄並導覽到該目錄。

   ```
   mkdir lambda-s3
   cd lambda-s3
   ```

1. 使用 `npm` 建立新 Node.js 專案。若要接受互動體驗中提供的預設選項，請按下 `Enter`。

   ```
   npm init
   ```

1. 將以下函數程式碼儲存在名為 `index.mjs` 檔案中。請務必以您建立來源和目的地儲存貯體的 AWS 區域 取代 `us-east-1`。

   ```
   // dependencies
   import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
   
   import { Readable } from 'stream';
   
   import sharp from 'sharp';
   import util from 'util';
   
   
   // create S3 client
   const s3 = new S3Client({region: 'us-east-1'});
   
   // define the handler function
   export const handler = async (event, context) => {
   
   // Read options from the event parameter and get the source bucket
   console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
     const srcBucket = event.Records[0].s3.bucket.name;
     
   // Object key may have spaces or unicode non-ASCII characters
   const srcKey    = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
   const dstBucket = srcBucket + "-resized";
   const dstKey    = "resized-" + srcKey;
   
   // Infer the image type from the file suffix
   const typeMatch = srcKey.match(/\.([^.]*)$/);
   if (!typeMatch) {
     console.log("Could not determine the image type.");
     return;
   }
   
   // Check that the image type is supported
   const imageType = typeMatch[1].toLowerCase();
   if (imageType != "jpg" && imageType != "png") {
     console.log(`Unsupported image type: ${imageType}`);
     return;
   }
   
   // Get the image from the source bucket. GetObjectCommand returns a stream.
   try {
     const params = {
       Bucket: srcBucket,
       Key: srcKey
     };
     var response = await s3.send(new GetObjectCommand(params));
     var stream = response.Body;
     
   // Convert stream to buffer to pass to sharp resize function.
     if (stream instanceof Readable) {
       var content_buffer = Buffer.concat(await stream.toArray());
       
     } else {
       throw new Error('Unknown object stream type');
     }
   
   
   } catch (error) {
     console.log(error);
     return;
   }
   
     
   // set thumbnail width. Resize will set the height automatically to maintain aspect ratio.
   const width  = 200;
   
   // Use the sharp module to resize the image and save in a buffer.
   try {    
     var output_buffer = await sharp(content_buffer).resize(width).toBuffer();
   
   } catch (error) {
     console.log(error);
     return;
   }
   
   // Upload the thumbnail image to the destination bucket
   try {
     const destparams = {
       Bucket: dstBucket,
       Key: dstKey,
       Body: output_buffer,
       ContentType: "image"
     };
   
     const putResult = await s3.send(new PutObjectCommand(destparams));
   
     } catch (error) {
       console.log(error);
       return;
     }
   
     console.log('Successfully resized ' + srcBucket + '/' + srcKey +
       ' and uploaded to ' + dstBucket + '/' + dstKey);
     };
   ```

1. 在 `lambda-s3` 目錄中，使用 npm 安裝 Sharp 程式庫。請注意，最新的 Sharp 版本 (0.33) 與 Lambda 不相容。安裝版本 0.32.6 以完成本教學課程。

   ```
   npm install sharp@0.32.6
   ```

   npm `install` 命令為您的模組建立一個 `node_modules` 目錄。在此步驟之後，目錄結構應如下所示。

   ```
   lambda-s3
   |- index.mjs
   |- node_modules
   |  |- base64js
   |  |- bl
   |  |- buffer
   ...
   |- package-lock.json
   |- package.json
   ```

1. 建立包含函數程式碼及其相依項 .zip 部署套件。在 MacOS 或 Linux 中，執行下列命令。

   ```
   zip -r function.zip .
   ```

   在 Windows 中，使用您偏好的 zip 公用程式建立 .zip 檔案。請確保 `index.mjs`、`package.json` 和 `package-lock.json` 檔案以及 `node_modules` 目錄全部都位於 .zip 檔案的根目錄。

------
#### [ Python ]

**建立部署套件 (Python)**

1. 將程式碼範例儲存為名為 `lambda_function.py` 的檔案。

   ```
   import boto3
   import os
   import sys
   import uuid
   from urllib.parse import unquote_plus
   from PIL import Image
   import PIL.Image
               
   s3_client = boto3.client('s3')
               
   def resize_image(image_path, resized_path):
     with Image.open(image_path) as image:
       image.thumbnail(tuple(x / 2 for x in image.size))
       image.save(resized_path)
               
   def lambda_handler(event, context):
     for record in event['Records']:
       bucket = record['s3']['bucket']['name']
       key = unquote_plus(record['s3']['object']['key'])
       tmpkey = key.replace('/', '')
       download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)
       upload_path = '/tmp/resized-{}'.format(tmpkey)
       s3_client.download_file(bucket, key, download_path)
       resize_image(download_path, upload_path)
       s3_client.upload_file(upload_path, '{}-resized'.format(bucket), 'resized-{}'.format(key))
   ```

1. 在建立 `lambda_function.py` 檔案的同一個目錄中，建立名為 `package` 的新目錄並安裝 [Pillow (PIL)](https://pypi.org/project/Pillow/) 程式庫和 適用於 Python (Boto3) 的 AWS SDK。雖然 Lambda Python 執行期包含 Boto3 SDK 的版本，但建議您將函數的所有相依項新增至部署套件，即使其包含在執行期中。如需詳細資訊，請參閱 [Python 中的執行期相依項](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-dependencies)。

   ```
   mkdir package
   pip install \
   --platform manylinux2014_x86_64 \
   --target=package \
   --implementation cp \
   --python-version 3.12 \
   --only-binary=:all: --upgrade \
   pillow boto3
   ```

   Pillow 程式庫中包含 C/C \$1\$1 程式碼。使用 `--platform manylinux_2014_x86_64` 和 `--only-binary=:all:` 選項，pip 便會下載並安裝適用的 Pillow 版本，其中包含與 Amazon Linux 2 作業系統相容的預先編譯二進位檔。這可確保無論本機建置機器的作業系統和架構為何，您的部署套件都能在 Lambda 執行環境中運作。

1. 建立一個包含應用程式碼以及 Pillow 和 Boto3 程式庫的 .zip 檔案。在 Linux 或 MacOS 中，使用命令列界面執行下列命令。

   ```
   cd package
   zip -r ../lambda_function.zip .
   cd ..
   zip lambda_function.zip lambda_function.py
   ```

    在 Windows 中，使用您偏好的 zip 工具建立 `lambda_function.zip` 檔案。確保包含相依項的 `lambda_function.py` 檔案和資料夾全部都在 .zip 檔案的根目錄中。

您也可以使用 Python 虛擬環境建立部署套件。請參閱 [使用 .zip 封存檔部署 Python Lambda 函數](python-package.md)

------

## 建立 Lambda 函式
<a name="with-s3-tutorial-create-function-createfunction"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps6.png)


您可以使用 AWS CLI 或 Lambda 主控台建立 Lambda 函數。依照所選語言的指示建立函數。

------
#### [ AWS 管理主控台 ]

**建立函數的方式 (主控台)**

要使用主控台建立 Lambda 函數，首先建立包含一些 ‘Hello world’ 程式碼的基本函數。然後，透過上傳您在上一個步驟中建立的 .zip 或 JAR 檔案，將此程式碼取代為您自己的函數程式碼。

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 請確定您使用 AWS 區域 與建立 Amazon S3 儲存貯體相同的 。可使用螢幕頂端的下拉式清單來變更區域。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/console_region_select.png)

1. 選擇 **Create function (建立函數)**。

1. 選擇 **Author from scratch** (從頭開始撰寫)。

1. 在**基本資訊**下，請執行下列動作：

   1. 針對**函數名稱**，請輸入 `CreateThumbnail`。

   1. 對於**執行時期**，請根據您為函數選擇的語言，選擇 **Node.js 22.x** 或 **Python 3.12**。

   1. 對於 **Architecture** (架構)，選擇 **x86\$164**。

1. 在**變更預設執行角色**索引標籤中，執行下列操作：

   1. 展開索引標籤，然後選擇**使用現有角色**。

   1. 選擇您之前建立的 `LambdaS3Role`。

1. 選擇**建立函數**。

**上傳函數程式碼 (主控台)**

1. 在**程式碼來源**窗格中選擇**上傳來源**。

1. 選擇 **.zip 檔案**。

1. 選擇**上傳**。

1. 在檔案選擇器中，選取 .zip 檔案，並選擇**開啟**。

1. 選擇**儲存**。

------
#### [ AWS CLI ]

**建立函數 (AWS CLI)**
+ 執行所選語言的 CLI 命令。針對 `role` 參數，請務必將 取代`123456789012`為您自己的 AWS 帳戶 ID。對於 `region` 參數，將 `us-east-1` 取代為您建立 Amazon S3 儲存貯體所在的區域。
  + 對於 **Node.js**，請從包含 `function.zip` 檔案的目錄中執行下列命令。

    ```
    aws lambda create-function --function-name CreateThumbnail \
    --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
    --timeout 10 --memory-size 1024 \
    --role arn:aws:iam::123456789012:role/LambdaS3Role --region us-east-1
    ```
  + 對於 **Python**，請從包含 `lambda_function.zip` 檔案的目錄中執行下列命令。

    ```
    aws lambda create-function --function-name CreateThumbnail \
    --zip-file fileb://lambda_function.zip --handler lambda_function.lambda_handler \
    --runtime python3.14 --timeout 10 --memory-size 1024 \
    --role arn:aws:iam::123456789012:role/LambdaS3Role --region us-east-1
    ```

------

## 設定 Amazon S3 以調用函數
<a name="with-s3-tutorial-configure-s3-trigger"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps7.png)


若要在將映像上傳至來源儲存貯體時執行 Lambda 函數，您需要設定函數的觸發條件。可以使用主控台或 AWS CLI來設定 Amazon S3 觸發條件。

**重要**  
此程序會將 Amazon S3 儲存貯體設定為每次在儲存貯體中建立物件時即會調用您的函數。請務必僅在來源儲存貯體上進行設定。如果 Lambda 函數在進行調用的同一個儲存貯體中建立物件，則可以[在一個迴圈中連續調用](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/recursive-runaway)函數。這可能會導致未預期的費用向您的 收費 AWS 帳戶。

------
#### [ AWS 管理主控台 ]

**設定 Amazon S3 觸發條件 (主控台)**

1. 開啟 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)，然後選擇您的函數 (`CreateThumbnail`)。

1. 選擇 **Add trigger (新增觸發條件)**。

1. 選取 **S3**。

1. 在**儲存貯體**下，選取您的來源儲存貯體。

1. 在**事件類型**下，選取**所有物件建立事件**。

1. 在**遞迴調用**下，選取核取方塊，確認您了解不建議使用相同的 Amazon S3 儲存貯體進行輸入和輸出作業。您可以閱讀無伺服器園地中 [導致 Lambda 函數失控的遞迴模式](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/recursive-runaway)，進一步了解 Lambda 中的遞迴調用模式。

1. 選擇**新增**。

   當您使用 Lambda 主控台建立觸發條件時，Lambda 會自動建立[資源型政策](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html)，為您選取的服務授予調用函數的許可。

------
#### [ AWS CLI ]

**設定 Amazon S3 觸發條件 (AWS CLI)**

1. 若要讓 Amazon S3 來源儲存貯體在新增映像檔案時調用函數，您首先需要使用[資源型政策](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html)為函數設定許可。資源型政策陳述式提供叫用 函數的其他 AWS 服務 許可。若要授予 Amazon S3 調用函數的許可，請執行下列 CLI 命令。請務必以您自己的 AWS 帳戶 ID 取代 `source-account` 參數，並使用您自己的來源儲存貯體名稱。

   ```
   aws lambda add-permission --function-name CreateThumbnail \
   --principal s3.amazonaws.com --statement-id s3invoke --action "lambda:InvokeFunction" \
   --source-arn arn:aws:s3:::amzn-s3-demo-source-bucket \
   --source-account 123456789012
   ```

   使用此命令定義的政策允許 Amazon S3 僅在來源儲存貯體上發生動作時調用函數。
**注意**  
雖然 Amazon S3 儲存貯體名稱全域唯一，但是在使用資源型政策時，最佳實務是指定儲存貯體必須屬於您的帳戶。這是因為如果您刪除儲存貯體，另一個 可以使用相同的 Amazon Resource Name (ARN) AWS 帳戶 建立儲存貯體。

1. 將下面的 JSON 儲存在名為 `notification.json` 的檔案中。套用至來源儲存貯體時，此 JSON 會設定儲存貯體，以便在每次新增新物件時傳送通知至 Lambda 函數。將 AWS 帳戶 Lambda 函數 ARN AWS 區域 中的數字 和 取代為您自己的帳號和區域。

   ```
   {
   "LambdaFunctionConfigurations": [
       {
         "Id": "CreateThumbnailEventConfiguration",
         "LambdaFunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:CreateThumbnail",
         "Events": [ "s3:ObjectCreated:Put" ]
       }
     ]
   }
   ```

1. 執行下列 CLI 命令，將您建立的 JSON 檔案中的通知設定套用至來源儲存貯體。用您自己的來源儲存貯體名稱取代 `amzn-s3-demo-source-bucket`。

   ```
   aws s3api put-bucket-notification-configuration --bucket amzn-s3-demo-source-bucket \
   --notification-configuration file://notification.json
   ```

   若要深入了解 `put-bucket-notification-configuration` 命令和 `notification-configuration` 選項，請參閱 *AWS CLI 命令參考*中的 [put-bucket-notification-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-bucket-notification-configuration.html)。

------

## 使用虛擬事件來測試 Lambda 函數
<a name="with-s3-tutorial-dummy-test"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps8.png)


在將映像檔案新增至 Amazon S3 來源儲存貯體以測試整個設定之前，可以透過使用虛擬事件調用 Lambda 函數來測試其是否正常運作。Lambda 中的事件是一種 JSON 格式的文件，它包含供函數處理的資料。Amazon S3 調用函數時，傳送至函數的事件會包含諸如儲存貯體名稱、儲存貯體 ARN 和物件金鑰等資訊。

------
#### [ AWS 管理主控台 ]

**使用虛擬事件來測試 Lambda 函數 (主控台)**

1. 開啟 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)，然後選擇您的函數 (`CreateThumbnail`)。

1. 選擇**測試**標籤。

1. 若要建立測試事件，請在**測試事件**窗格中執行下列動作：

   1. 在**測試事件動作**下方，選取**建立新事件**。

   1. **事件名稱**輸入 **myTestEvent**。

   1. 對於**範本**，選取 **S3 Put**。

   1. 將下列參數的值取代為您自己的值。
      + 對於 `awsRegion`，`us-east-1`將 取代 AWS 區域 為您在其中建立 Amazon S3 儲存貯體的 。
      + 對於 `name`，將 `amzn-s3-demo-bucket` 取代為 Amazon S3 來源儲存貯體的名稱。
      + 對於 `key`，將 `test%2Fkey` 取代為您在步驟 [將測試映像上傳到來源儲存貯體](#with-s3-tutorial-test-image) 中上傳至來源儲存貯體之測試物件的檔案名稱。

      ```
      {
        "Records": [
          {
            "eventVersion": "2.0",
            "eventSource": "aws:s3",
            "awsRegion": "us-east-1",
            "eventTime": "1970-01-01T00:00:00.000Z",
            "eventName": "ObjectCreated:Put",
            "userIdentity": {
              "principalId": "EXAMPLE"
            },
            "requestParameters": {
              "sourceIPAddress": "127.0.0.1"
            },
            "responseElements": {
              "x-amz-request-id": "EXAMPLE123456789",
              "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
            },
            "s3": {
              "s3SchemaVersion": "1.0",
              "configurationId": "testConfigRule",
              "bucket": {
                "name": "amzn-s3-demo-bucket",
                "ownerIdentity": {
                  "principalId": "EXAMPLE"
                },
                "arn": "arn:aws:s3:::amzn-s3-demo-bucket"
              },
              "object": {
                "key": "test%2Fkey",
                "size": 1024,
                "eTag": "0123456789abcdef0123456789abcdef",
                "sequencer": "0A1B2C3D4E5F678901"
              }
            }
          }
        ]
      }
      ```

   1. 選擇**儲存**。

1. 在**測試事件**窗格中，選擇**測試**。

1. 若要檢查您的函數已建立大小經過調整的映像版本並將其存放在目標 Amazon S3 儲存貯體中，請執行以下操作：

   1. 開啟 Amazon S3 主控台的[儲存貯體](https://console.aws.amazon.com/s3/buckets)頁面。

   1. 選擇目標儲存貯體，並確認在**物件**窗格中列出已調整大小的檔案。

------
#### [ AWS CLI ]

**使用虛擬事件來測試 Lambda 函數 (AWS CLI)**

1. 將下面的 JSON 儲存在名為 `dummyS3Event.json` 的檔案中。將下列參數的值取代為您自己的值：
   + 對於 `awsRegion`，`us-east-1`將 取代 AWS 區域 為您在其中建立 Amazon S3 儲存貯體的 。
   + 對於 `name`，將 `amzn-s3-demo-bucket` 取代為 Amazon S3 來源儲存貯體的名稱。
   + 對於 `key`，將 `test%2Fkey` 取代為您在步驟 [將測試映像上傳到來源儲存貯體](#with-s3-tutorial-test-image) 中上傳至來源儲存貯體之測試物件的檔案名稱。

   ```
   {
     "Records": [
       {
         "eventVersion": "2.0",
         "eventSource": "aws:s3",
         "awsRegion": "us-east-1",
         "eventTime": "1970-01-01T00:00:00.000Z",
         "eventName": "ObjectCreated:Put",
         "userIdentity": {
           "principalId": "EXAMPLE"
         },
         "requestParameters": {
           "sourceIPAddress": "127.0.0.1"
         },
         "responseElements": {
           "x-amz-request-id": "EXAMPLE123456789",
           "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
         },
         "s3": {
           "s3SchemaVersion": "1.0",
           "configurationId": "testConfigRule",
           "bucket": {
             "name": "amzn-s3-demo-bucket",
             "ownerIdentity": {
               "principalId": "EXAMPLE"
             },
             "arn": "arn:aws:s3:::amzn-s3-demo-bucket"
           },
           "object": {
             "key": "test%2Fkey",
             "size": 1024,
             "eTag": "0123456789abcdef0123456789abcdef",
             "sequencer": "0A1B2C3D4E5F678901"
           }
         }
       }
     ]
   }
   ```

1. 在您儲存 `dummyS3Event.json` 檔案的目錄中，透過執行下列 CLI 命令來調用函數。此命令透過將 `RequestResponse` 指定為調用類型參數的值來同步調用 Lambda 函數。若要進一步了解同步和非同步調用，請參閱[調用 Lambda 函數](https://docs.aws.amazon.com/lambda/latest/dg/lambda-invocation.html)。

   ```
   aws lambda invoke --function-name CreateThumbnail \
   --invocation-type RequestResponse --cli-binary-format raw-in-base64-out \
   --payload file://dummyS3Event.json outputfile.txt
   ```

   如果使用的是 AWS CLI 版本 2，則需要 cli-binary-format 選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。如需詳細資訊，請參閱《[支援AWS CLI 的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)》。

1. 確認函數已建立映像的縮圖版本，並將其儲存到目標 Amazon S3 儲存貯體。執行以下 CLI 命令，將 `amzn-s3-demo-source-bucket-resized` 取代為您自己的目的地儲存貯體的名稱。

   ```
   aws s3api list-objects-v2 --bucket amzn-s3-demo-source-bucket-resized
   ```

   您應該會看到類似下列的輸出。`Key` 參數會顯示調整大小後的映像檔案名稱。

   ```
   {
       "Contents": [
           {
               "Key": "resized-HappyFace.jpg",
               "LastModified": "2023-06-06T21:40:07+00:00",
               "ETag": "\"d8ca652ffe83ba6b721ffc20d9d7174a\"",
               "Size": 2633,
               "StorageClass": "STANDARD"
           }
       ]
   }
   ```

------

## 使用 Amazon S3 觸發條件測試函數
<a name="with-s3-tutorial-test-s3"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps9.png)


既然您已確認 Lambda 函數運作正常，便可將映像檔案新增至 Amazon S3 來源儲存貯體來測試完整的設定。將映像新增至來源儲存貯體時，應該會自動調用 Lambda 函數。函數會建立已調整大小的檔案版本，並將其存放在目標儲存貯體中。

------
#### [ AWS 管理主控台 ]

**使用 Amazon S3 觸發條件測試 Lambda 函數 (主控台)**

1. 若要將映像上傳到 Amazon S3 儲存貯體，請執行以下操作：

   1. 開啟 Amazon S3 主控台的[儲存貯體](https://console.aws.amazon.com/s3/buckets)頁面，並選擇來源儲存貯體。

   1. 選擇**上傳**。

   1. 選擇**新增檔案**，然後使用檔案選擇器選擇您要上傳的映像檔案。映像物件可以是任何 .jpg 或 .png 檔案。

   1. 選擇**開啟**，然後選擇**上傳**。

1. 透過執行下列操作，確認 Lambda 已在目標儲存貯體中儲存了調整大小後的映像檔案版本：

   1. 導覽回 Amazon S3 主控台的[儲存貯體](https://console.aws.amazon.com/s3/buckets)頁面，然後選擇目的地儲存貯體。

   1. 在**物件**窗格中，現在應該會看到兩個已調整大小的映像檔案，分別來自 Lambda 函數的每個測試。若要下載已調整大小的映像，請選取檔案，然後選擇**下載**。

------
#### [ AWS CLI ]

**使用 Amazon S3 觸發條件測試 Lambda 函數 (AWS CLI)**

1. 從包含要上傳之映像的目錄中，執行下列 CLI 命令。將 `--bucket` 參數取代為來源儲存貯體名稱。對於 `--key` 和 `--body` 參數，請使用測試映像的檔案名稱。測試映像可以是任何 .jpg 或 .png 檔案。

   ```
   aws s3api put-object --bucket amzn-s3-demo-source-bucket --key SmileyFace.jpg --body ./SmileyFace.jpg
   ```

1. 確認函數已建立映像的縮圖版本，並將其儲存到目標 Amazon S3 儲存貯體。執行以下 CLI 命令，將 `amzn-s3-demo-source-bucket-resized` 取代為您自己的目的地儲存貯體的名稱。

   ```
   aws s3api list-objects-v2 --bucket amzn-s3-demo-source-bucket-resized
   ```

   如果函數成功運作，則您會看到類似以下內容的輸出。您的目標儲存貯體現在應包含兩個已調整大小的檔案。

   ```
   {
       "Contents": [
           {
               "Key": "resized-HappyFace.jpg",
               "LastModified": "2023-06-07T00:15:50+00:00",
               "ETag": "\"7781a43e765a8301713f533d70968a1e\"",
               "Size": 2763,
               "StorageClass": "STANDARD"
           },
           {
               "Key": "resized-SmileyFace.jpg",
               "LastModified": "2023-06-07T00:13:18+00:00",
               "ETag": "\"ca536e5a1b9e32b22cd549e18792cdbc\"",
               "Size": 1245,
               "StorageClass": "STANDARD"
           }
       ]
   }
   ```

------

## 清除您的資源
<a name="s3-tutorial-cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇 **Delete** (刪除)。

**刪除您建立的政策**

1. 開啟 IAM 主控台中的 [Policies (政策) 頁面](https://console.aws.amazon.com/iam/home#/policies)。

1. 選取您建立的政策 (**AWSLambdaS3Policy**)。

1. 選擇**政策動作**，然後**刪除**。

1. 選擇 **刪除** 。

**若要刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇**刪除**。

**刪除 S3 儲存貯體**

1. 開啟 [Amazon S3 主控台](https://console.aws.amazon.com//s3/home#)。

1. 選擇您建立的儲存貯體。

1. 選擇 **刪除** 。

1. 在文字輸入欄位中輸入儲存貯體的名稱。

1. 選擇**刪除儲存貯體**。

# 在 Lambda 函式中使用 Secrets Manager 秘密
<a name="with-secrets-manager"></a>

AWS Secrets Manager 可協助您管理 Lambda 函數所需的登入資料、API 金鑰和其他秘密。與直接使用 AWS SDK 擷取秘密相比，您有兩種主要方法來擷取 Lambda 函數中的秘密，同時提供更好的效能和更低的成本：
+ **AWS 參數和秘密 Lambda 延伸** - 與執行時間無關的解決方案，提供簡單的 HTTP 界面以擷取秘密
+ **適用於 AWS Lambda 參數公用程式的 Powertools** - 一種程式碼整合解決方案，支援具有內建轉換的多個提供者 (Secrets Manager、參數存放區、AppConfig)

這兩種方案都會維護秘密的本機快取，無需函式在每次調用時都呼叫 Secrets Manager。當您的函式請求秘密時，會先檢查快取。如果秘密可用且未過期，則會立即傳回。否則，會從 Secrets Manager 中擷取秘密，快取後再傳回。此快取機制透過最大限度地減少 API 呼叫次數來縮短回應時間並降低成本。

## 選擇合適方案
<a name="lambda-secrets-manager-choosing-approach"></a>

在延伸模組與 PowerTools 之間進行選擇時，建議考量以下因素：

在下列情況下使用 AWS 參數和秘密 Lambda 延伸模組：  
+ 您想要一種與執行時期無關的解決方案，並且其可與任何 Lambda 執行時期搭配使用
+ 您不想將程式碼相依項新增至函式
+ 您僅需從 Secrets Manager 或 Parameter Store 中擷取秘密

在下列情況下，使用 Powertools 做為 AWS Lambda 參數公用程式：  
+ 您希望獲得與應用程式程式碼整合的開發體驗
+ 您需要支援多個提供者 (Secrets Manager、Parameter Store、AppConfig)
+ 您需要內建的資料轉換功能 (JSON 剖析、base64 解碼)
+ 您目前使用的是 Python、TypeScript、Java 或 .NET 執行時期

## 何時將 Secrets Manager 與 Lambda 搭配使用
<a name="lambda-secrets-manager-when-to-use"></a>

將 Secrets Manager 與 Lambda 搭配使用的常見案例包括：
+ 儲存函式用來連線至 Amazon RDS 或其他資料庫的資料庫憑證
+ 管理函式呼叫之外部服務的 API 金鑰
+ 儲存加密金鑰或其他敏感組態資料
+ 自動輪換憑證，而無需更新函式程式碼

## 使用 AWS 參數和秘密 Lambda 延伸模組
<a name="lambda-secrets-manager-extension-approach"></a>

Lambda 延伸模組的 AWS 參數和秘密使用與任何 Lambda 執行時間相容的簡單 HTTP 介面。依預設，該功能會快取秘密 300 秒 (5 分鐘)，並且最多可保留 1,000 個秘密。您可以[使用環境變數自訂這些設定](#lambda-secrets-manager-env-vars)。

### 在 Lambda 函式中使用 Secrets Manager
<a name="lambda-secrets-manager-setup"></a>

本節假設您已擁有一個 Secrets Manager 秘密。若要建立秘密，請參閱[建立 AWS Secrets Manager 秘密](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。

#### 建立部署套件
<a name="lambda-secrets-manager-function-code"></a>

選擇您偏好的執行時期，並依照步驟建立從 Secrets Manager 中擷取秘密的函式。範例函式會從 Secrets Manager 中擷取秘密，並可用來存取應用程式中的資料庫憑證、API 金鑰或其他敏感組態資料。

------
#### [ Python ]

**若要建立 Python 函數**

1. 建立一個新的專案目錄並導覽至該目錄。範例：

   ```
   mkdir my_function
   cd my_function
   ```

1. 建立名為 `lambda_function.py` 的檔案，並貼上以下程式碼。對於 `secret_name`，請使用秘密的名稱或 Amazon Resource Name (ARN)。

   ```
   import json
   import os
   import requests
   
   def lambda_handler(event, context):
       try:
           # Replace with the name or ARN of your secret
           secret_name = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME"
           
           secrets_extension_endpoint = f"http://localhost:2773/secretsmanager/get?secretId={secret_name}"
           headers = {"X-Aws-Parameters-Secrets-Token": os.environ.get('AWS_SESSION_TOKEN')}
           
           response = requests.get(secrets_extension_endpoint, headers=headers)
           print(f"Response status code: {response.status_code}")
           
           secret = json.loads(response.text)["SecretString"]
           print(f"Retrieved secret: {secret}")
           
           return {
               'statusCode': response.status_code,
               'body': json.dumps({
                   'message': 'Successfully retrieved secret',
                   'secretRetrieved': True
               })
           }
       
       except Exception as e:
           print(f"Error: {str(e)}")
           return {
               'statusCode': 500,
               'body': json.dumps({
                   'message': 'Error retrieving secret',
                   'error': str(e)
               })
           }
   ```

1. 建立名為 `requirements.txt` 的檔案，並貼上此內容：

   ```
   requests
   ```

1. 安裝相依項：

   ```
   pip install -r requirements.txt -t .
   ```

1. 建立一個包含所有檔案的 .zip 檔案：

   ```
   zip -r function.zip .
   ```

------
#### [ Node.js ]

**若要建立 Node.js 函數**

1. 建立一個新的專案目錄並導覽至該目錄。範例：

   ```
   mkdir my_function
   cd my_function
   ```

1. 建立名為 `index.mjs` 的檔案，並貼上以下程式碼。對於 `secret_name`，請使用秘密的名稱或 Amazon Resource Name (ARN)。

   ```
   import http from 'http';
   
   export const handler = async (event) => {
       try {
           // Replace with the name or ARN of your secret
           const secretName = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME";
           const options = {
               hostname: 'localhost',
               port: 2773,
               path: `/secretsmanager/get?secretId=${secretName}`,
               headers: {
                   'X-Aws-Parameters-Secrets-Token': process.env.AWS_SESSION_TOKEN
               }
           };
   
           const response = await new Promise((resolve, reject) => {
               http.get(options, (res) => {
                   let data = '';
                   res.on('data', (chunk) => { data += chunk; });
                   res.on('end', () => {
                       resolve({ 
                           statusCode: res.statusCode, 
                           body: data 
                       });
                   });
               }).on('error', reject);
           });
   
           const secret = JSON.parse(response.body).SecretString;
           console.log('Retrieved secret:', secret);
   
           return {
               statusCode: response.statusCode,
               body: JSON.stringify({
                   message: 'Successfully retrieved secret',
                   secretRetrieved: true
               })
           };
       } catch (error) {
           console.error('Error:', error);
           return {
               statusCode: 500,
               body: JSON.stringify({
                   message: 'Error retrieving secret',
                   error: error.message
               })
           };
       }
   };
   ```

1. 建立一個包含 `index.mjs` 檔案的 .zip 檔案：

   ```
   zip -r function.zip index.mjs
   ```

------
#### [ Java ]

**若要建立 Lambda 函數**

1. 建立一個 Maven 專案：

   ```
   mvn archetype:generate \
       -DgroupId=example \
       -DartifactId=lambda-secrets-demo \
       -DarchetypeArtifactId=maven-archetype-quickstart \
       -DarchetypeVersion=1.4 \
       -DinteractiveMode=false
   ```

1. 導覽至專案目錄：

   ```
   cd lambda-secrets-demo
   ```

1. 開啟 `pom.xml` 並將內容替換如下：

   ```
   <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
   
       <groupId>example</groupId>
       <artifactId>lambda-secrets-demo</artifactId>
       <version>1.0-SNAPSHOT</version>
   
       <properties>
           <maven.compiler.source>11</maven.compiler.source>
           <maven.compiler.target>11</maven.compiler.target>
       </properties>
   
       <dependencies>
           <dependency>
               <groupId>com.amazonaws</groupId>
               <artifactId>aws-lambda-java-core</artifactId>
               <version>1.2.1</version>
           </dependency>
       </dependencies>
   
       <build>
           <plugins>
               <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-shade-plugin</artifactId>
                   <version>3.2.4</version>
                   <executions>
                       <execution>
                           <phase>package</phase>
                           <goals>
                               <goal>shade</goal>
                           </goals>
                           <configuration>
                               <createDependencyReducedPom>false</createDependencyReducedPom>
                               <finalName>function</finalName>
                           </configuration>
                       </execution>
                   </executions>
               </plugin>
           </plugins>
       </build>
   </project>
   ```

1. 將 `/lambda-secrets-demo/src/main/java/example/App.java` 重新命名為 `Hello.java`，以符合 Lambda 的預設 Java 處理常式名稱 (`example.Hello::handleRequest`)：

   ```
   mv src/main/java/example/App.java src/main/java/example/Hello.java
   ```

1. 開啟 `Hello.java` 檔案並將內容替換如下。對於 `secretName`，請使用秘密的名稱或 Amazon Resource Name (ARN)。

   ```
   package example;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import java.net.URI;
   import java.net.http.HttpClient;
   import java.net.http.HttpRequest;
   import java.net.http.HttpResponse;
   
   public class Hello implements RequestHandler<Object, String> {
       private final HttpClient client = HttpClient.newHttpClient();
   
       @Override
       public String handleRequest(Object input, Context context) {
           try {
               // Replace with the name or ARN of your secret
               String secretName = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME";
               String endpoint = "http://localhost:2773/secretsmanager/get?secretId=" + secretName;
   
               HttpRequest request = HttpRequest.newBuilder()
                   .uri(URI.create(endpoint))
                   .header("X-Aws-Parameters-Secrets-Token", System.getenv("AWS_SESSION_TOKEN"))
                   .GET()
                   .build();
   
               HttpResponse<String> response = client.send(request, 
                   HttpResponse.BodyHandlers.ofString());
   
               String secret = response.body();
               secret = secret.substring(secret.indexOf("SecretString") + 15);
               secret = secret.substring(0, secret.indexOf("\""));
   
               System.out.println("Retrieved secret: " + secret);
               return String.format(
                   "{\"statusCode\": %d, \"body\": \"%s\"}",
                   response.statusCode(), "Successfully retrieved secret"
               );
   
           } catch (Exception e) {
               e.printStackTrace();
               return String.format(
                   "{\"body\": \"Error retrieving secret: %s\"}", 
                   e.getMessage()
               );
           }
       }
   }
   ```

1. 移除測試目錄。Maven 預設會建立此目錄，但此範例中不需要此目錄。

   ```
   rm -rf src/test
   ```

1. 建置專案：

   ```
   mvn package
   ```

1. 下載 JAR 檔案 (`target/function.jar`) 以供日後使用。

------

#### 建立函數
<a name="lambda-secrets-manager-create"></a>

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇**建立函數**。

1. 選取**從頭開始撰寫**。

1. 針對**函數名稱**，請輸入 **secret-retrieval-demo**。

1. 選擇偏好的**執行時期**。

1. 選擇**建立函數**。

**若要上傳部署套件**

1. 在函式的**程式碼**索引標籤中，選擇**上傳來源**，然後選擇 **.zip 檔案** (適用於 Python 與 Node.js) 或 **.jar 檔案** (適用於 Java)。

1. 上傳先前建立的部署套件。

1. 選擇**儲存**。

#### 新增延伸
<a name="lambda-secrets-manager-extension"></a>

**將 AWS Parameters and Secrets Lambda 延伸模組新增為 layer**

1. 在函式的**程式碼**索引標籤中，向下捲動至**層**。

1. 選擇 **Add a layer (新增 layer)**。

1. 選擇 **AWS 層**。

1. 選擇 **AWS-Parameters-and-Secrets-Lambda-Extension**。

1. 選擇最新版本。

1. 選擇**新增**。

#### 新增許可
<a name="lambda-secrets-manager-permissions"></a>

**若要將 Secrets Manager 許可新增至執行角色**

1. 依序選擇 **Configuration** (組態) 索引標籤和 **Permissions** (許可)。

1. 在**角色名稱**下面，選擇執行角色連結。此連結會在 IAM 主控台中開啟該角色。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/execution-role-console.png)

1. 選擇**新增許可**，然後選擇**建立內嵌政策**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/create-inline-policy.png)

1. 選擇 **JSON** 索引標籤，並新增下列政策。在 `Resource` 欄位中輸入秘密的 ARN。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "secretsmanager:GetSecretValue",
               "Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME"
           }
       ]
   }
   ```

------

1. 選擇**下一步**。

1. 輸入政策的名稱。

1. 選擇**建立政策**。

#### 測試函數
<a name="lambda-secrets-manager-test"></a>

**若要測試函數**

1. 返回 Lambda 主控台。

1. 選取**測試**索引標籤。

1. 選擇**測試**。您應該會看到下列回應：  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/execution-results-secret.png)

### 環境變數
<a name="lambda-secrets-manager-env-vars"></a>

 AWS Parameters and Secrets Lambda 延伸模組使用以下預設設定。您可以建立對應的[環境變數](configuration-envvars.md#create-environment-variables)來覆寫這些設定。若要檢視函式的目前設定，請將 `PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL` 設定為 `DEBUG`。該延伸模組會在每個函式調用開始時，將其組態資訊記錄至 CloudWatch Logs 中。


| 設定 | 預設值 | 有效值 | 環境變數 | 詳細資訊 | 
| --- | --- | --- | --- | --- | 
| HTTP 連接埠 | 2773 | 1 - 65535 | PARAMETERS\$1SECRETS\$1EXTENSION\$1HTTP\$1PORT | 本機 HTTP 伺服器的連接埠 | 
| 快取已啟用 | TRUE | TRUE \$1 FALSE | PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1ENABLED | 啟用或停用快取 | 
| 快取大小 | 1000 | 0 - 1000 | PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1SIZE | 設定為 0 以停用快取 | 
| Secrets Manager TTL | 300 秒 | 0 - 300 秒 | SECRETS\$1MANAGER\$1TTL | 快取秘密的存留時間。設定為 0 以停用快取。如果 PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1SIZE 的值為 0，則會忽略此變數。 | 
| Parameter Store TTL | 300 秒 | 0 - 300 秒 | SSM\$1PARAMETER\$1STORE\$1TTL | 快取參數的存留時間。設定為 0 以停用快取。如果 PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1SIZE 的值為 0，則會忽略此變數。 | 
| 日誌層級 | INFO | DEBUG \$1 INFO \$1 WARN \$1 ERROR \$1 NONE | PARAMETERS\$1SECRETS\$1EXTENSION\$1LOG\$1LEVEL | 延伸日誌中報告的詳細資訊層級 | 
| 連線數量上限 | 3 | 1 或以上 | PARAMETERS\$1SECRETS\$1EXTENSION\$1MAX\$1CONNECTIONS | 向 Parameter Store 或 Secrets Manager 發起請求的 HTTP 連線數量上限 | 
| Secrets Manager 逾時 | 0 (無逾時) | 所有整數 | SECRETS\$1MANAGER\$1TIMEOUT\$1MILLIS | 向 Secrets Manager 發出之請求的逾時 (以毫秒為單位) | 
| Parameter Store 逾時 | 0 (無逾時) | 所有整數 | SSM\$1PARAMETER\$1STORE\$1TIMEOUT\$1MILLIS | 向 Parameter Store 發出之請求的逾時 (以毫秒為單位) | 

### 使用秘密輪換
<a name="lambda-secrets-manager-rotation"></a>

如果經常輪換秘密，預設的 300 秒快取持續時間可能會導致函式使用過時的秘密。有兩種方式可確保函式使用最新的秘密值：
+ 將 `SECRETS_MANAGER_TTL` 環境變數設定為較低值 (以秒為單位)，即可降低快取 TTL。例如，將其設定為 `60`，可確保函式絕不會使用超過一分鐘的舊秘密。
+ 在秘密請求中使用 `AWSCURRENT` 或 `AWSPREVIOUS` 預備標籤，可確保取得所需的特定版本：

  ```
  secretsmanager/get?secretId=YOUR_SECRET_NAME&versionStage=AWSCURRENT
  ```

請選擇最能平衡效能與新鮮度需求的方案。TTL 較低意味著會更頻繁地呼叫 Secrets Manager，但能確保您使用的是最新的秘密值。

## 從 Powertools for 使用參數公用程式 AWS Lambda
<a name="lambda-secrets-manager-powertools-approach"></a>

Powertools for 的參數公用程式 AWS Lambda 提供統一界面，用於從多個提供者擷取秘密，包括 Secrets Manager、參數存放區和 AppConfig。該方案會處理快取、轉換作業，且相較於延伸模組方案，能提供整合更緊密的開發體驗。

### 參數公用程式的優點
<a name="lambda-secrets-manager-powertools-benefits"></a>
+ **多個提供者** – 使用同一個介面從 Secrets Manager、Parameter Store 和 AppConfig 中擷取參數
+ **內建轉換功能** – 自動 JSON 剖析、base64 解碼和其他資料轉換
+ **整合式快取** – 具有 TTL 支援的可設定快取，可減少 API 呼叫次數
+ **型別安全** – 在 TypeScript 與其他支援的執行時期中提供強型別支援
+ **錯誤處理** – 內建重試邏輯和錯誤處理

### 程式碼範例
<a name="lambda-secrets-manager-powertools-examples"></a>

下列範例示範如何在不同的執行時期中使用參數公用程式擷取秘密：

**Python**  
如需完整的範例和設定說明，請參閱 [Parameters utility documentation](https://docs.powertools.aws.dev/lambda/python/latest/utilities/parameters/)。
使用 Powertools for AWS Lambda Parameters 公用程式從 Secrets Manager 擷取秘密。  

```
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities import parameters

logger = Logger()

def lambda_handler(event, context):
    try:
        # Get secret with caching (default TTL: 5 seconds)
        secret_value = parameters.get_secret("my-secret-name")
        
        # Get secret with custom TTL
        secret_with_ttl = parameters.get_secret("my-secret-name", max_age=300)
        
        # Get secret and transform JSON
        secret_json = parameters.get_secret("my-json-secret", transform="json")
        
        logger.info("Successfully retrieved secrets")
        
        return {
            'statusCode': 200,
            'body': 'Successfully retrieved secrets'
        }
        
    except Exception as e:
        logger.error(f"Error retrieving secret: {str(e)}")
        return {
            'statusCode': 500,
            'body': f'Error: {str(e)}'
        }
```

**TypeScript**  
如需完整的範例和設定說明，請參閱 [Parameters utility documentation](https://docs.aws.amazon.com/powertools/typescript/2.1.1/utilities/parameters/)。
使用 Powertools for AWS Lambda Parameters 公用程式從 Secrets Manager 擷取秘密。  

```
import { Logger } from '@aws-lambda-powertools/logger';
import { getSecret } from '@aws-lambda-powertools/parameters/secrets';
import type { Context } from 'aws-lambda';

const logger = new Logger();

export const handler = async (event: any, context: Context) => {
    try {
        // Get secret with caching (default TTL: 5 seconds)
        const secretValue = await getSecret('my-secret-name');
        
        // Get secret with custom TTL
        const secretWithTtl = await getSecret('my-secret-name', { maxAge: 300 });
        
        // Get secret and transform JSON
        const secretJson = await getSecret('my-json-secret', { transform: 'json' });
        
        logger.info('Successfully retrieved secrets');
        
        return {
            statusCode: 200,
            body: 'Successfully retrieved secrets'
        };
        
    } catch (error) {
        logger.error('Error retrieving secret', { error });
        return {
            statusCode: 500,
            body: `Error: ${error}`
        };
    }
};
```

**Java**  
如需完整的範例和設定說明，請參閱 [Parameters utility documentation](https://docs.powertools.aws.dev/lambda/java/latest/utilities/parameters/)。
使用 Powertools for AWS Lambda Parameters 公用程式從 Secrets Manager 擷取秘密。  

```
import software.amazon.lambda.powertools.logging.Logging;
import software.amazon.lambda.powertools.parameters.SecretsProvider;
import software.amazon.lambda.powertools.parameters.ParamManager;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class SecretHandler implements RequestHandler<Object, String> {
    
    private final SecretsProvider secretsProvider = ParamManager.getSecretsProvider();
    
    @Logging
    @Override
    public String handleRequest(Object input, Context context) {
        try {
            // Get secret with caching (default TTL: 5 seconds)
            String secretValue = secretsProvider.get("my-secret-name");
            
            // Get secret with custom TTL (300 seconds)
            String secretWithTtl = secretsProvider.withMaxAge(300).get("my-secret-name");
            
            // Get secret and transform JSON
            MySecret secretJson = secretsProvider.get("my-json-secret", MySecret.class);
            
            return "Successfully retrieved secrets";
            
        } catch (Exception e) {
            return "Error retrieving secret: " + e.getMessage();
        }
    }
    
    public static class MySecret {
        // Define your secret structure here
    }
}
```

**.NET**  
如需完整的範例和設定說明，請參閱 [Parameters utility documentation](https://docs.aws.amazon.com/powertools/typescript/latest/features/parameters/)。
使用 Powertools for AWS Lambda Parameters 公用程式從 Secrets Manager 擷取秘密。  

```
using AWS.Lambda.Powertools.Logging;
using AWS.Lambda.Powertools.Parameters;
using Amazon.Lambda.Core;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

public class Function
{
    private readonly ISecretsProvider _secretsProvider;
    
    public Function()
    {
        _secretsProvider = ParametersManager.SecretsProvider;
    }
    
    [Logging]
    public async Task<string> FunctionHandler(object input, ILambdaContext context)
    {
        try
        {
            // Get secret with caching (default TTL: 5 seconds)
            var secretValue = await _secretsProvider.GetAsync("my-secret-name");
            
            // Get secret with custom TTL
            var secretWithTtl = await _secretsProvider.WithMaxAge(TimeSpan.FromMinutes(5))
                .GetAsync("my-secret-name");
            
            // Get secret and transform JSON
            var secretJson = await _secretsProvider.GetAsync<MySecret>("my-json-secret");
            
            return "Successfully retrieved secrets";
        }
        catch (Exception e)
        {
            return $"Error retrieving secret: {e.Message}";
        }
    }
    
    public class MySecret
    {
        // Define your secret structure here
    }
}
```

### 設定和許可
<a name="lambda-secrets-manager-powertools-setup"></a>

若要使用參數公用程式，您需要：

1.  AWS Lambda 為您的執行時間安裝適用於 的 Powertools。如需詳細資訊，請參閱[Powertools for AWS Lambda](powertools-for-lambda.md)。

1. 將必要的 IAM 許可新增至函式的執行角色。請參閱 [在 中管理許可 AWS Lambda](lambda-permissions.md) 以取得詳細資訊。

1. 透過[環境變數](configuration-envvars.md)來進行選用設定。

所需的 IAM 許可與延伸模組方案相同。參數公用程式會根據您的組態自動處理對 Secrets Manager 的快取和 API 呼叫。

# 搭配 Amazon SQS 使用 Lambda
<a name="with-sqs"></a>

**注意**  
如要將資料傳送到 Lambda 函數以外的目標，或在傳送資料之前讓資料更豐富，請參閱 [Amazon EventBridge Pipes](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes.html)。

您可以使用 Lambda 函數處理 Amazon Simple Queue Service (Amazon SQS) 佇列中的訊息。Lambda [事件來源映射](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html)既支援[標準佇列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html)，也支援[先進先出 (FIFO) 佇列](invocation-eventsourcemapping.md)。您也可以使用佈建模式為 Amazon SQS 事件來源映射配置專用輪詢資源。Lambda 函數和 Amazon SQS 佇列必須位於相同的 中 AWS 區域，雖然它們可以位於[不同的 AWS 帳戶](with-sqs-cross-account-example.md) 中。

處理 Amazon SQS 訊息時，您需要實作部分批次回應邏輯，避免批次中部分訊息處理失敗時，已成功處理的訊息被重新執行。Powertools for 的 [Batch Processor 公用程式](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)可自動處理部分批次回應邏輯、縮短開發時間並改善可靠性，藉此 AWS Lambda 簡化此實作。

**Topics**
+ [

## 了解 Amazon SQS 事件來源映射的輪詢和批次處理行為
](#sqs-polling-behavior)
+ [

## 搭配 Amazon SQS 事件來源映射使用佈建模式
](#sqs-provisioned-mode)
+ [

## 設定 Amazon SQS 事件來源映射的佈建模式
](#sqs-configuring-provisioned-mode)
+ [

## 標準佇列訊息事件範例
](#example-standard-queue-message-event)
+ [

## FIFO 佇列訊息事件範例
](#sample-fifo-queues-message-event)
+ [

# 建立和設定 Amazon SQS 事件來源映射
](services-sqs-configure.md)
+ [

# 設定 SQS 事件來源映射的擴展行為
](services-sqs-scaling.md)
+ [

# 在 Lambda 中處理 SQS 事件來源的錯誤
](services-sqs-errorhandling.md)
+ [

# Amazon SQS 事件來源映射的 Lambda 參數
](services-sqs-parameters.md)
+ [

# 對 Amazon SQS 事件來源使用事件篩選
](with-sqs-filtering.md)
+ [

# 教學課程：搭配 Amazon SQS 使用 Lambda
](with-sqs-example.md)
+ [

# 教學課程：使用跨帳戶 Amazon SQS 佇列做為事件來源
](with-sqs-cross-account-example.md)

## 了解 Amazon SQS 事件來源映射的輪詢和批次處理行為
<a name="sqs-polling-behavior"></a>

使用 Amazon SQS 事件來源映射時，Lambda 會輪詢佇列，並在出現事件時[同步](invocation-sync.md)調用函數。每個事件可以包含佇列中的一批訊息。Lambda 一次接收一個批次的這些事件，並為每個批次調用函數一次。當您的函數成功處理批次時，Lambda 會從佇列中刪除其訊息。

當 Lambda 接收到一個批次時，訊息會留在佇列中，但是在佇列的[可見性逾時](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)期間會變成隱藏。如果您的函數成功處理批次中的全部訊息，Lambda 會從佇列中刪除訊息。根據預設，如果函數在處理批次時遇到錯誤，則該批次中的所有訊息會在可見性逾時時間到了之後再次顯示在佇列中。因此，您的函數程式碼必須能夠多次處理相同的訊息，而不會產生副作用。

**警告**  
Lambda 事件來源映射至少會處理每個事件一次，而且可能會重複處理記錄。為避免與重複事件相關的潛在問題，強烈建議您讓函數程式碼具有等冪性。若要進一步了解，請參閱 AWS 知識中心中的[如何使 Lambda 函數具有等冪性](https://repost.aws/knowledge-center/lambda-function-idempotent)。

若要防止 Lambda 多次處理訊息，您可以設定事件來源映射，在函數回應中包含[批次項目失敗](services-sqs-errorhandling.md#services-sqs-batchfailurereporting)，或者可以使用 [DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html) API 動作，在 Lambda 函數成功處理訊息時從佇列中移除訊息。

如需 Lambda 支援用於 SQS 事件來源映射的組態參數的詳細資訊，請參閱[建立 SQS 事件來源映射](services-sqs-configure.md#events-sqs-eventsource)。

## 搭配 Amazon SQS 事件來源映射使用佈建模式
<a name="sqs-provisioned-mode"></a>

對於您需要微調事件來源映射輸送量的工作負載，可以使用佈建模式。在佈建模式中，可以定義佈建的事件輪詢器數量的下限和上限。這些佈建的事件輪詢器專用於您的事件來源映射，並且可以透過回應性自動擴展處理意外的訊息尖峰。使用佈建模式設定的 Amazon SQS 事件來源映射擴展速度快 3 倍 （每分鐘最多 1，000 個並行調用），並支援比預設 Amazon SQS 事件來源映射功能高 16 倍的並行調用 （最多 20，000 個並行調用）。我們建議您針對具有嚴格效能需求的 Amazon SQS 事件驅動型工作負載使用佈建模式，例如處理市場資料饋送的金融服務公司、提供即時個人化建議的電子商務平台，以及管理即時玩家互動的遊戲公司。使用佈建模式會產生額外費用。如需詳細的定價，請參閱 [AWS Lambda 定價](https://aws.amazon.com/lambda/pricing/)。

佈建模式中的每個事件輪詢器最多可處理每秒 1 MB 的輸送量、最多 10 個並行調用，或每秒最多 10 個 Amazon SQS 輪詢 API 呼叫。事件輪詢器 (MinimumPollers) 數目下限的接受值範圍介於 2 到 200 之間，預設值為 2。事件輪詢器 (MaximumPollers) 數目上限的接受值範圍介於 2 到 2，000 之間，預設值為 200。MaximumPollers 必須大於或等於 MinimumPollers。

### 判斷所需的事件輪詢器
<a name="sqs-determining-event-pollers"></a>

若要預估在 SQS ESM 使用佈建模式時確保最佳訊息處理效能所需的事件輪詢器數量，請為您的應用程式收集下列指標：需要低延遲處理的每秒尖峰 SQS 事件數、平均 SQS 事件承載大小、平均 Lambda 函數持續時間，以及設定的批次大小。

首先，您可以使用下列公式，為您的工作負載預估事件輪詢器支援的每秒 SQS 事件數 (EPS)：

```
EPS per event poller = 
        minimum(
            ceiling(1024 / average event size in KB),
            ceiling(10 / average function duration in seconds) * batch size, 
            min(100, 10 * batch size)
                )
```

然後，您可以使用以下公式計算所需的最低輪詢器數量。此計算可確保您佈建足夠的容量來處理尖峰流量需求。

```
Required event pollers = (Peak number of events per second in Queue) / EPS per event poller
```

假設工作負載的預設批次大小為 10、平均事件大小為 3 KB、平均函數持續時間為 100 毫秒，且需要每秒處理 1，000 個事件。在此案例中，每個事件輪詢器每秒將支援約 100 個事件 (EPS)。因此，您應該將最低輪詢器設定為 10，以充分處理您的尖峰流量需求。如果您的工作負載具有相同的特性，但平均函數持續時間為 1 秒，則每個輪詢器將僅支援 10 個 EPS，要求您設定 100 個最低輪詢器，以低延遲支援每秒 1，000 個事件。

建議使用預設批次大小 10 或更高，以最大限度地提高佈建模式事件輪詢器的效率。較高的批次大小可讓每個輪詢器在每次調用時處理更多事件，以提高輸送量和成本效益。規劃事件輪詢器容量時，請考量潛在的流量峰值，並考慮將 minimumPollers 值稍高於計算的最小值，以提供緩衝區。此外，隨著時間的推移監控工作負載特性，因為訊息大小、函數持續時間或流量模式的變更可能需要調整事件輪詢器組態，以維持最佳效能和成本效益。為了精確規劃容量，我們建議您測試特定工作負載，以判斷每個事件輪詢器可以驅動的實際 EPS。

## 設定 Amazon SQS 事件來源映射的佈建模式
<a name="sqs-configuring-provisioned-mode"></a>

您可以使用主控台或 Lambda API，為 Amazon SQS 事件來源映射設定佈建模式。

**設定現有 Amazon SQS 事件來源映射的佈建模式 （主控台）**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇具有您要為其設定佈建模式之 Amazon SQS 事件來源映射的函數。

1. 選擇**組態**，然後選擇**觸發條件**。

1. 選擇您要為其設定佈建模式的 Amazon SQS 事件來源映射，然後選擇**編輯**。

1. 在**事件來源映射組態**下，選擇**設定佈建模式**。
   + 針對**最低事件輪詢器**，輸入介於 2 到 200 之間的值。如果您未指定值，Lambda 會選擇預設值 2。
   + 針對**事件輪詢器上限**，輸入介於 2 到 2，000 之間的值。此值必須大於或等於**事件輪詢器下限**值。如果您沒有指定值，則 Lambda 會選擇預設值 200。

1. 選擇**儲存**。

您可以使用 中的 `ProvisionedPollerConfig` 物件，以程式設計方式設定佈建模式`EventSourceMappingConfiguration`。例如，下列 `UpdateEventSourceMapping` CLI 命令會設定 5 `MinimumPollers`的值，以及 100 `MaximumPollers`的值。

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{"MinimumPollers": 5, "MaximumPollers": 100}'
```

設定佈建模式後，可以透過監控 `ProvisionedPollers` 指標來觀察工作負載的事件輪詢器使用情況。如需詳細資訊，請參閱事件來源映射指標。

若要停用佈建模式並返回預設 （隨需） 模式，您可以使用下列 `UpdateEventSourceMapping` CLI 命令：

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{}'
```

**注意**  
佈建模式無法與最大並行設定搭配使用。使用佈建模式時，您可以透過事件輪詢器的數量上限來控制並行上限。

如需設定佈建模式的詳細資訊，請參閱 [建立和設定 Amazon SQS 事件來源映射](services-sqs-configure.md)。

## 標準佇列訊息事件範例
<a name="example-standard-queue-message-event"></a>

**Example Amazon SQS 訊息事件 (標準佇列)**  

```
{
    "Records": [
        {
            "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
            "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
            "body": "Test message.",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1545082649183",
                "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                "ApproximateFirstReceiveTimestamp": "1545082649185"
            },
            "messageAttributes": {
                "myAttribute": {
                    "stringValue": "myValue", 
                    "stringListValues": [], 
                    "binaryListValues": [], 
                    "dataType": "String"
                }
            },
            "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:my-queue",
            "awsRegion": "us-east-2"
        },
        {
            "messageId": "2e1424d4-f796-459a-8184-9c92662be6da",
            "receiptHandle": "AQEBzWwaftRI0KuVm4tP+/7q1rGgNqicHq...",
            "body": "Test message.",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1545082650636",
                "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                "ApproximateFirstReceiveTimestamp": "1545082650649"
            },
            "messageAttributes": {},
            "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:my-queue",
            "awsRegion": "us-east-2"
        }
    ]
}
```

依預設，Lambda 會一次輪詢佇列中最多 10 則訊息，並將該批次傳送給函數。為避免調用具有少量記錄的函數，您可設定批次間隔，讓事件來源緩衝記錄最長達五分鐘。調用函數之前，Lambda 會繼續從標準佇列輪詢訊息，直至批次間隔到期、達到[調用承載大小配額](gettingstarted-limits.md)，或達到設定的批次大小上限為止。

如果您使用的是批次時間範圍，並且您的 SQS 佇列包含非常低的流量，Lambda 可能會等到 20 秒，然後再調用您的函數。即使您將批次時間範圍設定為低於 20 秒也是如此。

**注意**  
在 Java 中，還原序列化 JSON 時可能會遇到 null 指標錯誤。這可能是由於 JSON 物件映射器對「Records」和「eventSourceARN」案例轉換的方式所致。

## FIFO 佇列訊息事件範例
<a name="sample-fifo-queues-message-event"></a>

對於 FIFO 佇列，記錄包含與重複資料刪除和定序相關的其他屬性。

**Example Amazon SQS 訊息事件 (FIFO 佇列)**  

```
{
    "Records": [
        {
            "messageId": "11d6ee51-4cc7-4302-9e22-7cd8afdaadf5",
            "receiptHandle": "AQEBBX8nesZEXmkhsmZeyIE8iQAMig7qw...",
            "body": "Test message.",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1573251510774",
                "SequenceNumber": "18849496460467696128",
                "MessageGroupId": "1",
                "SenderId": "AIDAIO23YVJENQZJOL4VO",
                "MessageDeduplicationId": "1",
                "ApproximateFirstReceiveTimestamp": "1573251510774"
            },
            "messageAttributes": {},
            "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:fifo.fifo",
            "awsRegion": "us-east-2"
        }
    ]
}
```

# 建立和設定 Amazon SQS 事件來源映射
<a name="services-sqs-configure"></a>

若要使用 Lambda 處理 Amazon SQS 訊息，請正確設定佇列，然後建立 Lambda 事件來源映射。

**Topics**
+ [

## 配置要搭配 Lambda 使用的佇列
](#events-sqs-queueconfig)
+ [

## 設定 Lambda 執行角色許可
](#events-sqs-permissions)
+ [

## 建立 SQS 事件來源映射
](#events-sqs-eventsource)

## 配置要搭配 Lambda 使用的佇列
<a name="events-sqs-queueconfig"></a>

如果您還沒有建立 Amazon SQS 佇列，請[建立一個](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-create-queue.html)來做為 Lambda 函數的事件來源。Lambda 函數和 Amazon SQS 佇列必須位於相同的 中 AWS 區域，雖然它們可以位於[不同的 AWS 帳戶](with-sqs-cross-account-example.md) 中。

為讓您的函數有時間處理每個記錄批次，請將來源佇列的[可見性逾時](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)設定為[函數設定之逾時](configuration-timeout.md)的至少六倍。萬一您的函數在處理前一個批次時遭到調節，額外的時間可允許 Lambda 重試。

**注意**  
函式的逾時必須小於或等於佇列的可見性逾時。當您建立或更新事件來源映射時，Lambda 會驗證此項要求，在函式逾時超過佇列的可見性逾時之時傳回錯誤。

根據預設，只要 Lambda 在處理批次的過程中遇到錯誤，則該批次中的所有訊息都會傳回佇列。在[可見性逾時](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)時間到了之後，這些訊息會再次對 Lambda 可見。您可以將事件來源映射設定為使用[部分批次回應](services-sqs-errorhandling.md#services-sqs-batchfailurereporting)，從而僅將失敗的訊息傳回佇列。此外，如果函數多次處理訊息失敗，Amazon SQS 可將訊息傳送到[無效字母佇列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)。我們建議將來源佇列的[再驅動政策](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html#policies-for-dead-letter-queues) 的 `maxReceiveCount` 設定為 5 或更大。這讓 Lambda 在將失敗的訊息傳送到無效字母佇列之前，有機會重試幾次。

## 設定 Lambda 執行角色許可
<a name="events-sqs-permissions"></a>

[ AWSLambdaSQSQueueExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaSQSQueueExecutionRole.html) AWS 受管政策包含 Lambda 從 Amazon SQS 佇列讀取所需的許可。您可以將此受管政策新增至函數的[執行角色](lambda-intro-execution-role.md)。

或者，如果您使用的是加密佇列，也需要將下列許可新增至您的執行角色：
+ [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)

## 建立 SQS 事件來源映射
<a name="events-sqs-eventsource"></a>

建立事件來源映射，指示 Lambda 從您的佇列傳送項目至 Lambda 函數。您可以建立多個事件來源映射，使用單一函數處理來自多個佇列的項目。當 Lambda 調用目標函數時，事件可能包含多個項目，最多為可設定的最大*批次大小*。

若要將函數設定為從 Amazon SQS 讀取，請將 [ AWSLambdaSQSQueueExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaSQSQueueExecutionRole.html) AWS 受管政策連接至您的執行角色。然後，透過以下步驟從主控台建立 **SQS** 事件來源映射。

**若要新增許可並建立觸發條件**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函數的名稱。

1. 依序選擇 **Configuration** (組態) 索引標籤和 **Permissions** (許可)。

1. 在**角色名稱**下面，選擇執行角色連結。此連結會在 IAM 主控台中開啟該角色。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/execution-role.png)

1. 選擇**新增許可**，然後選擇**連接政策**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/attach-policies.png)

1. 在搜尋欄位中輸入 `AWSLambdaSQSQueueExecutionRole`。將此政策新增至您的執行角色。這是 AWS 受管政策，其中包含函數從 Amazon SQS 佇列讀取所需的許可。如需此政策的詳細資訊，請參閱《AWS 受管政策參考》**中的 [AWSLambdaSQSQueueExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaSQSQueueExecutionRole.html) 一節。

1. 在 Lambda 主控台中返回您的 Lambda 函數。在**函數概觀**下，選擇**新增觸發條件**。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/add-trigger.png)

1. 選擇觸發條件類型。

1. 設定需要的選項，然後選擇**新增**。

Lambda 支援 Amazon SQS 事件來源的下列組態選項：

**SQS 佇列**  
要從中讀取記錄的 Amazon SQS 佇列。Lambda 函數和 Amazon SQS 佇列必須位於相同的 中 AWS 區域，雖然它們可以位於[不同的 AWS 帳戶](with-sqs-cross-account-example.md) 中。

**啟用觸發條件**  
事件來源映射的狀態。系統會預設選取**啟用觸發條件**。

**批次大小**  
每個批次中要傳送至函數的記錄數量上限。若是標準佇列，這最高可達 10,000 個記錄。若是 FIFO 佇列，最大值為 10。批次大小若超過 10，您還必須將批次間隔 (`MaximumBatchingWindowInSeconds`) 設定為至少 1 秒。  
設定[函數逾時](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/configurations#timeouts)以允許足夠時間來處理整個項目批次。如果項目需要長時間處理，請選擇較小的批次大小。大型批次大小可提升效率，適用非常快速或開銷龐大的工作負載。如果您在函數上設定[保留並行](configuration-concurrency.md)，應最少設定五個並行執行，藉此降低 Lambda 調用函數時的調節錯誤機率。  
Lambda 會將批次中所有記錄以單一呼叫傳送至函數，前提是事件的總大小不超過同步調用的[調用承載大小配額](gettingstarted-limits.md) (6 MB)。Lambda 和 Amazon SQS 兩者均會產生每筆記錄的中繼資料。這個額外的中繼資料會計入總酬載大小，並且可能會導致批次中傳送的記錄總數低於您設定的批次大小。Amazon SQS 傳送的中繼資料欄位長度可能有所不同。如需 Amazon SQS 中繼資料欄位的詳細資訊，請參閱 *Amazon Simple Queue Service API 參考*中的 [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html) API 操作文件。

**批次視窗**  
調用函式前收集記錄的最長時間 (單位為秒)。這僅適用於標準佇列。  
如果您使用的批次間隔大於 0 秒，則必須考慮佇列[可見性逾時](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)中增加的處理時間。我們建議將您的佇列可見性逾時設定為[函數逾時](configuration-timeout.md)的六倍，再加上 `MaximumBatchingWindowInSeconds` 的值。這可讓您的 Lambda 函數有時間處理每個事件批次，並在發生節流錯誤時重試。  
當訊息可供使用，Lambda 會開始批次處理訊息。Lambda 會開始一次處理五個批次，而函數有五個並行調用。如果訊息仍然可用，Lambda 每分鐘會為您的函數新增最多 300 個並行調用，最多 1，250 個並行調用。使用佈建模式時，每個事件輪詢器最多可處理每秒 1 MB 的輸送量、最多 10 個並行調用，或每秒最多 10 個 Amazon SQS 輪詢 API 呼叫。Lambda 會在設定的最小值和最大值之間擴展事件輪詢器的數量，快速新增每分鐘最多 1，000 個並行調用，以提供 Amazon SQS 事件的低延遲處理。您可以透過這些最小和最大事件輪詢器設定來控制擴展和並行。若要進一步了解函數擴展和並行，請參閱 [了解 Lambda 函數擴展](lambda-concurrency.md)。  
若要處理更多訊息，您可以最佳化 Lambda 函數以達到更高的輸送量。如需詳細資訊，請參閱[了解 如何使用 Amazon SQS 標準佇列 AWS Lambda 擴展](https://aws.amazon.com/blogs/compute/understanding-how-aws-lambda-scales-when-subscribed-to-amazon-sqs-queues/#:~:text=If there are more messages,messages from the SQS queue.)。

**篩選條件**  
新增篩選條件來控制 Lambda 要傳送哪些事件給函數進行處理。如需詳細資訊，請參閱[控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)。

**並行上限**  
事件來源可以調用的並行函數上限。無法與已啟用佈建模式搭配使用。如需詳細資訊，請參閱[設定 Amazon SQS 事件來源的並行上限](services-sqs-scaling.md#events-sqs-max-concurrency)。

**佈建模式**  
啟用時， 會為您的事件來源映射配置專用輪詢資源。您可以設定事件輪詢器的最小 (2-200) 和最大 (2-2000) 數量。每個事件輪詢器最多可以處理每秒 1 MB 的輸送量、最多 10 個並行調用，或每秒最多 10 個 Amazon SQS 輪詢 API 呼叫。  
注意：您無法同時使用佈建模式和最大並行。啟用佈建模式時，請使用最大輪詢器設定來控制並行。

# 設定 SQS 事件來源映射的擴展行為
<a name="services-sqs-scaling"></a>

您可以透過最大並行設定或啟用佈建模式來控制 Amazon SQS 事件來源映射的擴展行為。這些是互斥選項。

根據預設，Lambda 會根據訊息磁碟區自動擴展事件輪詢器。當您啟用佈建模式時，您可以配置最小和最大數量的專用輪詢資源，這些資源仍然準備好處理預期的流量模式。這可讓您以兩種方式最佳化事件來源映射的效能：
+ 標準模式 （預設）：Lambda 會自動管理擴展，從少量輪詢器開始，並根據工作負載向上或向下擴展。
+ 佈建模式：您可以設定具有最小和最大限制的專用輪詢資源，使擴展速度加快 3 倍，處理容量提高 16 倍。

針對標準佇列，Lambda 會使用[長輪詢](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html#sqs-long-polling)來輪詢佇列，直至其處於作用中狀態。當訊息可用時，Lambda 會開始一次處理五個批次，而函數有五個並行調用。如果訊息仍然可用，Lambda 會增加讀取批次的程序數量，每分鐘最多增加 300 個並行調用。事件來源映射可同時處理的調用數目上限為 1，250。當流量較低時，Lambda 會將處理縮減為五個並行調用，並且可以最佳化為最少 2 個並行調用，以減少 Amazon SQS 呼叫和對應的成本。然而，如果啟用並行上限設定，將無法使用此最佳化。

針對 FIFO 佇列，Lambda 會按照其接收的順序傳送訊息到您的函數。當您傳送訊息到 FIFO 佇列時，您可以指定[訊息群組 ID](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html)。Amazon SQS 可確保相同群組中的訊息依序傳遞至 Lambda。當 Lambda 將訊息讀取到批次時，每個批次可能包含來自多個訊息群組的訊息，但訊息的順序會保持不變。如果您的函數傳回錯誤，函數會先在受影響的訊息上嘗試所有重試，之後 Lambda 才會從相同群組接收到額外訊息。

使用佈建模式時，每個事件輪詢器最多可以處理每秒 1 MB 的輸送量、最多 10 個並行調用，或每秒最多 10 個 Amazon SQS 輪詢 API 呼叫。Lambda 會在您設定的最小值和最大值之間擴展事件輪詢器數量，快速新增高達每分鐘 1，000 個並行，以提供 Amazon SQS 事件的一致、低延遲處理。使用佈建模式會產生額外費用。如需詳細的定價，請參閱 [AWS Lambda 定價](https://aws.amazon.com/lambda/pricing/)。每個事件輪詢器對您的 SQS 佇列使用[長輪詢](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html)，每秒最多 10 個輪詢，這會產生 SQS API 請求成本。如需詳細資訊，請參閱 [Amazon SQS 定價](https://aws.amazon.com/sqs/pricing/ )。您可以透過這些最小和最大事件輪詢器設定來控制擴展和並行，而不是使用最大並行設定，因為這些選項無法一起使用。

**注意**  
您無法同時使用最大並行設定和佈建模式。啟用佈建模式時，您可以透過事件輪詢器的最小和最大數量來控制 Amazon SQS 事件來源映射的擴展和並行。

## 設定 Amazon SQS 事件來源的並行上限
<a name="events-sqs-max-concurrency"></a>

您可以使用最大並行設定來控制 SQS 事件來源的擴展行為。請注意，最大並行不能在已啟用佈建模式的情況下使用。並行上限設定限制了 Amazon SQS 事件來源可以調用的函數並行執行個體數。並行上限是事件來源層級的設定。如果您將多個 Amazon SQS 事件來源映射到一個函數，那麼每個事件來源都可以有個別的並行上限設定。您可以使用並行上限來防止一個佇列用完函數的所有[預留並行配額](configuration-concurrency.md)，或其餘的[帳戶並行配額](gettingstarted-limits.md)。對 Amazon SQS 事件來源設定並行無需付費。

重要的是，並行上限和預留並行是兩項獨立的設定。請勿將並行上限設為超過函數的預留並行。若您設定了並行上限，請確定函數的預留並行大於或等於函數上所有 Amazon SQS 事件來源的總並行上限。若小於此上限，Lambda 可能會限流您的訊息。

當您帳戶的並行配額設定為預設值 1,000 時，除非您指定最大並行，否則 Amazon SQS 事件來源映射最高可以擴展至調用數量為該值的函數執行個體。

即便帳戶的預設並行配額增加，Lambda 也可能無法調用數量為新配額的並行函數執行個體。根據預設，對於一個 Amazon SQS 事件來源映射，Lambda 可以擴展為調用最多 1,250 個並行函數執行個體。如果這不足以滿足您的使用案例，請聯絡 AWS 支援，以討論增加您帳戶的 Amazon SQS 事件來源映射並行。

**注意**  
對於 FIFO 佇列，並行調用的上限是[訊息群組 ID](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html) (`messageGroupId`) 的數量或最大並行設定 (以較低者為準)。例如，如果您有六個訊息群組 ID，而最大並行設定為 10，則函數最多可以有六個並行調用。

您可以對新的和現有的 Amazon SQS 事件來源映射設定並行上限。

**使用 Lambda 主控台設定並行上限**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函數的名稱。

1. 在**函數概觀**下，選擇 **SQS**。這會開啟 **Configuration** (組態) 索引標籤。

1. 選取 Amazon SQS 觸發條件，然後選擇**編輯**。

1. **Maximum concurrency** (並行上限) 請輸入介於 2 到 1,000 之間的數字。若要關閉並行上限，請將方塊保留空白。

1. 選擇**儲存**。

**使用 AWS Command Line Interface (AWS CLI) 設定並行上限**  
使用 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 命令和 `--scaling-config` 選項。範例：

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --scaling-config '{"MaximumConcurrency":5}'
```

若要關閉並行上限，請為 `--scaling-config` 輸入空值：

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --scaling-config "{}"
```

**使用 Lambda API 設定並行上限**  
使用 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 或[UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) 動作搭配 [ScalingConfig](https://docs.aws.amazon.com/lambda/latest/api/API_ScalingConfig.html) 物件。

# 在 Lambda 中處理 SQS 事件來源的錯誤
<a name="services-sqs-errorhandling"></a>

為了處理與 SQS 事件來源相關的錯誤，Lambda 會自動使用重試策略搭配退避策略。您也可以透過設定 SQS 事件來源映射，來自訂錯誤處理行為，以傳回[部分批次回應](#services-sqs-batchfailurereporting)。

## 失敗調用的輪詢策略
<a name="services-sqs-backoff-strategy"></a>

當調用失敗，Lambda 會在實作輪詢策略時嘗試重試調用。根據 Lambda 是否因函數程式碼錯誤或限流而發生失敗，輪詢策略會略有不同。
+  如果是**函數程式碼**導致錯誤，則 Lambda 會停止處理並重試調用。同時，Lambda 會逐漸退避，減少分配給 Amazon SQS 事件來源映射的並行數量。在佇列的可見性逾時時間到了之後，訊息會再次重新出現在佇列中。
+ 如果是**限流**導致調用失敗，Lambda 會減少分配給 Amazon SQS 事件來源映射的並行數量，逐漸重試輪詢。Lambda 會持續重試訊息，直到訊息的時間戳記超過佇列的可見性逾時為止，此時 Lambda 會捨棄訊息。

## 實作部分批次回應
<a name="services-sqs-batchfailurereporting"></a>

當 Lambda 函數在處理批次時遇到錯誤，根據預設，該批次中的所有訊息會再次顯示在佇列中，包含 Lambda 已順利處理的訊息。因此，您的函數可能最後會處理數次相同的訊息。

若要避免重新處理失敗批次中成功處理過的訊息，您可以設定事件來源映射，僅讓失敗的訊息再次可見。我們將其稱為部分批次回應。若要開啟部分批次回應，請在設定事件來源映射時為 [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html#lambda-UpdateEventSourceMapping-request-FunctionResponseTypes) 動作指定 `ReportBatchItemFailures`。這可以讓您的函數傳回部分成功，有助於減少記錄上不必要的重試次數。

**注意**  
適用於 的 Powertools [批次處理器公用程式](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)會自動 AWS Lambda 處理所有部分批次回應邏輯。此公用程式簡化了批次處理模式的實作流程，也減少了正確處理批次項目失敗所需的自訂程式碼。該工具組支援 Python、Java、Typescript 與 .NET。

啟動 `ReportBatchItemFailures` 時，Lambda 不會在函數調用失敗時[縮減訊息輪詢的規模](#services-sqs-backoff-strategy)。如果您預期部分訊息會失敗，且不希望這些失敗影響到訊息的處理速度，則請使用 `ReportBatchItemFailures`。

**注意**  
使用部分批次回應時，請注意下列事項：  
如果函數擲出例外情況，便會將整個批次視為完全失敗。
如果您將此功能與 FIFO 佇列一起使用，您的函數應該在第一次失敗後停止處理訊息，並傳回 `batchItemFailures` 中所有失敗與尚未處理的訊息。這有助於保留佇列中訊息的順序。

**若要啟動部分批次報告**

1. 檢閱[實作部分批次回應的最佳實務](https://docs.aws.amazon.com/prescriptive-guidance/latest/lambda-event-filtering-partial-batch-responses-for-sqs/best-practices-partial-batch-responses.html)。

1. 執行以下命令以便為函數啟用 `ReportBatchItemFailures`。若要擷取事件來源映射的 UUID，請執行 [list-event-source-mappings](https://docs.aws.amazon.com/cli/latest/reference/lambda/list-event-source-mappings.html) AWS CLI 命令。

   ```
   aws lambda update-event-source-mapping \
   --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
   --function-response-types "ReportBatchItemFailures"
   ```

1. 更新函數程式碼以擷取所有例外狀況，並傳回 `batchItemFailures` JSON 回應中的失敗訊息。`batchItemFailures` 回應必須含有以 `itemIdentifier` JSON 值表示的訊息 ID 清單。

   例如，假設您有五則訊息的批次，其中，訊息 ID 分別為 `id1`、`id2`、`id3`、`id4`，以及 `id5`。您的函數已成功處理 `id1`、`id3`，以及 `id5`。若要讓訊息 `id2` 和 `id4` 再次於佇列中可見，您的函數應傳回以下回應：

   ```
   { 
     "batchItemFailures": [ 
           {
               "itemIdentifier": "id2"
           },
           {
               "itemIdentifier": "id4"
           }
       ]
   }
   ```

   以下範例函數程式碼會傳回批次中失敗訊息 ID 的清單：

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   using Amazon.Lambda.Core;
   using Amazon.Lambda.SQSEvents;
   
   // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
   [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
   namespace sqsSample;
   
   public class Function
   {
       public async Task<SQSBatchResponse> FunctionHandler(SQSEvent evnt, ILambdaContext context)
       {
           List<SQSBatchResponse.BatchItemFailure> batchItemFailures = new List<SQSBatchResponse.BatchItemFailure>();
           foreach(var message in evnt.Records)
           {
               try
               {
                   //process your message
                   await ProcessMessageAsync(message, context);
               }
               catch (System.Exception)
               {
                   //Add failed message identifier to the batchItemFailures list
                   batchItemFailures.Add(new SQSBatchResponse.BatchItemFailure{ItemIdentifier=message.MessageId}); 
               }
           }
           return new SQSBatchResponse(batchItemFailures);
       }
   
       private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context)
       {
           if (String.IsNullOrEmpty(message.Body))
           {
               throw new Exception("No Body in SQS Message.");
           }
           context.Logger.LogInformation($"Processed message {message.Body}");
           // TODO: Do interesting work based on the new message
           await Task.CompletedTask;
       }
   }
   ```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures)儲存庫中設定和執行。
使用 Go 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   package main
   
   import (
   	"context"
   	"fmt"
   	"github.com/aws/aws-lambda-go/events"
   	"github.com/aws/aws-lambda-go/lambda"
   )
   
   func handler(ctx context.Context, sqsEvent events.SQSEvent) (map[string]interface{}, error) {
   	batchItemFailures := []map[string]interface{}{}
   
   	for _, message := range sqsEvent.Records {
   		if len(message.Body) > 0 {
   			// Your message processing condition here
   			fmt.Printf("Successfully processed message: %s\n", message.Body)
   		} else {
   			// Message processing failed
   			fmt.Printf("Failed to process message %s\n", message.MessageId)
   			batchItemFailures = append(batchItemFailures, map[string]interface{}{"itemIdentifier": message.MessageId})
   		}
   	}
   
   	sqsBatchResponse := map[string]interface{}{
   		"batchItemFailures": batchItemFailures,
   	}
   	return sqsBatchResponse, nil
   }
   
   func main() {
   	lambda.Start(handler)
   }
   ```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures)儲存庫中設定和執行。
使用 Java 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import com.amazonaws.services.lambda.runtime.events.SQSEvent;
   import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
    
   import java.util.ArrayList;
   import java.util.List;
    
   public class ProcessSQSMessageBatch implements RequestHandler<SQSEvent, SQSBatchResponse> {
       @Override
       public SQSBatchResponse handleRequest(SQSEvent sqsEvent, Context context) {
            List<SQSBatchResponse.BatchItemFailure> batchItemFailures = new ArrayList<SQSBatchResponse.BatchItemFailure>();
   
            for (SQSEvent.SQSMessage message : sqsEvent.getRecords()) {
                try {
                    //process your message
                } catch (Exception e) {
                    //Add failed message identifier to the batchItemFailures list
                    batchItemFailures.add(new SQSBatchResponse.BatchItemFailure(message.getMessageId()));
                }
            }
            return new SQSBatchResponse(batchItemFailures);
        }
   }
   ```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   // Node.js 20.x Lambda runtime, AWS SDK for Javascript V3
   export const handler = async (event, context) => {
       const batchItemFailures = [];
       for (const record of event.Records) {
           try {
               await processMessageAsync(record, context);
           } catch (error) {
               batchItemFailures.push({ itemIdentifier: record.messageId });
           }
       }
       return { batchItemFailures };
   };
   
   async function processMessageAsync(record, context) {
       if (record.body && record.body.includes("error")) {
           throw new Error("There is an error in the SQS Message.");
       }
       console.log(`Processed message: ${record.body}`);
   }
   ```
使用 TypeScript 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   import { SQSEvent, SQSBatchResponse, Context, SQSBatchItemFailure, SQSRecord } from 'aws-lambda';
   
   export const handler = async (event: SQSEvent, context: Context): Promise<SQSBatchResponse> => {
       const batchItemFailures: SQSBatchItemFailure[] = [];
   
       for (const record of event.Records) {
           try {
               await processMessageAsync(record);
           } catch (error) {
               batchItemFailures.push({ itemIdentifier: record.messageId });
           }
       }
   
       return {batchItemFailures: batchItemFailures};
   };
   
   async function processMessageAsync(record: SQSRecord): Promise<void> {
       if (record.body && record.body.includes("error")) {
           throw new Error('There is an error in the SQS Message.');
       }
       console.log(`Processed message ${record.body}`);
   }
   ```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   <?php
   
   use Bref\Context\Context;
   use Bref\Event\Sqs\SqsEvent;
   use Bref\Event\Sqs\SqsHandler;
   use Bref\Logger\StderrLogger;
   
   require __DIR__ . '/vendor/autoload.php';
   
   class Handler extends SqsHandler
   {
       private StderrLogger $logger;
       public function __construct(StderrLogger $logger)
       {
           $this->logger = $logger;
       }
   
       /**
        * @throws JsonException
        * @throws \Bref\Event\InvalidLambdaEvent
        */
       public function handleSqs(SqsEvent $event, Context $context): void
       {
           $this->logger->info("Processing SQS records");
           $records = $event->getRecords();
   
           foreach ($records as $record) {
               try {
                   // Assuming the SQS message is in JSON format
                   $message = json_decode($record->getBody(), true);
                   $this->logger->info(json_encode($message));
                   // TODO: Implement your custom processing logic here
               } catch (Exception $e) {
                   $this->logger->error($e->getMessage());
                   // failed processing the record
                   $this->markAsFailed($record);
               }
           }
           $totalRecords = count($records);
           $this->logger->info("Successfully processed $totalRecords SQS records");
       }
   }
   
   $logger = new StderrLogger();
   return new Handler($logger);
   ```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures)儲存庫中設定和執行。
使用 Python 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   # SPDX-License-Identifier: Apache-2.0
   
   def lambda_handler(event, context):
       if event:
           batch_item_failures = []
           sqs_batch_response = {}
        
           for record in event["Records"]:
               try:
                   print(f"Processed message: {record['body']}")
               except Exception as e:
                   batch_item_failures.append({"itemIdentifier": record['messageId']})
           
           sqs_batch_response["batchItemFailures"] = batch_item_failures
           return sqs_batch_response
   ```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda-with-batch-item-handling)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   # SPDX-License-Identifier: Apache-2.0
   require 'json'
   
   def lambda_handler(event:, context:)
     if event
       batch_item_failures = []
       sqs_batch_response = {}
   
       event["Records"].each do |record|
         begin
           # process message
         rescue StandardError => e
           batch_item_failures << {"itemIdentifier" => record['messageId']}
         end
       end
   
       sqs_batch_response["batchItemFailures"] = batch_item_failures
       return sqs_batch_response
     end
   end
   ```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 報告 SQS 批次項目失敗。  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   use aws_lambda_events::{
       event::sqs::{SqsBatchResponse, SqsEvent},
       sqs::{BatchItemFailure, SqsMessage},
   };
   use lambda_runtime::{run, service_fn, Error, LambdaEvent};
   
   async fn process_record(_: &SqsMessage) -> Result<(), Error> {
       Err(Error::from("Error processing message"))
   }
   
   async fn function_handler(event: LambdaEvent<SqsEvent>) -> Result<SqsBatchResponse, Error> {
       let mut batch_item_failures = Vec::new();
       for record in event.payload.records {
           match process_record(&record).await {
               Ok(_) => (),
               Err(_) => batch_item_failures.push(BatchItemFailure {
                   item_identifier: record.message_id.unwrap(),
               }),
           }
       }
   
       Ok(SqsBatchResponse {
           batch_item_failures,
       })
   }
   
   #[tokio::main]
   async fn main() -> Result<(), Error> {
       run(service_fn(function_handler)).await
   }
   ```

------

如果失敗的事件未傳回佇列，請參閱 AWS 知識中心中的[如何疑難排解 Lambda 函數 SQS ReportBatchItemFailures？](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-sqs-report-batch-item-failures/)。

### 成功與失敗條件
<a name="sqs-batchfailurereporting-conditions"></a>

如果您的函數傳回下列任一項目，Lambda 會將批次視為完全成功：
+ 空白 `batchItemFailures` 清單
+ Null `batchItemFailures` 清單
+ 空白 `EventResponse`
+ Null `EventResponse`

如果您的函數傳回下列任一項目，Lambda 會將批次視為完全失敗：
+ 無效的 JSON 回應
+ 空白字串 `itemIdentifier`
+ Null `itemIdentifier`
+ 具有錯誤金鑰名稱的 `itemIdentifier`
+ 具有不存在之訊息 ID 的 `itemIdentifier` 值

### CloudWatch 指標
<a name="sqs-batchfailurereporting-metrics"></a>

若要判斷您的函數是否正確報告批次項目失敗，您可以在 Amazon CloudWatch 中監控 `NumberOfMessagesDeleted` 和 `ApproximateAgeOfOldestMessage` Amazon SQS 指標。
+ `NumberOfMessagesDeleted` 會追蹤從佇列移除的訊息數目。如果下降到 0，表示您的函數回應並未正確傳回失敗訊息。
+ `ApproximateAgeOfOldestMessage` 會追蹤最舊訊息停留在佇列中的時間長度。此指標的急劇增加可能表示您的函數並未正確傳回失敗訊息。

### 使用 Powertools 進行 AWS Lambda 批次處理器
<a name="services-sqs-batchfailurereporting-powertools"></a>

Powertools for 的批次處理器公用程式 AWS Lambda 會自動處理部分批次回應邏輯，降低實作批次失敗報告的複雜性。以下是使用批次處理器的範例：

**Python**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)。
使用 AWS Lambda 批次處理器處理 Amazon SQS 訊息。  

```
import json
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.batch import BatchProcessor, EventType, process_partial_response
from aws_lambda_powertools.utilities.data_classes import SQSEvent
from aws_lambda_powertools.utilities.typing import LambdaContext

processor = BatchProcessor(event_type=EventType.SQS)
logger = Logger()

def record_handler(record):
    logger.info(record)
    # Your business logic here
    # Raise an exception to mark this record as failed
    
def lambda_handler(event, context: LambdaContext):
    return process_partial_response(
        event=event, 
        record_handler=record_handler, 
        processor=processor,
        context=context
    )
```

**TypeScript**  
如需完整的範例和設定說明，請參閱 [batch processor documentation](https://docs.aws.amazon.com/powertools/typescript/latest/features/batch/)。
使用 AWS Lambda 批次處理器處理 Amazon SQS 訊息。  

```
import { BatchProcessor, EventType, processPartialResponse } from '@aws-lambda-powertools/batch';
import { Logger } from '@aws-lambda-powertools/logger';
import type { SQSEvent, Context } from 'aws-lambda';

const processor = new BatchProcessor(EventType.SQS);
const logger = new Logger();

const recordHandler = async (record: any): Promise<void> => {
    logger.info('Processing record', { record });
    // Your business logic here
    // Throw an error to mark this record as failed
};

export const handler = async (event: SQSEvent, context: Context) => {
    return processPartialResponse(event, recordHandler, processor, {
        context,
    });
};
```

# Amazon SQS 事件來源映射的 Lambda 參數
<a name="services-sqs-parameters"></a>

所有 Lambda 事件來源類型都會共用相同的 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 和 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 操作。但是，只有一些參數適用於 Amazon SQS。


| 參數 | 必要 | 預設 | 備註 | 
| --- | --- | --- | --- | 
|  BatchSize  |  否  |  10  |  對於標準佇列，最大值為 10,000。對於 FIFO 隊列，最大值為 10。  | 
|  已啟用  |  N  |  true  | 無  | 
|  EventSourceArn  |  Y  | N/A |  資料串流或串流消費者的 ARN  | 
|  FunctionName  |  是  | N/A  | 無  | 
|  FilterCriteria  |  N  |  N/A   |  [控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)  | 
|  FunctionResponseTypes  |  N  | N/A  |  若要讓函數報告批次中的特定失敗，請將值 `ReportBatchItemFailures` 包含在 `FunctionResponseTypes` 中。如需詳細資訊，請參閱[實作部分批次回應](services-sqs-errorhandling.md#services-sqs-batchfailurereporting)。  | 
|  MaximumBatchingWindowInSeconds  |  N  |  0  | FIFO 佇列不支援批次間隔 | 
|  ProvisionedPollerConfig  |  N  |  N/A  |  設定 SQS 事件來源映射的專用事件輪詢器數量下限 (2-200) 和上限 (2-2000)。每個輪詢器最多可處理每秒 1 MB 的輸送量和 10 個並行調用。  | 
|  ScalingConfig  |  N  |  N/A   |  [設定 Amazon SQS 事件來源的並行上限](services-sqs-scaling.md#events-sqs-max-concurrency)  | 

# 對 Amazon SQS 事件來源使用事件篩選
<a name="with-sqs-filtering"></a>

您可以使用事件篩選來控制 Lambda 將哪些記錄從串流或佇列中傳送至函數。如需事件篩選運作方式的一般資訊，請參閱[控制 Lambda 將哪些事件傳送至您的函數](invocation-eventfiltering.md)。

本節重點介紹了 Amazon SQS 事件來源的事件篩選。

**注意**  
Amazon SQS 事件來源映射僅支援依據 `body` 鍵進行篩選。

**Topics**
+ [

## Amazon SQS 事件篩選基本概念
](#filtering-SQS)

## Amazon SQS 事件篩選基本概念
<a name="filtering-SQS"></a>

假設您的 Amazon SQS 佇列包含以下 JSON 格式的訊息。

```
{
    "RecordNumber": 1234,
    "TimeStamp": "yyyy-mm-ddThh:mm:ss",
    "RequestCode": "AAAA"
}
```

此佇列的範例記錄如下所示。

```
{
    "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
    "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
    "body": "{\n "RecordNumber": 1234,\n "TimeStamp": "yyyy-mm-ddThh:mm:ss",\n "RequestCode": "AAAA"\n}",
    "attributes": {
        "ApproximateReceiveCount": "1",
        "SentTimestamp": "1545082649183",
        "SenderId": "AIDAIENQZJOLO23YVJ4VO",
        "ApproximateFirstReceiveTimestamp": "1545082649185"
        },
    "messageAttributes": {},
    "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
    "eventSource": "aws:sqs",
    "eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:my-queue",
    "awsRegion": "us-west-2"
}
```

若要根據 Amazon SQS 訊息的內容進行篩選，請使用 Amazon SQS 訊息記錄中的 `body` 金鑰。假設您只想處理 Amazon SQS 訊息中的 `RequestCode` 為 "BBBB" 的記錄。`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "body": {
        "RequestCode": [ "BBBB" ]
        }
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "body" : { "RequestCode" : [ "BBBB" ] } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:sqs:us-east-2:123456789012:my-queue \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "body" : { "RequestCode" : [ "BBBB" ] } }'
```

------

假設您希望函數僅處理 `RecordNumber` 大於 9999 的記錄。`FilterCriteria` 物件如下所示。

```
{
    "Filters": [
        {
            "Pattern": "{ \"body\" : { \"RecordNumber\" : [ { \"numeric\": [ \">\", 9999 ] } ] } }"
        }
    ]
}
```

補充說明，此處是篩選條件的 `Pattern` 在純文字 JSON 中擴展的值。

```
{
    "body": {
        "RecordNumber": [
            {
                "numeric": [ ">", 9999 ]
            }
        ]
    }
}
```

您可以使用主控台、AWS CLI 或 AWS SAM 範本新增篩選條件。

------
#### [ Console ]

若要使用主控台新增此篩選條件，請遵循 [將篩選條件標準連接至事件來源映射 (主控台)](invocation-eventfiltering.md#filtering-console) 中的指示，並針對**篩選條件標準**輸入下列字串。

```
{ "body" : { "RecordNumber" : [ { "numeric": [ ">", 9999 ] } ] } }
```

------
#### [ AWS CLI ]

若要使用 AWS Command Line Interface (AWS CLI) 來建立具有這些篩選條件標準的新事件來源映射，請執行下列命令。

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:sqs:us-east-2:123456789012:my-queue \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RecordNumber\" : [ { \"numeric\": [ \">\", 9999 ] } ] } }"}]}'
```

若要將這些篩選條件標準新增到現有事件來源映射，請執行下列命令。

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RecordNumber\" : [ { \"numeric\": [ \">\", 9999 ] } ] } }"}]}'
```

------
#### [ AWS SAM ]

若要使用 AWS SAM 新增此篩選條件，請將下列程式碼片段新增到事件來源的 YAML 範本。

```
FilterCriteria:
  Filters:
    - Pattern: '{ "body" : { "RecordNumber" : [ { "numeric": [ ">", 9999 ] } ] } }'
```

------

針對 Amazon SQS，訊息內文可以是任何字串。但是，如果您的 `FilterCriteria` 預期 `body` 為有效的 JSON 格式，這就會造成問題。反之亦然 — 如果傳入的訊息內文是有效的 JSON 格式，但您的選條件標準預期 `body` 應為純字串，則此可能會導致意外的行為。

為了避免此問題，請確定 `FilterCriteria` 中的內文格式與從佇列收到的訊息中的 `body` 之預期格式相符。篩選訊息之前，Lambda 會自動評估傳入訊息內文之格式和 `body` 的篩選條件模式之格式。如果有不相符的情形，Lambda 就會捨棄訊息。下表摘要說明此評估：


| 傳入訊息 `body` 格式 | 篩選條件模式 `body` 格式 | 產生的動作 | 
| --- | --- | --- | 
|  純文字的字串  |  純文字的字串  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 
|  純文字的字串  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  純文字的字串  |  有效的 JSON  |  Lambda 捨棄訊息。  | 
|  有效的 JSON  |  純文字的字串  |  Lambda 捨棄訊息。  | 
|  有效的 JSON  |  資料屬性沒有篩選條件模式  |  Lambda 篩選條件 (僅限其他中繼資料屬性) 會根據您的篩選條件標準而定。  | 
|  有效的 JSON  |  有效的 JSON  |  根據您的篩選條件標準之 Lambda 篩選條件。  | 

# 教學課程：搭配 Amazon SQS 使用 Lambda
<a name="with-sqs-example"></a>

在本教學課程中，您將建立一個 Lambda 函數，該函數取用 [Amazon Simple Queue Service (Amazon SQS)](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html) 佇列中的訊息。只要有新訊息加入佇列，Lambda 函數就會執行。函數會將訊息寫入 Amazon CloudWatch Logs 串流。下圖顯示可用來完成教學課程的 AWS 資源。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_resources.png)


請執行下列步驟以完成本教學課程：

1. 建立將訊息寫入 CloudWatch Logs 的 Lambda 函數。

1. 建立 Amazon SQS 佇列。

1. 建立 Lambda 事件來源映射。事件來源映射會讀取 Amazon SQS 佇列，並在新增訊息時調用 Lambda 函數。

1. 透過將訊息新增至佇列並監控 CloudWatch Logs 中的結果來測試設定。

## 先決條件
<a name="with-sqs-prepare"></a>

### 安裝 AWS Command Line Interface
<a name="install_aws_cli"></a>

如果您尚未安裝 AWS Command Line Interface，請依照[安裝或更新最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)中的步驟進行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中，使用您偏好的 Shell 和套件管理工具。

**注意**  
在 Windows 中，作業系統的內建終端不支援您常與 Lambda 搭配使用的某些 Bash CLI 命令 (例如 `zip`)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本，請[安裝適用於 Linux 的 Windows 子系統](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。

## 建立執行角色
<a name="with-sqs-create-execution-role"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_steps1.png)


[執行角色](lambda-intro-execution-role.md)是授予 Lambda 函數存取 AWS 服務 和資源許可的 AWS Identity and Access Management (IAM) 角色。若要允許函數從 Amazon SQS 中讀取項目，請連接 **AWSLambdaSQSQueueExecutionRole** 許可政策。

**建立執行角色並連接 Amazon SQS 許可政策**

1. 開啟 IAM 主控台中的[角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇 **建立角色**。

1. 針對**信任的實體類型**，請選擇 **AWS 服務**。

1. 針對**使用案例**，請選擇 **Lambda**。

1. 選擇**下一步**。

1. 在**許可政策**搜尋方塊中，輸入 **AWSLambdaSQSQueueExecutionRole**。

1. 選取 **AWSLambdaSQSQueueExecutionRole** 政策，然後選擇**下一步**。

1. 針對**角色詳細資訊**下的**角色名稱**，請輸入 **lambda-sqs-role**，然後選擇**建立角色**。

角色建立後，請記下執行角色的 Amazon Resource Name (ARN)。在後續步驟中會需要用到它。

## 建立函數
<a name="with-sqs-create-function"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_steps2.png)


建立 Lambda 函數，它處理 Amazon SQS 訊息。函數程式碼會將 Amazon SQS 的訊息內文記錄到 Amazon CloudWatch Logs。

本教學課程使用 Node.js 24 執行時間，但我們也提供其他執行時間語言的範例程式碼。您可以在下列方塊中選取索引標籤，查看您感興趣的執行期程式碼。此步驟要使用的 JavaScript 程式碼，位於 **JavaScript** 索引標籤中顯示的第一個範例。

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 來使用 SQS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
﻿using Amazon.Lambda.Core;
using Amazon.Lambda.SQSEvents;


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace SqsIntegrationSampleCode
{
    public async Task FunctionHandler(SQSEvent evnt, ILambdaContext context)
    {
        foreach (var message in evnt.Records)
        {
            await ProcessMessageAsync(message, context);
        }

        context.Logger.LogInformation("done");
    }

    private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context)
    {
        try
        {
            context.Logger.LogInformation($"Processed message {message.Body}");

            // TODO: Do interesting work based on the new message
            await Task.CompletedTask;
        }
        catch (Exception e)
        {
            //You can use Dead Letter Queue to handle failures. By configuring a Lambda DLQ.
            context.Logger.LogError($"An error occurred");
            throw;
        }

    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 Go 搭配 Lambda 來使用 SQS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration_sqs_to_lambda

import (
	"fmt"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(event events.SQSEvent) error {
	for _, record := range event.Records {
		err := processMessage(record)
		if err != nil {
			return err
		}
	}
	fmt.Println("done")
	return nil
}

func processMessage(record events.SQSMessage) error {
	fmt.Printf("Processed message %s\n", record.Body)
	// TODO: Do interesting work based on the new message
	return nil
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 Java 搭配 Lambda 來使用 SQS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;

public class Function implements RequestHandler<SQSEvent, Void> {
    @Override
    public Void handleRequest(SQSEvent sqsEvent, Context context) {
        for (SQSMessage msg : sqsEvent.getRecords()) {
            processMessage(msg, context);
        }
        context.getLogger().log("done");
        return null;
    }

    private void processMessage(SQSMessage msg, Context context) {
        try {
            context.getLogger().log("Processed message " + msg.getBody());

            // TODO: Do interesting work based on the new message

        } catch (Exception e) {
            context.getLogger().log("An error occurred");
            throw e;
        }

    }
}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/blob/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 來使用 SQS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const message of event.Records) {
    await processMessageAsync(message);
  }
  console.info("done");
};

async function processMessageAsync(message) {
  try {
    console.log(`Processed message ${message.body}`);
    // TODO: Do interesting work based on the new message
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```
使用 TypeScript 搭配 Lambda 來使用 SQS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { SQSEvent, Context, SQSHandler, SQSRecord } from "aws-lambda";

export const functionHandler: SQSHandler = async (
  event: SQSEvent,
  context: Context
): Promise<void> => {
  for (const message of event.Records) {
    await processMessageAsync(message);
  }
  console.info("done");
};

async function processMessageAsync(message: SQSRecord): Promise<any> {
  try {
    console.log(`Processed message ${message.body}`);
    // TODO: Do interesting work based on the new message
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 來使用 SQS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\InvalidLambdaEvent;
use Bref\Event\Sqs\SqsEvent;
use Bref\Event\Sqs\SqsHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler extends SqsHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws InvalidLambdaEvent
     */
    public function handleSqs(SqsEvent $event, Context $context): void
    {
        foreach ($event->getRecords() as $record) {
            $body = $record->getBody();
            // TODO: Do interesting work based on the new message
        }
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 Python 搭配 Lambda 來使用 SQS 事件。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event, context):
    for message in event['Records']:
        process_message(message)
    print("done")

def process_message(message):
    try:
        print(f"Processed message {message['body']}")
        # TODO: Do interesting work based on the new message
    except Exception as err:
        print("An error occurred")
        raise err
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 來使用 SQS 事件。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event:, context:)
  event['Records'].each do |message|
    process_message(message)
  end
  puts "done"
end

def process_message(message)
  begin
    puts "Processed message #{message['body']}"
    # TODO: Do interesting work based on the new message
  rescue StandardError => err
    puts "An error occurred"
    raise err
  end
end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 來使用 SQS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::event::sqs::SqsEvent;
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

async fn function_handler(event: LambdaEvent<SqsEvent>) -> Result<(), Error> {
    event.payload.records.iter().for_each(|record| {
        // process the record
        tracing::info!("Message body: {}", record.body.as_deref().unwrap_or_default())
    });

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

**若要建立 Node.js Lambda 函數**

1. 建立專案的目錄，然後切換至該目錄。

   ```
   mkdir sqs-tutorial
   cd sqs-tutorial
   ```

1. 將範例 JavaScript 程式碼複製到名為 `index.js` 的新檔案。

1. 使用以下 `zip` 命令建立部署套件。

   ```
   zip function.zip index.js
   ```

1. 使用 [create-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) AWS CLI 命令建立 Lambda 函數。針對 `role` 參數，輸入您之前建立的執行角色 ARN。
**注意**  
該 Lambda 函數和 Amazon SQS 佇列必須位於相同的 AWS 區域。

   ```
   aws lambda create-function --function-name ProcessSQSRecord \
   --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
   --role arn:aws:iam::111122223333:role/lambda-sqs-role
   ```

## 測試函數
<a name="with-sqs-create-test-function"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_steps3.png)


使用 `invoke` AWS CLI 命令和範例 Amazon SQS 事件手動叫用 Lambda 函數。

**使用範例事件調用 Lambda 函數**

1. 將下面的 JSON 儲存為名為 `input.json` 的檔案。此 JSON 會模擬 Amazon SQS 可能傳送至 Lambda 函數的事件，其中 `"body"` 包含佇列中的實際訊息。在此範例中，訊息為 `"test"`。  
**Example Amazon SQS 事件**  

   這是測試事件，您不需要變更訊息或帳號。

   ```
   {
       "Records": [
           {
               "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
               "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
               "body": "test",
               "attributes": {
                   "ApproximateReceiveCount": "1",
                   "SentTimestamp": "1545082649183",
                   "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                   "ApproximateFirstReceiveTimestamp": "1545082649185"
               },
               "messageAttributes": {},
               "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
               "eventSource": "aws:sqs",
               "eventSourceARN": "arn:aws:sqs:us-east-1:111122223333:my-queue",
               "awsRegion": "us-east-1"
           }
       ]
   }
   ```

1. 執行下列[叫用](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/invoke.html) AWS CLI 命令。此命令在回應中傳回 CloudWatch 日誌。如需擷取日誌的詳細資訊，請參閱[使用 存取日誌 AWS CLI](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-cli)。

   ```
   aws lambda invoke --function-name ProcessSQSRecord --payload file://input.json out --log-type Tail \
   --query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode
   ```

   如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

1. 在回應中查找 `INFO` 日誌。這是 Lambda 函數記錄訊息內文的位置。您應該會看到類似以下內容的輸出：

   ```
   2023-09-11T22:45:04.271Z	348529ce-2211-4222-9099-59d07d837b60	INFO	Processed message test
   2023-09-11T22:45:04.288Z	348529ce-2211-4222-9099-59d07d837b60	INFO	done
   ```

## 建立 Amazon SQS 佇列
<a name="with-sqs-configure-sqs"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_steps4.png)


建立 Lambda 函數可用作事件來源的 Amazon SQS 佇列。該 Lambda 函數和 Amazon SQS 佇列必須位於相同的 AWS 區域。

**建立佇列**

1. 開啟 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)。

1. 選擇**建立佇列**。

1. 輸入佇列的名稱。將所有其他選項保留為預設值。

1. 選擇**建立佇列**。

建立佇列後，請記下其 ARN。在下個步驟中，將佇列與您的 Lambda 函數建立關聯時會需要用到它。

## 設定事件來源
<a name="with-sqs-attach-notification-configuration"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_steps5.png)


透過建立[事件來源映射](invocation-eventsourcemapping.md)，將 Amazon SQS 佇列連線至 Lambda 函數。事件來源映射會讀取 Amazon SQS 佇列，並在新增訊息時調用 Lambda 函數。

若要在 Amazon SQS 佇列和 Lambda 函數之間建立映射，請使用 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) AWS CLI 命令。範例：

```
aws lambda create-event-source-mapping --function-name ProcessSQSRecord  --batch-size 10 \
--event-source-arn arn:aws:sqs:us-east-1:111122223333:my-queue
```

若要獲取事件來源映射清單，請使用 [list-event-source-mappings](https://awscli.amazonaws.com/v2/documentation/api/2.1.29/reference/lambda/list-event-source-mappings.html) 命令。範例：

```
aws lambda list-event-source-mappings --function-name ProcessSQSRecord
```

## 傳送測試訊息
<a name="with-sqs-test-message"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_steps6.png)


**將 Amazon SQS 訊息傳送至 Lambda 函數**

1. 開啟 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)。

1. 選擇您稍早建立的佇列。

1. 選擇**傳送及接收訊息**。

1. 在**訊息內文**下，輸入測試訊息，例如「這是測試訊息」。

1. 選擇**傳送訊息**。

Lambda 輪詢佇列以查看是否有更新。當有新訊息時，Lambda 會使用佇列中的此新事件資料來叫用您的函數。如果函數處理常式傳回而無例外情況，則 Lambda 會認為訊息已成功處理，並開始讀取佇列中的新訊息。成功處理訊息之後，Lambda 從佇列中自動刪除它。如果處理常式擲出例外情況，Lambda 會認為訊息批次未成功處理，並且 Lambda 會調用具有相同訊息批次的函數。

## 檢查 CloudWatch 日誌
<a name="with-sqs-check-logs"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sqs_tut_steps7.png)


**確認函數已處理訊息**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇 **ProcessSQSRecord** 函數。

1. 選擇**監控**。

1. 選擇**檢視 CloudWatch 日誌**。

1. 在 CloudWatch 主控台中，選擇函數的**日誌串流**。

1. 查找 `INFO` 日誌。這是 Lambda 函數記錄訊息內文的位置。應能看到您從 Amazon SQS 佇列傳送的訊息。範例：

   ```
   2023-09-11T22:49:12.730Z b0c41e9c-0556-5a8b-af83-43e59efeec71 INFO Processed message this is a test message.
   ```

## 清除您的資源
<a name="cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇 **刪除** 。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇 **刪除** 。

**刪除 Amazon SQS 佇列**

1. 登入 AWS 管理主控台 並開啟位於 https：//[https://console.aws.amazon.com/sqs/](https://console.aws.amazon.com/sqs/) 的 Amazon SQS 主控台。

1. 選取您建立的佇列。

1. 選擇 **刪除** 。

1. 在文字輸入欄位中輸入 **confirm**。

1. 選擇 **刪除** 。

# 教學課程：使用跨帳戶 Amazon SQS 佇列做為事件來源
<a name="with-sqs-cross-account-example"></a>

在本教學課程中，您會建立 Lambda 函數，使用來自不同 AWS 帳戶中 Amazon Simple Queue Service (Amazon SQS) 佇列的訊息。本教學課程涉及兩個 AWS 帳戶：**帳戶 A** 是指包含 Lambda 函數的帳戶，**帳戶 B** 是指包含 Amazon SQS 佇列的帳戶。

## 先決條件
<a name="with-sqs-cross-account-prepare"></a>

### 安裝 AWS Command Line Interface
<a name="install_aws_cli"></a>

如果您尚未安裝 AWS Command Line Interface，請依照[安裝或更新最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)中的步驟進行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中，使用您偏好的 Shell 和套件管理工具。

**注意**  
在 Windows 中，作業系統的內建終端不支援您常與 Lambda 搭配使用的某些 Bash CLI 命令 (例如 `zip`)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本，請[安裝適用於 Linux 的 Windows 子系統](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。

## 建立執行角色 (帳戶 A)
<a name="with-sqs-cross-account-create-execution-role"></a>

在**帳戶 A** 中，建立 [執行角色](lambda-intro-execution-role.md)，授予您的函數存取所需 AWS 資源的許可。

**若要建立執行角色**

1. 在 AWS Identity and Access Management (IAM) 主控台中開啟[角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇建**立角色**。

1. 建立具備下列屬性的角色。
   + **信任實體** – **AWS Lambda**。
   + **許可** - **AWSLambdaSQSQueueExecutionRole**
   + **角色名稱** - **cross-account-lambda-sqs-role**。

**AWSLambdaSQSQueueExecutionRole** 政策具備函數自 Amazon SQS 讀取項目以及寫入日誌到 Amazon CloudWatch Logs 時所需的許可。

## 建立函數 (帳戶 A)
<a name="with-sqs-cross-account-create-function"></a>

在**帳戶 A** 中建立 Lambda 函數，它會處理 Amazon SQS 訊息。該 Lambda 函數和 Amazon SQS 佇列必須位於相同的 AWS 區域。

下列 Node.js 程式碼範例將每則訊息寫入 CloudWatch Logs 的日誌中。

**Example index.mjs**  

```
export const handler = async function(event, context) {
  event.Records.forEach(record => {
    const { body } = record;
    console.log(body);
  });
  return {};
}
```

**建立函數**
**注意**  
遵循這些步驟，建立 Node.js 函式。對於其他語言，步驟類似，但有些細節不同。

1. 將程式碼範例儲存為名為 `index.mjs` 的檔案。

1. 建立部署套件。

   ```
   zip function.zip index.mjs
   ```

1. 使用 `create-function` AWS Command Line Interface (AWS CLI) 命令建立 函數。將 `arn:aws:iam::111122223333:role/cross-account-lambda-sqs-role` 取代為先前建立之執行角色的 ARN。

   ```
   aws lambda create-function --function-name CrossAccountSQSExample \
   --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
   --role arn:aws:iam::111122223333:role/cross-account-lambda-sqs-role
   ```

## 測試函數 (帳戶 A)
<a name="with-sqs-cross-account-create-test-function"></a>

在**帳戶 A** 中，使用 `invoke` AWS CLI 命令和範例 Amazon SQS 事件手動測試 Lambda 函數。

如果處理常式均正常傳回而無例外情況，Lambda 會認為訊息已成功處理，並開始讀取佇列中的新訊息。成功處理訊息之後，Lambda 從佇列中自動刪除它。如果處理常式擲出例外情況，Lambda 會認為訊息批次未成功處理，並且 Lambda 會調用具有相同訊息批次的函數。

1. 將下面的 JSON 儲存為名為 `input.txt` 的檔案。

   ```
   {
       "Records": [
           {
               "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
               "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
               "body": "test",
               "attributes": {
                   "ApproximateReceiveCount": "1",
                   "SentTimestamp": "1545082649183",
                   "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                   "ApproximateFirstReceiveTimestamp": "1545082649185"
               },
               "messageAttributes": {},
               "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
               "eventSource": "aws:sqs",
               "eventSourceARN": "arn:aws:sqs:us-east-1:111122223333:example-queue",
               "awsRegion": "us-east-1"
           }
       ]
   }
   ```

   上述 JSON 會模擬 Amazon SQS 可能傳送至 Lambda 函數的事件，其中 `"body"` 包含佇列中的實際訊息。

1. 執行下列 `invoke` AWS CLI 命令。

   ```
   aws lambda invoke --function-name CrossAccountSQSExample \
   --cli-binary-format raw-in-base64-out \
   --payload file://input.txt outputfile.txt
   ```

   如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

1. 在檔案 `outputfile.txt` 中確認輸出。

## 建立 Amazon SQS 佇列 (帳戶 B)
<a name="with-sqs-cross-account-configure-sqs"></a>

在**帳戶 B** 中，建立**帳戶 A** 中 Lambda 函數可用作事件來源的 Amazon SQS 佇列。該 Lambda 函數和 Amazon SQS 佇列必須位於相同的 AWS 區域。

**建立佇列**

1. 開啟 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)。

1. 選擇 **建立佇列** 。

1. 建立具備下列屬性的佇列。
   + **Type** (類型) - **Standard** (標準)
   + **Name** (名稱) - **LambdaCrossAccountQueue**
   + **Configuration** (組態) - 保留預設設定。
   + **存取政策** - 選擇**進階**。貼入下列 JSON 政策中。取代以下的值：
     + `111122223333`**帳戶 A** 的 ： AWS 帳戶 ID
     + `444455556666`**帳戶 B** 的 ： AWS 帳戶 ID

------
#### [ JSON ]

****  

     ```
     {
         "Version":"2012-10-17",		 	 	 
         "Id": "Queue1_Policy_UUID",
         "Statement": [
             {
                 "Sid": "Queue1_AllActions",
                 "Effect": "Allow",
                 "Principal": {
                     "AWS": [
                         "arn:aws:iam::111122223333:role/cross-account-lambda-sqs-role"
                     ]
                 },
                 "Action": "sqs:*",
                 "Resource": "arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue"
             }
         ]
     }
     ```

------

     此政策許可**帳戶 A** 中的 Lambda 執行角色取用此 Amazon SQS 佇列中的訊息。

1. 建立佇列後，記錄其 Amazon Resource Name (ARN)。在下個步驟中，將佇列與您的 Lambda 函數建立關聯時會需要用到它。

## 設定事件來源 (帳戶 A)
<a name="with-sqs-cross-account-event-source"></a>

在**帳戶 A** 中，執行下列`create-event-source-mapping` AWS CLI 命令，在**帳戶 B** 中的 Amazon SQS 佇列與 Lambda 函數之間建立事件來源映射。將 `arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue` 取代為您在上一個步驟中建立的 Amazon SQS 佇列 ARN。

```
aws lambda create-event-source-mapping --function-name CrossAccountSQSExample --batch-size 10 \
--event-source-arn arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue
```

若要取得事件來源映射的清單，請執行下列命令。

```
aws lambda list-event-source-mappings --function-name CrossAccountSQSExample \
--event-source-arn arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue
```

## 測試設定
<a name="with-sqs-final-integration-test-no-iam"></a>

現在您可以測試設定，如下所示：

1. 在**帳戶 B** 中，開啟 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)。

1. 選擇您先前建立的 **LambdaCrossAccountQueue**。

1. 選擇**傳送及接收訊息**。

1. 在 **Message body** (訊息主體) 中，輸入測試訊息。

1. 選擇**傳送訊息**。

**帳戶 A** 中您的 Lambda 函數應該會收到訊息。Lambda 會繼續輪詢佇列是否有更新。當有新訊息時，Lambda 會使用佇列中的此新事件資料來調用您的函數。您的函數會執行並在 Amazon CloudWatch 中建立日誌。可在 [CloudWatch 主控台](https://console.aws.amazon.com/cloudwatch)中檢視日誌。

## 清除您的資源
<a name="cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

在**帳戶 A** 中，清除您的執行角色和 Lambda 函數。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇 **刪除** 。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇 **刪除** 。

在**帳戶 B** 中，清除 Amazon SQS 佇列。

**刪除 Amazon SQS 佇列**

1. 登入 AWS 管理主控台 並開啟位於 https：//[https://console.aws.amazon.com/sqs/](https://console.aws.amazon.com/sqs/) 的 Amazon SQS 主控台。

1. 選取您建立的佇列。

1. 選擇 **刪除** 。

1. 在文字輸入欄位中輸入 **confirm**。

1. 選擇 **刪除** 。

# 使用 Step Functions 協同運作 Lambda 函式
<a name="with-step-functions"></a>

AWS Step Functions 提供視覺化工作流程協同運作，以協調 Lambda 函數與其他 AWS 服務。透過原生整合 220 種以上的 AWS 服務，以及全受管、零維護的基礎設施， Step Functions 是您需要視覺化工作流程設計和全受管服務整合時的理想選擇。

對於使用 Lambda 內工作流程邏輯與商業邏輯一起運作的標準程式設計語言進行協調，請考慮 [Lambda 耐用函數](durable-functions.md)。如需在這些選項之間進行選擇的說明，請參閱[耐用函數或 Step Functions](durable-step-functions.md)。

例如，處理訂單可能需要驗證訂單詳細資訊、檢查庫存程度、處理付款和產生發票。為每個任務編寫單獨的 Lambda 函式，並使用 Step Functions 來管理工作流程。Step Functions 會協調函式之間的資料流程，並在每個步驟中處理錯誤。這種區隔可確保工作流程即使日益複雜，也將更容易進行視覺化、修改和維護。

## 何時將 Step Functions 與 Lambda 搭配使用
<a name="when-to-use-step-functions"></a>

以下是 Step Functions 特別適合協調 Lambda 型應用程式的良好範例。
+ [循序處理](#sequential-processing)
+ [複雜錯誤處理](#complex-error-handling)
+ [條件式工作流程與人工核准](#conditional-workflows-human-approvals)
+ [平行處理](#parallel-processing)

### 循序處理
<a name="sequential-processing"></a>

循序處理是指一個任務必須完成後，下一個任務才能開始。例如，在訂單處理系統中，訂單驗證完成後才能開始付款處理，而發票產生必須等待付款確認。需要為每個任務編寫單獨的 Lambda 函式，並使用 Step Functions 來管理順序和處理函式之間的資料流程。

#### 反模式範例
<a name="anti-pattern-sequential"></a>

單一 Lambda 函式透過下列方式來管理整個訂單處理工作流程：
+ 依序調用其他 Lambda 函式
+ 剖析與驗證各函式的回應
+ 實作錯誤處理與復原邏輯
+ 管理函式之間的資料流程

#### 建議方法
<a name="recommended-sequential"></a>

使用兩個 Lambda 函式：一個用於驗證訂單，另一個用於處理付款。Step Functions 透過下列方式協調這些函式：
+ 以正確順序執行任務
+ 在函式之間傳遞資料
+ 在各步驟實作錯誤處理
+ 使用 [Choice](https://docs.aws.amazon.com/step-functions/latest/dg/state-choice.html) 狀態確保僅有效訂單能進入付款流程

**Example 工作流程圖**  

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sequential_workflow.png)


**注意**  
**程式碼優先替代方案：**如需使用程式碼型檢查點和重試的循序處理，請參閱 [Lambda 耐久函數步驟](durable-basic-concepts.md)。

### 複雜錯誤處理
<a name="complex-error-handling"></a>

儘管 Lambda [為非同步調用和事件來源映射提供重試功能](invocation-retries.md)，但 Step Functions 為複雜的工作流程提供了更精密的錯誤處理。您可以使用指數退避[設定自動重試](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html#error-handling-retrying-after-an-error)，並為不同類型的錯誤設定不同的重試政策。如果重試用盡，請使用 `Catch` 將錯誤路由至[後援狀態](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html#error-handling-fallback-states)。當您需要協調多個函式和服務的工作流程層級錯誤處理時，這尤其有用。

若要進一步了解如何在狀態機器中處理 Lambda 函數錯誤，請參閱* AWS Step Functions 研討會*中的[處理錯誤](https://catalog.workshops.aws/stepfunctions/handling-errors)。

#### 反模式範例
<a name="anti-pattern-error-handling"></a>

單一 Lambda 函式會處理下列所有項目：
+ 嘗試呼叫付款處理服務
+ 如果付款服務無法使用，函式會等待並於稍後重試。
+ 為等待時間實作自訂指數退避
+ 所有嘗試都失敗後，擷取錯誤並選擇另一個流程

#### 建議方法
<a name="recommended-error-handling"></a>

使用僅專注於付款處理的單一 Lambda 函式。Step Functions 透過下列方式管理錯誤處理：
+ [使用可設定的退避期間自動重試失敗的任務](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html#error-handling-retrying-after-an-error)
+ 根據錯誤類型套用不同的重試政策
+ 將不同類型的錯誤路由至相應的後援狀態
+ 維護錯誤處理狀態與歷史記錄

**Example 工作流程圖**  

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/error_handling_workflow.png)


**注意**  
**程式碼優先替代方案：**耐用的 函數透過可設定的重試策略提供 try-catch 錯誤處理。請參閱[耐用函數中的錯誤處理](durable-execution-sdk-retries.md)。

### 條件式工作流程與人工核准
<a name="conditional-workflows-human-approvals"></a>

使用 Step Functions 的 [Choice 狀態](https://docs.aws.amazon.com/step-functions/latest/dg/state-choice.html)，根據函式輸出路由工作流程，並使用 [waitForTaskToken 尾碼](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token)暫停工作流程以等待人工決策。例如，若要處理信用額度提高請求，可使用 Lambda 函式評估風險因素。然後，透過 Step Functions 將高風險請求路由至手動核准，將低風險請求路由至自動核准。

若要部署使用回呼任務字符整合模式的範例工作流程，請參閱* AWS Step Functions 研討會*中的[使用任務字符回呼](https://catalog.workshops.aws/stepfunctions/integrating-services/3-callback-token)。

#### 反模式範例
<a name="anti-pattern-conditional"></a>

單一 Lambda 函式透過下列方式管理複雜的核准工作流程：
+ 實作巢狀條件邏輯來評估額度請求
+ 根據請求金額調用不同的核准函式
+ 管理多個核准路徑與決策點
+ 追蹤待核准的狀態
+ 實作核准逾時與通知邏輯

#### 建議方法
<a name="recommended-conditional"></a>

使用三個 Lambda 函式：一個用於評估每筆請求的風險，一個用於核准低風險請求，另一個用於將高風險請求路由至經理以供檢閱。Step Functions 透過下列方式管理工作流程：
+ 使用 [Choice](https://docs.aws.amazon.com/step-functions/latest/dg/state-choice.html) 狀態根據金額與風險等級來路由請求
+ 在等待人工核准時暫停執行
+ 管理待核准逾時
+ 提供每個請求目前狀態的可見性

**Example 工作流程圖**  

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/conditional_workflow.png)


**注意**  
**程式碼優先替代方案：**耐用的 函數支援human-in-the-loop工作流程的回呼。請參閱[耐用函數中的回呼](durable-execution-sdk.md)。

### 平行處理
<a name="parallel-processing"></a>

Step Functions 提供三種平行處理的實作方式：
+ [平行狀態](https://docs.aws.amazon.com/step-functions/latest/dg/state-parallel.html)會同時執行工作流程的多個分支。需要平行執行不同的函式時 (例如在擷取映像中繼資料時產生縮圖)，可使用此狀態。
+ [內嵌映射狀態](https://docs.aws.amazon.com/step-functions/latest/dg/state-map-inline.html)會處理資料陣列，最多支援 40 個並行迭代。此狀態適用於需要對每個項目執行相同操作的中小型資料集。
+ [分散式映射狀態](https://docs.aws.amazon.com/step-functions/latest/dg/state-map-distributed.html)會處理大規模平行處理，最多支援 10,000 個並行執行，同時支援 JSON 陣列和 Amazon Simple Storage Service (Amazon S3) 資料來源。處理大型資料集或需要更高並行性時，可使用此狀態。

#### 反模式範例
<a name="anti-pattern-parallel"></a>

單一 Lambda 函式嘗試透過下列方式管理平行處理：
+ 同時調用多個映像處理函式
+ 實作自訂的平行執行邏輯
+ 管理各平行任務的逾時與錯誤處理
+ 收集並彙總所有函式的結果

#### 建議方法
<a name="recommended-parallel"></a>

使用三個 Lambda 函式：一個用於建立縮圖映像、一個用於新增浮水印，另一個用於擷取中繼資料。Step Functions 透過下列方式管理這些函式：
+ 使用[平行](https://docs.aws.amazon.com/step-functions/latest/dg/state-parallel.html)狀態同時執行所有函式
+ 將每個函式的結果收集到排序陣列
+ 管理所有平行執行的逾時與錯誤處理
+ 僅在所有平行分支完成後才繼續進行

**Example 工作流程圖**  

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/parallel_workflow.png)


**注意**  
**程式碼優先替代方案：**耐用的 函數提供 `parallel()`和 `map()`操作。請參閱[平行執行](durable-execution-sdk.md)。

## 不適用 Step Functions 搭配 Lambda 的時機
<a name="when-not-to-use"></a>

並非所有以 Lambda 為基礎的應用程式都能從使用 Step Functions 中受益。選擇應用程式架構時，建議考量以下案例。
+ [簡易的應用程式](#simple-applications)
+ [複雜的資料處理](#complex-data-processing)
+ [CPU 密集型工作負載](#cpu-intensive)

### 簡易的應用程式
<a name="simple-applications"></a>

**注意**  
對於不需要視覺化設計或廣泛服務整合的工作流程，[Lambda 耐用函數](durable-functions.md)可能是將工作流程邏輯保留在 Lambda 內更簡單的替代方案。

對於不需要複雜協同運作的應用程式，使用 Step Functions 可能會增加不必要的複雜性。例如，若只是處理來自 Amazon SQS 佇列的訊息或回應 Amazon EventBridge 事件，您可以將這些服務設定為直接調用 Lambda 函式。同理，如果應用程式僅包含一或兩個具有直接錯誤處理的 Lambda 函式，則 Lambda 直接調用或事件驅動型架構可能更易於部署與維護。

### 複雜的資料處理
<a name="complex-data-processing"></a>

您可以使用 Step Functions 的[分散式映射](https://docs.aws.amazon.com/step-functions/latest/dg/state-map-distributed.html)狀態，透過 Lambda 函式並行處理大型 Amazon S3 資料集。這對於許多大規模平行工作負載有效，包括處理 JSON 或 CSV 檔案等半結構化資料。但是，對於更複雜的資料轉換或進階分析，建議考量以下替代方案：
+ **資料轉換管道**： AWS Glue 用於處理來自多個來源的結構化或半結構化資料的 ETL 任務。當您需要內建資料目錄和結構描述管理功能時 AWS Glue ， 特別有用。
+ **資料分析：**針對 PB 級資料分析，可以使用 Amazon EMR，尤其是當您需要 Apache Hadoop 生態系統工具或用於超過 Lambda [記憶體](configuration-memory.md)限制的機器學習工作負載時。

### CPU 密集型工作負載
<a name="cpu-intensive"></a>

儘管 Step Functions 可以協調 CPU 密集型任務，但由於 Lambda 函式的 CPU 資源有限，可能不適合處理此類工作負載。對於工作流程中需要大量運算資源的操作，建議考量以下替代方案：
+ **容器協同運作：**使用 Step Functions 來管理 Amazon Elastic Container Service (Amazon ECS) 任務，取得更加一致且可擴展的運算資源。
+ **批次處理：** AWS Batch 與 Step Functions 整合，以管理需要持續 CPU 用量的運算密集型批次任務。

# 使用 Amazon S3 批次事件調用 Lambda 函數
<a name="services-s3-batch"></a>

您可以使用 Amazon S3 批次操作，在大型 Amazon S3 物件組合叫用 Lambda 函數。Amazon S3 會追蹤批次操作的進度、傳送通知以及儲存顯示每個動作狀態的完成報告。

若要執行批次操作，您可以建立 Amazon S3 [批次操作任務](https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops-operations.html)。當您建立任務時，請提供資訊清單 (物件清單)，並設定要在這些物件上執行的動作。

當批次任務開始時，Amazon S3 會針對資訊清單中的每個物件[同步](invocation-sync.md)叫用 Lambda 函數。事件參數包括儲存貯體和物件的名稱。

下列範例顯示 Amazon S3 針對 **amzn-s3-demo-bucket** 儲存貯體中名稱為 **customerImage1.jpg** 的物件，傳送事件至 Lambda 函數。

**Example Amazon S3 批次請求事件**  

```
{
"invocationSchemaVersion": "1.0",
    "invocationId": "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo",
    "job": {
        "id": "f3cc4f60-61f6-4a2b-8a21-d07600c373ce"
    },
    "tasks": [
        {
            "taskId": "dGFza2lkZ29lc2hlcmUK",
            "s3Key": "customerImage1.jpg",
            "s3VersionId": "1",
            "s3BucketArn": "arn:aws:s3:::amzn-s3-demo-bucket"
        }
    ]  
}
```

您的 Lambda 函數必須傳回一個 JSON 物件，並有如下例所示的欄位。您可以從事件參數複製 `invocationId` 和 `taskId`。您可以在 `resultString` 返回子串。Amazon S3 會在完成報告中儲存 `resultString` 值。

**Example Amazon S3 批次請求回應**  

```
{
  "invocationSchemaVersion": "1.0",
  "treatMissingKeysAs" : "PermanentFailure",
  "invocationId" : "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo",
  "results": [
    {
      "taskId": "dGFza2lkZ29lc2hlcmUK",
      "resultCode": "Succeeded",
      "resultString": "[\"Alice\", \"Bob\"]"
    }
  ]
}
```

## 從 Amazon S3 批次操作叫用 Lambda 函數
<a name="invoking"></a>

您可以使用不合格或合格的函數 ARN 叫用 Lambda 函數。如果您要在整個批次任務中使用相同的函數版本，請在建立任務時，在 `FunctionARN` 參數中設定特定的函數版本。如果您設定別名或 \$1LATEST 限定詞，如果在任務執行期間更新別名或 \$1LATEST，批次任務就會立即開始呼叫新版函數。

請注意，您無法重複使用現有的 Amazon S3 事件型函數進行批次操作。這是因為 Amazon S3 批次操作將不同的事件參數傳遞給 Lambda 函數，並預期傳回有特定 JSON 結構的訊息。

在您針對 Amazon S3 批次任務建立的[資源型政策](access-control-resource-based.md)中，請確認您已針對任務設定權限以叫用您的 Lambda 函數。

在函數的[執行角色](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops-iam-role-policies.html)中，針對 Amazon S3 設定信任政策以在角色執行您的函數時取得該角色。

如果您的函數使用 AWS SDK 來管理 Amazon S3 資源，您需要在執行角色中新增 Amazon S3 許可。

執行任務時，Amazon S3 會啟動多個函數執行個體以並行處理 Amazon S3 物件，直至達到函數的[並行限制](lambda-concurrency.md)。Amazon S3 會限制執行個體的初始漸進測試，以避免較小任務造成過多成本。

如果 Lambda 函數傳回 `TemporaryFailure` 回應程式碼，Amazon S3 就會重試操作。

如需 Amazon S3 批次操作的詳細資訊，請參閱 *Amazon S3 開發人員指南*中的[執行批次操作](https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops.html)。

如需如何在 Amazon S3 批次操作中使用 Lambda 函數的範例，請參閱 *Amazon S3 開發人員指南*中的[從 Amazon S3 批次操作中叫用 Lambda 函數](https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops-invoke-lambda.html)。

# 使用 Amazon SNS 通知調用 Lambda 函數
<a name="with-sns"></a>

您可以使用 Lambda 函數來處理 Amazon Simple Notification Service (Amazon SNS) 通知。Amazon SNS 支援 Lambda 函數作為傳送至主題之訊息的目標。您可以將自己的函數訂閱至相同帳戶或其他 AWS 帳戶中的主題。如需詳細演練，請參閱[教學課程： AWS Lambda 搭配 Amazon Simple Notification Service 使用](with-sns-example.md)。

Lambda 僅支援標準 SNS 主題的 SNS 觸發條件。不支援 FIFO 主題。

Lambda 透過將訊息排入佇列並處理重試，以非同步方式處理 SNS 訊息。如果 Amazon SNS 無法連接至 Lambda 或訊息遭到拒絕，Amazon SNS 會在數小時中以增加的間隔重試。如需詳細資訊，請參閱 Amazon SNS 常見問答集中的[可靠性](https://aws.amazon.com/sns/faqs/#Reliability)。

**警告**  
Lambda 非同步調用至少會處理每個事件一次，而且可能會重複處理記錄。為避免與重複事件相關的潛在問題，強烈建議您讓函數程式碼具有等冪性。如需詳細資訊，請參閱 AWS 知識中心中的[如何使 Lambda 函式具有冪等性](https://repost.aws/knowledge-center/lambda-function-idempotent)。

## Powertools for AWS Lambda 的冪等性公用程式
<a name="services-sns-powertools-idempotency"></a>

Powertools for AWS Lambda 的冪等性公用程式可讓 Lambda 函式具有冪等性。該工具組支援 Python、TypeScript、Java 與 .NET。如需詳細資訊，請參閱 *Powertools for AWS Lambda (Python) documentation* 中的 [Idempotency utility](https://docs.powertools.aws.dev/lambda/python/latest/utilities/idempotency/)、*Powertools for AWS Lambda (TypeScript) documentation* 中的 [Idempotency Utility](https://docs.aws.amazon.com/powertools/typescript/2.1.1/utilities/idempotency/)、*Powertools for AWS Lambda (Java) documentation* 中的 [Idempotency Utility](https://docs.powertools.aws.dev/lambda/java/latest/utilities/idempotency/)，以及 *Powertools for AWS Lambda (.NET) documentation* 中的 [Idempotency Utility](https://docs.powertools.aws.dev/lambda/dotnet/utilities/idempotency/)。

**Topics**
+ [

## Powertools for AWS Lambda 的冪等性公用程式
](#services-sns-powertools-idempotency)
+ [

## 使用主控台為 Lambda 函數新增 Amazon SNS 主題觸發條件
](#sns-trigger-console)
+ [

## 手動新增 Lambda 函數的 Amazon SNS 主題觸發條件
](#sns-trigger-manual)
+ [

## 範例 SNS 事件形狀
](#sns-sample-event)
+ [

# 教學課程： AWS Lambda 搭配 Amazon Simple Notification Service 使用
](with-sns-example.md)

## 使用主控台為 Lambda 函數新增 Amazon SNS 主題觸發條件
<a name="sns-trigger-console"></a>

若要新增 SNS 主題做為 Lambda 函數的觸發條件，最簡單的方法便是使用 Lambda 主控台。當您透過主控台新增觸發條件時，Lambda 會自動設定必要的許可和訂閱，以開始從 SNS 主題接收事件。

**若要新增 SNS 主題做為 Lambda 函數的觸發條件 (主控台)**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇要為其新增觸發條件的函數名稱。

1. 選擇**組態**，然後**觸發條件**。

1. 選擇 **Add trigger (新增觸發條件)**。

1. 在**觸發條件組態**底下的下拉式清單中，選擇 **SNS**。

1. 針對 **SNS 主題**，選擇要訂閱的 SNS 主題。

## 手動新增 Lambda 函數的 Amazon SNS 主題觸發條件
<a name="sns-trigger-manual"></a>

若要手動設定 Lambda 函數的 SNS 觸發條件，您需要完成以下步驟：
+ 為函數定義資源型政策，以允許 SNS 調用它。
+ 讓 Lambda 函數訂閱 Amazon SNS 主題。
**注意**  
如果 SNS 主題和 Lambda 函數位於不同的 AWS 帳戶中，您還需要授予函數額外許可，以允許跨帳戶訂閱 SNS 主題。如需詳細資訊，請參閱[跨帳戶授予 Amazon SNS 訂閱的許可](with-sns-example.md#with-sns-subscription-grant-permission)。

您可以使用 AWS Command Line Interface (AWS CLI) 來完成這兩個步驟。首先，使用以下 AWS CLI 命令，為 Lambda 函數定義資源型政策以允許 SNS 調用。請務必以您的 Lambda 函數名稱取代 `--function-name`，並以您的 SNS 主題 ARN 取代 `--source-arn` 的值。

```
aws lambda add-permission --function-name example-function \
    --source-arn arn:aws:sns:us-east-1:123456789012:sns-topic-for-lambda \
    --statement-id function-with-sns --action "lambda:InvokeFunction" \
    --principal sns.amazonaws.com
```

若要讓函數訂閱 SNS 主題，請使用以下 AWS CLI 命令。以您的 SNS 主題 ARN 取代 `--topic-arn` 的值，並以您的 Lambda 函數 ARN 取代 `--notification-endpoint` 的值。

```
aws sns subscribe --protocol lambda \
    --region us-east-1 \
    --topic-arn arn:aws:sns:us-east-1:123456789012:sns-topic-for-lambda \
    --notification-endpoint arn:aws:lambda:us-east-1:123456789012:function:example-function
```

## 範例 SNS 事件形狀
<a name="sns-sample-event"></a>

Amazon SNS 使用包含訊息和中繼資料的事件，以[非同步方](invocation-async.md)式叫用您的函數。

**Example Amazon SNS 訊息事件**  

```
{
  "Records": [
    {
      "EventVersion": "1.0",
      "EventSubscriptionArn": "arn:aws:sns:us-east-1:123456789012:sns-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
      "EventSource": "aws:sns",
      "Sns": {
        "SignatureVersion": "1",
        "Timestamp": "2019-01-02T12:45:07.000Z",
        "Signature": "tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==",
        "SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem",
        "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
        "Message": "Hello from SNS!",
        "MessageAttributes": {
          "Test": {
            "Type": "String",
            "Value": "TestString"
          },
          "TestBinary": {
            "Type": "Binary",
            "Value": "TestBinary"
          }
        },
        "Type": "Notification",
        "UnsubscribeUrl": "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&amp;SubscriptionArn=arn:aws:sns:us-east-1:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
        "TopicArn":"arn:aws:sns:us-east-1:123456789012:sns-lambda",
        "Subject": "TestInvoke"
      }
    }
  ]
}
```

# 教學課程： AWS Lambda 搭配 Amazon Simple Notification Service 使用
<a name="with-sns-example"></a>

在本教學課程中，您會在一個 中使用 Lambda 函數 AWS 帳戶 ，以個別方式訂閱 Amazon Simple Notification Service (Amazon SNS) 主題 AWS 帳戶。將訊息發佈至 Amazon SNS 主題時，Lambda 函數會讀取訊息的內容，並將其輸出到 Amazon CloudWatch Logs。若要完成本教學課程，請使用 AWS Command Line Interface (AWS CLI)。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_resources.png)


請執行下列步驟以完成本教學課程：
+ 在**帳戶 A** 中建立 Amazon SNS 主題。
+ 在**帳戶 B** 中建立 Lambda 函數，以讀取主題的訊息。
+ 在**帳戶 B** 中建立主題的訂閱。
+ 將訊息發佈至**帳戶 A** 中的 Amazon SNS 主題，並確認**帳戶 B** 中的 Lambda 函數是否有將其輸出至 CloudWatch Logs。

完成這些步驟後，您將了解如何設定 Amazon SNS 主題來調用 Lambda 函數。您也將了解如何建立 AWS Identity and Access Management (IAM) 政策，為另一個 中的資源提供叫用 Lambda AWS 帳戶 的許可。

在此教學課程中，您會使用兩種獨立的  AWS 帳戶。這些 AWS CLI 命令使用兩個名為 `accountA`和 的命名設定檔來說明這一點`accountB`，每個設定檔都設定為與不同的設定檔搭配使用 AWS 帳戶。若要了解如何將 AWS CLI 設定為使用不同的設定檔，請參閱《 第 *AWS Command Line Interface 2 版使用者指南*》中的[組態和登入資料檔案設定](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)。請務必 AWS 區域 為兩個設定檔設定相同的預設值。

如果您為兩者建立的 AWS CLI 設定檔 AWS 帳戶 使用不同的名稱，或者您使用預設設定檔和一個具名設定檔，請視需要在下列步驟中修改 AWS CLI 命令。

## 先決條件
<a name="with-sns-prereqs"></a>

### 安裝 AWS Command Line Interface
<a name="install_aws_cli"></a>

如果您尚未安裝 AWS Command Line Interface，請依照[安裝或更新最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)中的步驟進行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中，使用您偏好的 Shell 和套件管理工具。

**注意**  
在 Windows 中，作業系統的內建終端不支援您常與 Lambda 搭配使用的某些 Bash CLI 命令 (例如 `zip`)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本，請[安裝適用於 Linux 的 Windows 子系統](https://docs.microsoft.com/en-us/windows/wsl/install-win10)。

## 建立 Amazon SNS 主題 (帳戶 A)
<a name="with-sns-create-topic"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_1.png)


**若要建立 主題**
+ 在**帳戶 A** 中，使用下列 AWS CLI 命令建立 Amazon SNS 標準主題。

  ```
  aws sns create-topic --name sns-topic-for-lambda --profile accountA
  ```

  您應該會看到類似下列的輸出。

  ```
  {
      "TopicArn": "arn:aws:sns:us-west-2:123456789012:sns-topic-for-lambda"
  }
  ```

  記下主題的 Amazon Resource Name (ARN)。當您新增許可到 Lambda 函數以訂閱主題時，稍後會在教學課程中用上它。

## 建立函數執行角色 (帳戶 B)
<a name="with-sns-example-create-iam-role"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_2.png)


執行角色是授予 Lambda 函數存取 AWS 服務 和資源許可的 IAM 角色。在**帳戶 B** 建立函數前，您必須建立一個角色，該角色會授與將日誌寫入 CloudWatch Logs 的函數基本許可。我們將在稍後的步驟中新增要從 Amazon SNS 主題讀取的許可。

**若要建立執行角色**

1. 在**帳戶 B** 中開啟 IAM 主控台的[角色頁面](https://console.aws.amazon.com/iam/home#/roles)。

1. 選擇建**立角色**。

1. 針對**信任的實體類型**，請選擇 **AWS 服務**。

1. 針對**使用案例**，請選擇 **Lambda**。

1. 選擇**下一步**。

1. 透過下列步驟將基本許可政策新增至角色：

   1. 在**許可政策**搜尋方塊中，輸入 **AWSLambdaBasicExecutionRole**。

   1. 選擇**下一步**。

1. 執行下列動作來完成角色的建立：

   1. 在**角色詳細資訊**下方的**角色名稱**中輸入 **lambda-sns-role**。

   1. 選擇建**立角色**。

## 建立 Lambda 函數 (帳戶 B)
<a name="with-sns-example-create-test-function"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_3.png)


建立可處理 Amazon SQS 訊息的 Lambda 函數。函數程式碼會將每筆記錄的訊息內容記錄到 Amazon CloudWatch Logs。

本教學課程使用 Node.js 24 執行時間，但我們也提供其他執行時間語言的範例程式碼。您可以在下列方塊中選取索引標籤，查看您感興趣的執行期程式碼。此步驟要使用的 JavaScript 程式碼，位於 **JavaScript** 索引標籤中顯示的第一個範例。

------
#### [ .NET ]

**適用於 .NET 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 .NET 搭配 Lambda 來使用 SNS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
using Amazon.Lambda.Core;
using Amazon.Lambda.SNSEvents;


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace SnsIntegration;

public class Function
{
    public async Task FunctionHandler(SNSEvent evnt, ILambdaContext context)
    {
        foreach (var record in evnt.Records)
        {
            await ProcessRecordAsync(record, context);
        }
        context.Logger.LogInformation("done");
    }

    private async Task ProcessRecordAsync(SNSEvent.SNSRecord record, ILambdaContext context)
    {
        try
        {
            context.Logger.LogInformation($"Processed record {record.Sns.Message}");

            // TODO: Do interesting work based on the new message
            await Task.CompletedTask;
        }
        catch (Exception e)
        {
            //You can use Dead Letter Queue to handle failures. By configuring a Lambda DLQ.
            context.Logger.LogError($"An error occurred");
            throw;
        }
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 Go 搭配 Lambda 來使用 SNS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"fmt"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context, snsEvent events.SNSEvent) {
	for _, record := range snsEvent.Records {
		processMessage(record)
	}
	fmt.Println("done")
}

func processMessage(record events.SNSEventRecord) {
	message := record.SNS.Message
	fmt.Printf("Processed message: %s\n", message)
	// TODO: Process your record here
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 Java 搭配 Lambda 來使用 SNS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SNSEvent;
import com.amazonaws.services.lambda.runtime.events.SNSEvent.SNSRecord;


import java.util.Iterator;
import java.util.List;

public class SNSEventHandler implements RequestHandler<SNSEvent, Boolean> {
    LambdaLogger logger;

    @Override
    public Boolean handleRequest(SNSEvent event, Context context) {
        logger = context.getLogger();
        List<SNSRecord> records = event.getRecords();
        if (!records.isEmpty()) {
            Iterator<SNSRecord> recordsIter = records.iterator();
            while (recordsIter.hasNext()) {
                processRecord(recordsIter.next());
            }
        }
        return Boolean.TRUE;
    }

    public void processRecord(SNSRecord record) {
        try {
            String message = record.getSNS().getMessage();
            logger.log("message: " + message);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
```

------
#### [ JavaScript ]

**適用於 JavaScript (v3) 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/blob/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 JavaScript 搭配 Lambda 來使用 SNS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const record of event.Records) {
    await processMessageAsync(record);
  }
  console.info("done");
};

async function processMessageAsync(record) {
  try {
    const message = JSON.stringify(record.Sns.Message);
    console.log(`Processed message ${message}`);
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```
使用 TypeScript 搭配 Lambda 來使用 SNS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { SNSEvent, Context, SNSHandler, SNSEventRecord } from "aws-lambda";

export const functionHandler: SNSHandler = async (
  event: SNSEvent,
  context: Context
): Promise<void> => {
  for (const record of event.Records) {
    await processMessageAsync(record);
  }
  console.info("done");
};

async function processMessageAsync(record: SNSEventRecord): Promise<any> {
  try {
    const message: string = JSON.stringify(record.Sns.Message);
    console.log(`Processed message ${message}`);
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```

------
#### [ PHP ]

**適用於 PHP 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 PHP 搭配 Lambda 來使用 SNS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

/* 
Since native PHP support for AWS Lambda is not available, we are utilizing Bref's PHP functions runtime for AWS Lambda.
For more information on Bref's PHP runtime for Lambda, refer to: https://bref.sh/docs/runtimes/function

Another approach would be to create a custom runtime. 
A practical example can be found here: https://aws.amazon.com/blogs/apn/aws-lambda-custom-runtime-for-php-a-practical-example/
*/

// Additional composer packages may be required when using Bref or any other PHP functions runtime.
// require __DIR__ . '/vendor/autoload.php';

use Bref\Context\Context;
use Bref\Event\Sns\SnsEvent;
use Bref\Event\Sns\SnsHandler;

class Handler extends SnsHandler
{
    public function handleSns(SnsEvent $event, Context $context): void
    {
        foreach ($event->getRecords() as $record) {
            $message = $record->getMessage();

            // TODO: Implement your custom processing logic here
            // Any exception thrown will be logged and the invocation will be marked as failed

            echo "Processed Message: $message" . PHP_EOL;
        }
    }
}

return new Handler();
```

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 Python 搭配 Lambda 來使用 SNS 事件。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event, context):
    for record in event['Records']:
        process_message(record)
    print("done")

def process_message(record):
    try:
        message = record['Sns']['Message']
        print(f"Processed message {message}")
        # TODO; Process your record here
        
    except Exception as e:
        print("An error occurred")
        raise e
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 Ruby 搭配 Lambda 來使用 SNS 事件。  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event:, context:)
  event['Records'].map { |record| process_message(record) }
end

def process_message(record)
  message = record['Sns']['Message']
  puts("Processing message: #{message}")
rescue StandardError => e
  puts("Error processing message: #{e}")
  raise
end
```

------
#### [ Rust ]

**適用於 Rust 的 SDK**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在[無伺服器範例](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda)儲存庫中設定和執行。
使用 Rust 搭配 Lambda 來使用 SNS 事件。  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::event::sns::SnsEvent;
use aws_lambda_events::sns::SnsRecord;
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use tracing::info;

// Built with the following dependencies:
//  aws_lambda_events = { version = "0.10.0", default-features = false, features = ["sns"] }
//  lambda_runtime = "0.8.1"
//  tokio = { version = "1", features = ["macros"] }
//  tracing = { version = "0.1", features = ["log"] }
//  tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }

async fn function_handler(event: LambdaEvent<SnsEvent>) -> Result<(), Error> {
    for event in event.payload.records {
        process_record(&event)?;
    }
    
    Ok(())
}

fn process_record(record: &SnsRecord) -> Result<(), Error> {
    info!("Processing SNS Message: {}", record.sns.message);

    // Implement your record handling code here.

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        .with_target(false)
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

**建立函數**

1. 建立專案的目錄，然後切換至該目錄。

   ```
   mkdir sns-tutorial
   cd sns-tutorial
   ```

1. 將範例 JavaScript 程式碼複製到名為 `index.js` 的新檔案。

1. 使用以下 `zip` 命令建立部署套件。

   ```
   zip function.zip index.js
   ```

1. 執行下列 AWS CLI 命令，在**帳戶 B** 中建立 Lambda 函數。

   ```
   aws lambda create-function --function-name Function-With-SNS \
       --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
       --role arn:aws:iam::<AccountB_ID>:role/lambda-sns-role  \
       --timeout 60 --profile accountB
   ```

   您應該會看到類似下列的輸出。

   ```
   {
       "FunctionName": "Function-With-SNS",
       "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:Function-With-SNS",
       "Runtime": "nodejs24.x",
       "Role": "arn:aws:iam::123456789012:role/lambda_basic_role",
       "Handler": "index.handler",
       ...
       "RuntimeVersionConfig": {
           "RuntimeVersionArn": "arn:aws:lambda:us-west-2::runtime:7d5f06b69c951da8a48b926ce280a9daf2e8bb1a74fc4a2672580c787d608206"
       }
   }
   ```

1. 記錄函數的 Amazon Resource Name (ARN)。當您新增許可以允許 Amazon SNS 調用您的函數時，稍後會在教學課程中用上它。

## 為函數新增許可 (帳戶 B)
<a name="with-sns-create-function-permissions"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_4.png)


若要使用 Amazon SNS 調用函數，您必須在[以資源為基礎之政策](access-control-resource-based.md)的陳述式中授予許可。您可以使用 命令新增此陳述式 AWS CLI `add-permission`。

**若要授予 Amazon SNS 調用您函數的許可**
+ 在**帳戶 B** 中，針對您先前記錄的 Amazon SNS 主題，使用 ARN 執行下列 AWS CLI 命令。

  ```
  aws lambda add-permission --function-name Function-With-SNS \
      --source-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \
      --statement-id function-with-sns --action "lambda:InvokeFunction" \
      --principal sns.amazonaws.com --profile accountB
  ```

  您應該會看到類似下列的輸出。

  ```
  {
      "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":
        \"arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda\"}},
        \"Action\":[\"lambda:InvokeFunction\"],
        \"Resource\":\"arn:aws:lambda:us-east-1:<AccountB_ID>:function:Function-With-SNS\",
        \"Effect\":\"Allow\",\"Principal\":{\"Service\":\"sns.amazonaws.com\"},
        \"Sid\":\"function-with-sns\"}"
  }
  ```

**注意**  
如果具有 Amazon SNS 主題的帳戶託管在[選擇加入 AWS 區域](https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-regions.html)中，您需要在委託人中指定區域。例如，如果您使用亞太區域 (香港)的 Amazon SNS 主題，則需要為主體指定 `sns.ap-east-1.amazonaws.com`，而不是 `sns.amazonaws.com`。

## 授予 Amazon SNS 訂閱的跨帳戶許可 (帳戶 A)
<a name="with-sns-subscription-grant-permission"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_5.png)


若要讓**帳戶 B** 中的 Lambda 函數訂閱您在**帳戶 A** 中建立的 Amazon SNS 主題，您必須向**帳戶 B** 授予訂閱您主題的許可。您可以使用 AWS CLI `add-permission`命令授予此許可。

**若要向帳戶 B 授予訂閱主題的許可**
+ 在**帳戶 A** 中，執行下列 AWS CLI 命令。將 ARN 用於之前記錄的 Amazon SNS 主題。

  ```
  aws sns add-permission --label lambda-access --aws-account-id <AccountB_ID> \
      --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \  
      --action-name Subscribe ListSubscriptionsByTopic --profile accountA
  ```

## 建立訂閱 (帳戶 B)
<a name="with-sns-create-subscription"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_6.png)


在**帳戶 B** 中，您現在讓 Lambda 函數訂閱您在教學課程開始時透過**帳戶 A** 建立的 Amazon SNS 主題。當訊息傳送至此主題 (`sns-topic-for-lambda`) 時，Amazon SNS 會調用您**帳戶 B** 中的 Lambda 函數 `Function-With-SNS`。

**若要建立訂閱**
+ 在**帳戶 B** 中，執行下列 AWS CLI 命令。使用您建立主題的預設區域，以及主題和 Lambda 函數的 ARN。

  ```
  aws sns subscribe --protocol lambda \
      --region us-east-1 \
      --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \
      --notification-endpoint arn:aws:lambda:us-east-1:<AccountB_ID>:function:Function-With-SNS \
      --profile accountB
  ```

  您應該會看到類似下列的輸出。

  ```
  {
      "SubscriptionArn": "arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda:5d906xxxx-7c8x-45dx-a9dx-0484e31c98xx"
  }
  ```

## 將訊息發佈至主題 (帳戶 A 和帳戶 B)
<a name="with-sns-publish-message"></a>

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_7.png)


**帳戶 B** 中的 Lambda 函數已訂閱您**帳戶 A** 中的 Amazon SNS 主題後，是時候將訊息發佈至您的主題來測試您的設定了。若要確認 Amazon SNS 是否已調用 Lambda 函數，請使用 CloudWatch Logs 來檢視函數的輸出。

**若要將訊息發佈到您的主題並檢視函數的輸出**

1. 輸入 `Hello World` 至文字檔，並儲存為 `message.txt`。

1. 從您儲存文字檔案的相同目錄中，在**帳戶 A** 中執行下列 AWS CLI 命令。 針對您自己的主題使用 ARN。

   ```
   aws sns publish --message file://message.txt --subject Test \
       --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \
       --profile accountA
   ```

   這將傳回具有唯一識別符的訊息 ID，表示 Amazon SNS 已接受訊息。接著，Amazon SNS 會嘗試將訊息傳遞給主題訂閱者。若要確認 Amazon SNS 是否已調用 Lambda 函數，請使用 CloudWatch Logs 來檢視函數的輸出：

1. 在**帳戶 B**中開啟 Amazon CloudWatch 主控台的[日誌群組](https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups)頁面。

1. 為函數 (`/aws/lambda/Function-With-SNS`) 選擇日誌群組名稱。

1. 選擇最新的日誌串流。

1. 如果您的函數有被正確調用，您將會看到類似下方的輸出，顯示您發佈到主題的訊息內容。

   ```
   2023-07-31T21:42:51.250Z c1cba6b8-ade9-4380-aa32-d1a225da0e48 INFO Processed message Hello World
   2023-07-31T21:42:51.250Z c1cba6b8-ade9-4380-aa32-d1a225da0e48 INFO done
   ```

## 清除您的資源
<a name="cleanup"></a>

除非您想要保留為此教學課程建立的資源，否則您現在便可刪除。透過刪除您不再使用 AWS 的資源，您可以避免不必要的 費用 AWS 帳戶。

在**帳戶 A** 中，清除您的 Amazon SNS 主題。

**刪除 Amazon SNS 主題**

1. 在 Amazon SNS 主控台開啟 [Topics (主題) 頁面](https://console.aws.amazon.com//sns/home#topics:)。

1. 選擇您建立的主題。

1. 選擇 **刪除** 。

1. 在文字輸入欄位中輸入 **delete me**。

1. 選擇 **刪除** 。

在**帳戶 B** 中，清除您的執行角色、Lambda 函數以及 Amazon SNS 訂閱。

**刪除執行角色**

1. 開啟 IAM 主控台中的 [角色頁面](https://console.aws.amazon.com/iam/home#/roles) 。

1. 選取您建立的執行角色。

1. 選擇**刪除**。

1. 在文字輸入欄位中輸入角色的名稱，然後選擇 **刪除** 。

**若要刪除 Lambda 函數**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇您建立的函數。

1. 選擇 **Actions** (動作)、**Delete** (刪除)。

1. 在文字輸入欄位中輸入 **confirm**，然後選擇 **刪除** 。

**刪除 Amazon SNS 訂閱**

1. 在 Amazon SNS 主控台開啟 [Subscriptions (訂閱) 頁面](https://console.aws.amazon.com//sns/home#subscriptions:)。

1. 選取您建立的訂閱。

1. 選擇**刪除**，**刪除**。