

# 获取 Lambda 异步调用记录
<a name="invocation-async-retain-records"></a>

Lambda 可以将异步调用记录发送给以下某个 AWS 服务。
+ **Amazon SQS** – 标准 SQS 队列
+ **Amazon SNS** – 标准 SNS 主题
+ **Amazon S3** – Amazon S3 存储桶（仅限失败时）
+ **AWS Lambda** – Lambda 函数
+ **Amazon EventBridge** – EventBridge 事件总线

调用记录包含有关 JSON 格式的请求和响应的详细信息。您可为成功处理的事件以及处理尝试失败的事件配置单独的目标。或者，您可以将标准 Amazon SQS 队列或标准 Amazon SNS 主题配置为丢弃事件的死信队列。对于死信队列，Lambda 只发送事件的内容，不包含有关响应的详细信息。

如果 Lambda 无法向您配置的目的地发送记录，它会向 Amazon CloudWatch 发送 `DestinationDeliveryFailures` 指标。如果您的配置包含不支持的目标类型，例如 Amazon SQS FIFO 队列或 Amazon SNS FIFO 主题，则可能会发生这种情况。权限误配和大小限制可能会导致发生传输错误。有关 Lambda 调用指标的更多信息，请参阅 [调用指标](monitoring-metrics-types.md#invocation-metrics)。

**注意**  
要防止触发函数，可以将函数的预留并发设置为零。当您将异步调用函数的预留并发设置为零时，Lambda 会开始将新事件发送到已配置的[死信队列](#invocation-dlq)或失败时的[事件目标](#invocation-async-destinations)，且不会做出任何重试。要处理在预留并发设置为零时发送的事件，您必须使用死信队列或失败时事件目标中的事件。

## 添加目标
<a name="invocation-async-destinations"></a>

要保留异步调用的记录，请向函数添加目标。您可以选择将成功或失败的调用发送到目标。每个函数可以有多个目标，因此您可以为成功和失败的事件配置不同的目标。发送到目标的每条记录都是一个 JSON 文档，其中包含有关调用的详细信息。与错误处理设置一样，您可以在函数版本或别名上配置目标。

**提示**  
您还可以保留以下事件源映射类型的失败调用记录：[Amazon Kinesis](kinesis-on-failure-destination.md#kinesis-on-failure-destination-console)、[Amazon DynamoDB](services-dynamodb-errors.md) 和 [Apache Kafka（Amazon MSK 和自托管式 Apache Kafka）](kafka-on-failure.md#kafka-onfailure-destination)。<a name="destinations-permissions"></a>

下表列出了 Lambda 支持的异步调用记录目标。要让 Lambda 成功将记录发送到您选择的目标，请确保函数的[执行角色](lambda-intro-execution-role.md)也包含相关权限。该表还描述了每种目标类型如何接收 JSON 调用记录。


| 目标类型 | 所需的权限 | 特定于目标的 JSON 格式 | 
| --- | --- | --- | 
|  Amazon SQS 队列  |  [sqs:SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)  |  Lambda 将调用记录作为 `Message` 传递到目标。  | 
|  Amazon SNS 主题  |  [sns:Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html)  |  Lambda 将调用记录作为 `Message` 传递到目标。  | 
|  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_ListObjectsV2.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/invocation-async-retain-records.html)  | 
|  Lambda 函数  |  [lambda:InvokeFunction](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html)  |  Lambda 将调用记录作为有效负载传递给函数。  | 
|  EventBridge  |  [events:PutEvents](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutEvents.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/invocation-async-retain-records.html)  | 

**注意**  
对于 Amazon S3 目标，如果您已使用 KMS 密钥对存储桶启用加密，则您的函数还需要 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) 权限。

**重要**  
使用 Amazon SNS 作为目的地时，请注意，Amazon SNS 的最大消息大小限为 256 KB。如果异步调用有效载荷接近 1 MB，则调用记录（包括原始有效载荷加上其他元数据）可能会超过 Amazon SNS 限制并导致传输失败。对于较大的有效载荷，可考虑使用 Amazon SQS 或 Amazon S3 目的地。

以下步骤介绍如何使用 Lambda 控制台和 AWS CLI 配置函数的目标。

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

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择函数。

1. 在 **Function overview (函数概览)** 下，选择 **Add destination (添加目标)**。

1. 对于 **Source (源)**，选择 **Asynchronous invocation (异步调用)**。

1. 对于 **Condition (条件)**，请从以下选项中选择：
   + **On failure**（失败时）– 当事件的所有处理尝试均失败或超过最长期限时发送记录。
   + **On success**（成功时）– 函数成功处理异步调用时发送记录。

1. 对于 **Destination type (目标类型)**，请选择接收调用记录的资源类型。

1. 对于 **Destination (目标)**，请选择一个资源。

1. 选择**保存**。

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

要使用 AWS CLI 配置目标，请运行 [update-function-event-invoke-config](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-event-invoke-config.html) 命令。以下示例配置 Lambda，以便在无法处理事件时将记录发送到名为 `destination` 的标准 SQS 队列。

```
aws lambda update-function-event-invoke-config \
  --function-name my-function \
  --destination-config '{"OnFailure":{"Destination": "arn:aws:sqs:us-east-1:123456789012:destination"}}'
```

------

### Amazon S3 目标的安全最佳实践
<a name="s3-destination-security"></a>

如果删除配置为目标的 S3 存储桶而不将目标从函数配置中删除，则可能会造成安全风险。如果其他用户知道您的目标存储桶的名称，则他们可以在其 AWS 账户中重新创建存储桶。调用失败的记录将发送到存储桶，这可能会暴露您函数中的数据。

**警告**  
为确保您的函数中的调用记录不会发送到另一个 AWS 账户中的 S3 存储桶，请向函数的执行角色添加条件，以将 `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. 打开 Lamba 控制台的[函数](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
   ```

------

### 调用记录的示例
<a name="destination-example-record"></a>

当调用与条件匹配时，Lambda 会向目标发送包含调用详细信息的 [JSON 文档](#destinations-permissions)。以下示例显示了由于函数错误而导致三次处理尝试失败的事件的调用记录。

**Example**  

```
{
    "version": "1.0",
    "timestamp": "2019-11-14T18:16:05.568Z",
    "requestContext": {
        "requestId": "e4b46cbf-b738-xmpl-8880-a18cdf61200e",
        "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:my-function:$LATEST",
        "condition": "RetriesExhausted",
        "approximateInvokeCount": 3
    },
    "requestPayload": {
        "ORDER_IDS": [
            "9e07af03-ce31-4ff3-xmpl-36dce652cb4f",
            "637de236-e7b2-464e-xmpl-baf57f86bb53",
            "a81ddca6-2c35-45c7-xmpl-c3a03a31ed15"
        ]
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "responsePayload": {
        "errorMessage": "RequestId: e4b46cbf-b738-xmpl-8880-a18cdf61200e Process exited before completing request"
    }
}
```

调用记录包含有关事件、响应和记录发送原因的详细信息。

### 追踪发往目的地的请求
<a name="destinations-tracing"></a>

在每个请求排队、由 Lambda 函数处理并传递到目标服务时，您可以使用 AWS X-Ray 查看每个请求的连接视图。当您为调用函数的函数或服务激活 X-Ray 跟踪时，Lambda 会向请求添加 X-Ray 标头并将标头传递给目标服务。来自上游服务的跟踪会自动链接到下游 Lambda 函数的跟踪，从而创建整个应用程序的端到端视图。有关跟踪的更多信息，请参阅 [使用 AWS X-Ray 可视化 Lambda 函数调用](services-xray.md)。

## 添加死信队列
<a name="invocation-dlq"></a>

作为[失败时的目标](#invocation-async-destinations)的替代，您可以使用死信队列配置函数，以保存丢弃的事件供进一步处理。死信队列的作用与失败时的目标相同，在某个事件的所有处理尝试都失败或者已过期而未处理时使用。但是，您只能在函数级别添加或删除死信队列。函数版本使用与未发布的版本（\$1LATEST）相同的死信队列设置。失败时的目标还支持其他目标，并在调用记录中包含有关函数响应的详细信息。

要重新处理死信队列中的事件，您可以将其设置为 Lambda 函数的[事件源](invocation-eventsourcemapping.md)。或者，您也可以手动检索事件。

您可以为死信队列选择 Amazon SQS 标准队列或 Amazon SNS 标准主题。不支持 FIFO 队列和 Amazon SNS FIFO 主题。
+ [Amazon SQS 队列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-create-queue.html) – 队列会保存失败的事件，直到检索这些事件为止。如果您希望单个实体（例如 Lambda 函数或 CloudWatch 告警）来处理失败事件，请选择 Amazon SQS 标准队列。有关更多信息，请参阅 [将 Lambda 与 Amazon SQS 结合使用](with-sqs.md)。
+ [Amazon SNS 主题](https://docs.aws.amazon.com/sns/latest/gsg/CreateTopic.html) – 主题将失败的事件中继到一个或多个目标。如果您希望多个实体对失败事件采取行动，请选择 Amazon SNS 标准主题。例如，您可以配置主题以将事件发送到电子邮件地址、Lambda 函数或 HTTP 端点。有关更多信息，请参阅 [使用 Amazon SNS 通知调用 Lambda 函数](with-sns.md)。

要将事件发送到队列或主题，您的函数需要其他权限。添加具有函数[执行角色](lambda-intro-execution-role.md)[所需权限](#destinations-permissions)的策略。如果已使用客户自主管理型 AWS KMS 密钥加密目标队列或主题，则请确保您的函数的执行角色和密钥[基于资源的策略](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html)都包含相关权限。

创建目标并更新函数的执行角色后，将死信队列添加到函数中。您可以配置多个函数，以便将事件发送到同一目标。

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

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择函数。

1. 选择 **Configuration（配置）**，然后选择 **Asynchronous invocation（异步调用）**。

1. 在 **Asynchronous invocation (异步调用)** 下，选择 **Edit (编辑)**。

1. 将**死信队列服务**设置为 **Amazon SQS** 或 **Amazon SNS**。

1. 选择目标队列或主题。

1. 选择**保存**。

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

要通过 AWS CLI 配置死信队列，请使用 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) 命令。

```
aws lambda update-function-configuration \
  --function-name my-function \
  --dead-letter-config TargetArn=arn:aws:sns:us-east-1:123456789012:my-topic
```

------

Lambda 按原样将事件发送到死信队列，并在属性中包含其他信息。您可以使用此信息来标识函数返回的错误，或者将事件与日志或 AWS X-Ray 跟踪相关联。

**死信队列消息属性**
+ **RequestID**（字符串）– 调用请求的 ID。请求 ID 显示在函数日志中。您还可以使用 X-Ray 开发工具包，在跟踪中的属性上记录请求 ID。然后，可以在 X-Ray 控制台中按请求 ID 搜索跟踪。
+ **ErrorCode**（数字）– HTTP 状态代码。
+ **ErrorMessage**（字符串）– 错误消息的第一个 1 KB 文本块。

如果 Lambda 无法向死信队列发送消息，则会删除该事件并发出 [DeadLetterErrors](monitoring-metrics-types.md) 指标。之所以发生这种情况，可能是由于缺少权限，或者消息的总大小超过目标队列或主题的限制。例如，假设正文大小接近 1 MB 的 Amazon SNS 通知触发了一个导致错误的函数。在这种情况下，Amazon SNS 添加的事件数据加上 Lambda 添加的属性，可能会导致消息超过死信队列中允许的最大大小。

如果您正在使用 Amazon SQS 作为事件源，请在 Amazon SQS 队列本身而不是 Lambda 函数上配置死信队列。有关更多信息，请参阅 [将 Lambda 与 Amazon SQS 结合使用](with-sqs.md)。