

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

# 使用 Lambda 函数作为应用程序负载均衡器的目标
<a name="lambda-functions"></a>

您可以将 Lambda 函数注册为目标并将侦听器规则配置为将请求转发到 Lambda 函数的目标组。当负载均衡器将请求转发到目标组并使用 Lambda 函数作为目标时，它会调用 Lambda 函数并以 JSON 格式将请求内容传递到 Lambda 函数。

负载均衡器会直接调用 Lambda 函数，而不使用网络连接。因此，对应用程序负载均衡器安全组的出站规则没有要求。

**限制**
+ Lambda 函数和目标组必须位于同一账户中，且位于同一区域中。
+ 您可以发送到 Lambda 函数的请求正文的最大大小为 1 MB。有关相关大小限制，请参阅 [HTTP 标头限制](https://docs.aws.amazon.com/elasticloadbalancing/latest/userguide/how-elastic-load-balancing-works.html#http-header-limits)。
+ Lambda 函数可以发送的响应 JSON 的最大大小为 1 MB。
+ WebSockets 不支持。升级请求被拒绝，并显示 HTTP 400 代码。
+ 不支持本地区域。
+ 不支持自动目标权重（ATW）。

**Topics**
+ [准备 Lambda 函数](#prepare-lambda-function)
+ [为 Lambda 函数创建目标组](#create-lambda-target-group)
+ [从负载均衡器接收事件](#receive-event-from-load-balancer)
+ [响应负载均衡器](#respond-to-load-balancer)
+ [多值标头](#multi-value-headers)
+ [启用运行状况检查](#enable-health-checks-lambda)
+ [注册 Lambda 函数](#register-lambda-function)
+ [注销 Lambda 函数](#deregister-lambda-function)

有关演示，请参阅 [Application Load Balancer 上的 Lambda 目标](https://exampleloadbalancer.com/lambda_demo.html)。

## 准备 Lambda 函数
<a name="prepare-lambda-function"></a>

如果您将 Lambda 函数与 Application Load Balancer 一起使用，则以下建议适用。

**调用 Lambda 函数的权限**  
如果使用 AWS 管理控制台创建目标组并注册 Lambda 函数，控制台会代表您将所需的权限添加到 Lambda 函数策略。否则，在创建目标组并使用注册函数后，必须使用[添加权限](https://docs.aws.amazon.com/cli/latest/reference/lambda/add-permission.html)命令授予 Elastic Load Balancing 调用您的 Lambda 函数的权限。 AWS CLI我们建议您使用 `aws:SourceAccount` 和 `aws:SourceArn` 条件键限制对指定目标组的函数调用。有关更多信息，请参阅 *IAM 用户指南*中的[混淆代理人问题](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)。

```
aws lambda add-permission \
    --function-name lambda-function-arn-with-alias-name \ 
    --statement-id elb1 \
    --principal elasticloadbalancing.amazonaws.com \
    --action lambda:InvokeFunction \
    --source-arn target-group-arn \
    --source-account target-group-account-id
```

**Lambda 函数版本控制**  
您可以为每个目标组注册一个 Lambda 函数。为确保您可以更改 Lambda 函数并且负载均衡器始终调用当前版本的 Lambda 函数，请在向负载均衡器注册 Lambda 函数时创建一个函数别名并在函数 ARN 中包含该别名。有关更多信息，请参阅《AWS Lambda 开发人员指南》中的 [AWS Lambda 函数别名](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html)**。

**函数超时**  
负载均衡器会一直等待，直到您的 Lambda 函数响应或超时。建议您根据预期运行时间配置 Lambda 函数的超时。有关默认超时值以及如何更改该值的信息，请参阅[配置 Lambda 函数超时](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html)。有关可配置的最大超时值的信息，请参阅 [AWS Lambda 限额](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html)。

## 为 Lambda 函数创建目标组
<a name="create-lambda-target-group"></a>

创建一个要在请求路由中使用的目标组。如果请求内容与侦听器规则匹配并且具有将该内容转发到此目标组的操作，则负载均衡器会调用已注册的 Lambda 函数。

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

**创建目标组并注册 Lambda 函数**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格上的 **Load Balancing** (负载均衡) 下，选择 **Target Groups** (目标组)。

1. 选择 **Create target group (创建目标组)**。

1. 对于**选择目标类型**，选择 **Lambda 函数**。

1. 对于**目标组名称**，输入目标组的名称。

1. （可选）要启用运行状况检查，请在 **Health checks**（运行状况检查）部分中选择 **Enable**（启用）。

1. （可选）展开**标签**。对于每个标签，请选择**添加新标签**，然后输入标签键和标签值。

1. 选择**下一步**。

1. 如果您已准备好注册该 Lambda 函数，请选中**选择一个 Lambda 函数**并从列表中选择该 Lambda 函数，或者选择**输入 Lambda 函数 ARN** 并输入该 Lambda 函数的 ARN，

   如果您还没有准备好注册该 Lambda 函数，请选择**稍后注册 Lambda 函数**，以后再注册目标。有关更多信息，请参阅 [注册目标](target-group-register-targets.md#register-targets)。

1. 选择**创建目标组**。

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

**创建 lambda 类型的目标组**  
使用 [create-target-group](https://docs.aws.amazon.com/cli/latest/reference/elbv2/create-target-group.html) 命令。

```
aws elbv2 create-target-group \
    --name my-target-group \
    --target-type lambda
```

**注册 Lambda 函数**  
使用 [register-targets](https://docs.aws.amazon.com/cli/latest/reference/elbv2/register-targets.html) 命令。

```
aws elbv2 register-targets \
    --target-group-arn target-group-arn \
    --targets Id=lambda-function-arn
```

------
#### [ CloudFormation ]

**创建目标组并注册 Lambda 函数**  
定义类型为的资源[AWS::ElasticLoadBalancingV2::TargetGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html)。如果您现在还没有准备好注册该 Lambda 函数，则可以省略 `Targets` 属性，以后再添加。

```
Resources:
  myTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Name: my-target-group
      TargetType: lambda
      Tags: 
        - Key: 'department'
          Value: '123'
      Targets:
        - Id: !Ref myLambdaFunction
```

------

## 从负载均衡器接收事件
<a name="receive-event-from-load-balancer"></a>

负载均衡器支持通过 HTTP 和 HTTPS 进行请求的 Lambda 调用。负载均衡器采用 JSON 格式发送事件。负载均衡器将以下标头添加到每个请求：`X-Amzn-Trace-Id`、`X-Forwarded-For`、`X-Forwarded-Port` 和 `X-Forwarded-Proto`。

如果 `content-encoding` 标头存在，负载均衡器会对正文进行 Base64 编码并将 `isBase64Encoded` 设置为 `true`。

如果 `content-encoding` 标头不存在，Base64 编码取决于内容类型。对于以下类型，负载均衡器按原样发送正文并将其设置`isBase64Encoded`为`false`：text/\$1,。application/json, application/javascript, and application/xml否则，负载均衡器会对正文进行 Base64 编码并将 `isBase64Encoded` 设置为 `true`。

以下是示例事件。

```
{
    "requestContext": {
        "elb": {
            "targetGroupArn": "arn:aws:elasticloadbalancing:region:123456789012:targetgroup/my-target-group/6d0ecf831eec9f09"
        }
    },
    "httpMethod": "GET",
    "path": "/",
    "queryStringParameters": {parameters},
    "headers": {
        "accept": "text/html,application/xhtml+xml",
        "accept-language": "en-US,en;q=0.8",
        "content-type": "text/plain",
        "cookie": "cookies",
        "host": "lambda-846800462-us-east-2.elb.amazonaws.com",
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6)",
        "x-amzn-trace-id": "Root=1-5bdb40ca-556d8b0c50dc66f0511bf520",
        "x-forwarded-for": "72.21.198.66",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https"
    },
    "isBase64Encoded": false,
    "body": "request_body"
}
```

## 响应负载均衡器
<a name="respond-to-load-balancer"></a>

来自 Lambda 函数的响应必须包含 Base64 编码状态、状态代码和标头。您可以省略正文。

要在响应的正文中包含二进制内容，您必须对内容进行 Base64 编码并将 `isBase64Encoded` 设置为 `true`。负载均衡器解码内容以检索二进制内容并将该内容发送到 HTTP 响应的正文中的客户端。

负载均衡器不支持 hop-by-hop标头，例如`Connection`或`Transfer-Encoding`。您可以省略 `Content-Length` 标头，因为负载均衡器会在将响应发送到客户端之前计算它。

以下是来自基于 **nodejs** 的 Lambda 函数的示例响应。

```
{
    "isBase64Encoded": false,
    "statusCode": 200,
    "statusDescription": "200 OK",
    "headers": {
        "Set-cookie": "cookies",
        "Content-Type": "application/json"
    },
    "body": "Hello from Lambda (optional)"
}
```

有关与应用程序负载均衡器配合使用的 Lambda 函数模板，请参阅 github 上的 [application-load-balancer-serverless-](https://github.com/aws/elastic-load-balancing-tools/tree/master/application-load-balancer-serverless-app) app。或者，打开 [Lambda 控制台](https://console.aws.amazon.com/lambda)，依次选择**应用程序**、**创建应用程序**，然后从  AWS Serverless Application Repository 中选择下列项目之一:
+ alb-Lambda-target-S UploadFileto
+ alb-lambda-targe BinaryResponse
+ alb-Lambda-target-IP WhatisMy

## 多值标头
<a name="multi-value-headers"></a>

如果来自客户端的请求或来自 Lambda 函数的响应包含具有多个值的标头或多次包含同一标头，或包含同一键具有多个值的查询参数，则可启用对多值标头语法的支持。启用多值标头后，负载均衡器和 Lambda 函数之间交换的标头和查询参数将使用数组而不是字符串。如果您没有启用多值标头语法，并且标头或查询参数具有多个值，则负载均衡器将使用其收到的最后一个值。

**Topics**
+ [包含多值标头的请求](#multi-value-headers-request)
+ [包含多值标头的响应](#multi-value-headers-response)
+ [启用多值标头](#enable-multi-value-headers)

### 包含多值标头的请求
<a name="multi-value-headers-request"></a>

用于标头和查询字符串参数的字段名称根据是否为目标组启用了多值标头而有所不同。

以下示例请求具有两个查询参数和同一个键：

```
http://www.example.com?&myKey=val1&myKey=val2
```

对于默认格式，负载均衡器将使用客户端发送的最后一个值，并使用 `queryStringParameters` 向您发送包含查询字符串参数的事件。例如：

```
"queryStringParameters": { "myKey": "val2"},
```

如果启用了多值标头，则负载平衡器将使用客户端发送的两个键值，并使用 `multiValueQueryStringParameters` 向您发送包含查询字符串参数的事件。例如：

```
"multiValueQueryStringParameters": { "myKey": ["val1", "val2"] },
```

同样，假设客户端发送标头中包含两个 Cookie 的请求：

```
"cookie": "name1=value1",
"cookie": "name2=value2",
```

对于默认格式，负载均衡器将使用客户端发送的最后一个 Cookie，并使用 `headers` 向您发送包含标头的事件。例如：

```
"headers": {
    "cookie": "name2=value2",
    ...
},
```

如果启用了多值标头，负载均衡器将使用客户端发送的两个 Cookie 并使用 `multiValueHeaders` 向您发送包含标头的事件。例如：

```
"multiValueHeaders": {
    "cookie": ["name1=value1", "name2=value2"],
    ...
},
```

如果查询参数是 URL 编码的，则负载均衡器不会对它们进行解码。您必须在 Lambda 函数中对它们进行解码。

### 包含多值标头的响应
<a name="multi-value-headers-response"></a>

用于标头的字段名称根据是否为目标组启用了多值标头而有所不同。如果启用了多值标头，则必须使用 `multiValueHeaders`，否则使用 `headers`。

对于默认格式，您可以指定单个 Cookie：

```
{
  "headers": {
      "Set-cookie": "cookie-name=cookie-value;Domain=myweb.com;Secure;HttpOnly",
      "Content-Type": "application/json"
  },
}
```

如果启用了多值标头，您必须指定多个 Cookie，如下所示：

```
{
  "multiValueHeaders": {
      "Set-cookie": ["cookie-name=cookie-value;Domain=myweb.com;Secure;HttpOnly","cookie-name=cookie-value;Expires=May 8, 2019"],
      "Content-Type": ["application/json"]
  },
}
```

负载均衡器向客户端发送标头时所遵循的顺序可能与 Lambda 响应负载中指定的顺序不同。因此，不要指望按特定顺序返回标头。

### 启用多值标头
<a name="enable-multi-value-headers"></a>

您可以对目标类型为 `lambda` 的目标组启用或禁用多值标头。

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

**启用多值标头**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格上的**负载均衡**下，选择**目标组**。

1. 选择目标组的名称以打开其详细信息页面。

1. 在 **Attributes**（属性）选项卡上，选择 **Edit**（编辑）。

1. 启用**多值标头**。

1. 选择**保存更改**。

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

**启用多值标头**  
使用带 `lambda.multi_value_headers.enabled` 属性的 [modify-target-group-attributes](https://docs.aws.amazon.com/cli/latest/reference/elbv2/modify-target-group-attributes.html) 命令。

```
aws elbv2 modify-target-group-attributes \
    --target-group-arn target-group-arn \
    --attributes "Key=lambda.multi_value_headers.enabled,Value=true"
```

------
#### [ CloudFormation ]

**启用多值标头**  
更新[AWS::ElasticLoadBalancingV2::TargetGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html)资源以包含该`lambda.multi_value_headers.enabled`属性。

```
Resources:
  myTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Name: my-target-group
      TargetType: lambda
      Tags: 
        - Key: 'department'
          Value: '123'
      Targets:
        - Id: !Ref myLambdaFunction
      TargetGroupAttributes:
        - Key: "lambda.multi_value_headers.enabled"
          Value: "true"
```

------

## 启用运行状况检查
<a name="enable-health-checks-lambda"></a>

默认情况下，对类型为 `lambda` 的目标组禁用运行状况检查。您可以启用运行状况检查，以便通过 Amazon Route 53 实施 DNS 故障转移。Lambda 函数可以在响应运行状况检查请求之前检查下游服务的运行状况。如果来自 Lambda 函数的响应指示运行状况检查失败，则运行状况检查失败会传递到 Route 53。您可以将 Route 53 配置为故障转移到备份应用程序堆栈。

您需要支付运行状况检查的费用，就像您支付任何 Lambda 函数调用的费用一样。

以下是发送到您的 Lambda 函数的运行状况检查事件的格式。要检查事件是否为运行状况检查事件，请检查 user-agent 字段的值。运行状况检查的用户代理为 `ELB-HealthChecker/2.0`。

```
{
    "requestContext": {
        "elb": {
            "targetGroupArn": "arn:aws:elasticloadbalancing:region:123456789012:targetgroup/my-target-group/6d0ecf831eec9f09"
        }
    },
    "httpMethod": "GET",  
    "path": "/",  
    "queryStringParameters": {},  
    "headers": {
        "user-agent": "ELB-HealthChecker/2.0"
    },  
    "body": "",  
    "isBase64Encoded": false
}
```

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

**为 lambda 目标组启用运行状况检查**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格上的**负载均衡**下，选择**目标组**。

1. 选择目标组的名称以打开其详细信息页面。

1. 在 **Health checks** 选项卡上，选择 **Edit**。

1. 对于**运行状况检查**，选择**启用**。

1. （可选）根据需要更新运行状况检查设置。

1. 选择**保存更改**。

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

**为 lambda 目标组启用运行状况检查**  
使用 [modify-target-group](https://docs.aws.amazon.com/cli/latest/reference/elbv2/modify-target-group.html) 命令。

```
aws elbv2 modify-target-group \
    --target-group-arn target-group-arn \
    --health-check-enabled
```

------
#### [ CloudFormation ]

**为 lambda 目标组启用运行状况检查**  
更新[AWS::ElasticLoadBalancingV2::TargetGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html)资源。

```
Resources:
  myTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Name: my-target-group
      TargetType: lambda
      HealthCheckEnabled: true
      Tags: 
        - Key: 'department'
          Value: '123'
      Targets:
        - Id: !Ref myLambdaFunction
```

------

## 注册 Lambda 函数
<a name="register-lambda-function"></a>

您可以向每个目标组注册单个 Lambda 函数。要替换 Lambda 函数，建议您创建一个新的目标组，将新函数注册到该新目标组，然后将侦听器规则更新为使用新目标组。

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

**注册 Lambda 函数**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格上的**负载均衡**下，选择**目标组**。

1. 选择目标组的名称以打开其详细信息页面。

1. 在**目标**选项卡中，如果未注册任何 Lambda 函数，请选择**注册目标**。

1. 选择该 Lambda 函数或输入其 ARN。

1. 选择**注册**。

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

**注册 Lambda 函数**  
使用 [register-targets](https://docs.aws.amazon.com/cli/latest/reference/elbv2/register-targets.html) 命令。

```
aws elbv2 register-targets \
    --target-group-arn target-group-arn \
    --targets Id=lambda-function-arn
```

------
#### [ CloudFormation ]

**注册 Lambda 函数**  
更新[AWS::ElasticLoadBalancingV2::TargetGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html)资源。

```
Resources:
  myTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Name: my-target-group
      TargetType: lambda
      Tags: 
        - Key: 'department'
          Value: '123'
      Targets:
        - Id: !Ref myLambdaFunction
```

------

## 注销 Lambda 函数
<a name="deregister-lambda-function"></a>

如果您不再需要向您的 Lambda 函数发送流量，则可以将其取消注册。在取消注册 Lambda 函数后，进行中的请求会失败，并显示 HTTP 5XX 错误。

要替换 Lambda 函数，建议您创建一个新的目标组，将新函数注册到该新目标组，然后将侦听器规则更新为使用新目标组。

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

**注销 Lambda 函数**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格上的**负载均衡**下，选择**目标组**。

1. 选择目标组的名称以打开其详细信息页面。

1. 在**目标**选项卡上，选择目标并选择**注销**。

1. 当系统提示您确认时，选择 **Deregister (取消注册)**。

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

**注销 Lambda 函数**  
使用 [deregister-targets](https://docs.aws.amazon.com/cli/latest/reference/elbv2/deregister-targets.html) 命令。

```
aws elbv2 deregister-targets \
    --target-group-arn target-group-arn \
    --targets Id=lambda-function-arn
```

------