从 RDS for PostgreSQL 数据库实例中调用 Amazon Lambda 函数 - Amazon Relational Database Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

RDS for PostgreSQL 数据库实例中调用 Amazon Lambda 函数

Amazon Lambda 是事件驱动型计算服务,无需您预置或管理服务器即可运行代码。该服务可与许多 Amazon 服务搭配使用,其中包括 RDS for PostgreSQL。例如,您可以使用 Lambda 函数处理来自数据库的事件通知,或者在将新文件上传到 Amazon S3 时从文件中加载数据。若要了解 Lambda 的更多信息,请参阅《Amazon Lambda 开发人员指南》中的什么是 Amazon Lambda?

注意

这些 RDS for PostgreSQL 版本支持调用 Amazon Lambda 函数:

  • 14.1 及更高的次要版本

  • 13.2 及更高的次要版本

  • 12.6 及更高的次要版本

设置 RDS for PostgreSQL 使用 Lambda 函数的过程包含多个步骤,其中涉及 Amazon Lambda、IAM、VPC 和 RDS for PostgreSQL 数据库实例。下文对必要步骤进行了总结。

有关 Lambda 函数的更多信息,请参阅《Amazon 开发人员指南https://docs.amazonaws.cn/lambda/latest/dg/getting-started.html》中的 Lambda 入门Amazon Lambda Lambda 函数

步骤 1:配置 RDS for PostgreSQL 数据库实例,实现与 Amazon Lambda 的出站连接

Lambda 函数始终在 Amazon Lambda 服务拥有的 Amazon VPC 中运行。Lambda 将向此 VPC 应用网络访问和安全规则,并且会自动维护和监控 VPC。RDS for PostgreSQL 数据库实例需要向 Lambda 服务的 VPC 发送网络流量。其配置方式取决于 数据库实例是公有实例,还是私有实例。

  • 如果 RDS for PostgreSQL 数据库实例 为公有,则只需配置安全组以允许来自 VPC 的出站流量。如果数据库实例位于 VPC 的公有子网中,且实例的 PubliclyAccessible 属性为 true,则其为公有实例。

    若要查找此属性的值,您可以使用 describe-db-instances Amazon CLI 命令。您也可以使用 Amazon Web Services Management Console 打开 Connectivity & security(连接和安全性)选项卡,然后检查 Publicly accessible(公开访问)是否为 Yes(是)。您还可以使用 Amazon Web Services Management Console 和 Amazon CLI 检查实例是否在 VPC 的公有子网中。

  • 如果 RDS for PostgreSQL 数据库实例为私有,则您有几种选择。您可以使用网络地址转换 (NAT) 网关 或 VPC 终端节点。有关 NAT 网关的更多信息,请参阅 NAT 网关。下面是使用 VPC 终端节点的步骤汇总。

公有数据库实例配置与 Amazon Lambda 的连接

  • 配置运行 RDS for PostgreSQL 数据库实例的 VPC 来允许出站连接。您可以在 VPC 安全组上创建出站规则来完成配置,该规则允许 TCP 流量流向端口 443 和任何 IPv4 地址 (0.0.0.0/0)。

私有数据库实例配置与 Amazon Lambda 的连接

  1. 使用 VPC 终端节点为 Amazon Lambda 配置 VPC。有关更多信息,请参阅《Amazon VPC 用户指南https://docs.amazonaws.cn/vpc/latest/userguide/vpc-endpoints.html》中的 VPC 终端节点。该端点会返回 RDS for PostgreSQL 数据库实例向 Lambda 函数发出的调用的响应。

  2. 将端点添加到 VPC 路由表中。有关更多信息,请参阅《Amazon VPC 用户指南》中的使用路由表

  3. VPC 终端节点使用自己的私有 DNS 解析。在您将 rds.custom_dns_resolution 的值从其默认值 0(未启用)更改为 1 之前,RDS for PostgreSQL 无法使用 Lambda VPC 终端节点。

    1. 创建自定义数据库参数组。

    2. rds.custom_dns_resolution 参数的值由默认值 0 更改为 1

    3. 修改数据库实例以使用自定义数据库参数组。

    4. 重启实例,使修改的参数生效。

您的 VPC 现在可以在网络级别与 Amazon Lambda VPC 交互。不过,您仍然需要使用 IAM 配置权限。

步骤 2:为 RDS for PostgreSQL 数据库实例和 Amazon Lambda 配置 IAM

RDS for PostgreSQL 数据库实例调用 Lambda 函数需要特定权限。若要配置必要权限,建议创建允许调用 Lambda 函数的 IAM 策略,将该策略分配给一个角色,然后将该角色应用于数据库实例。这种方法授予数据库实例代表您调用指定 Lambda 函数的权限。以下步骤说明如何使用 Amazon CLI 执行此操作。

配置 IAM 权限以将Amazon RDS 实例与 Lambda 搭配使用

  1. 使用 create-policy Amazon CLI 命令创建允许 RDS for PostgreSQL 数据库实例调用指定 Lambda 函数的 IAM 策略。(语句 ID (Sid) 是策略语句的可选描述,对使用没有影响。) 此策略授予 数据库实例调用指定 Lambda 函数所需的最低权限。

    aws iam create-policy --policy-name rds-lambda-policy --policy-document '{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowAccessToExampleFunction", "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": "arn:aws:lambda:aws-region:444455556666:function:my-function" } ] }'

    您也可以使用允许您调用任何 Lambda 函数的预定义 AWSLambdaRole 策略。有关更多信息,请参阅 Lambda 的基于身份的 IAM 策略

  2. 使用 create-role Amazon CLI 命令创建该策略可在运行时担任的 IAM 角色。

    aws iam create-role --role-name rds-lambda-role --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "rds.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }'
  3. 使用 attach-role-policy Amazon CLI 命令将策略应用于角色。

    aws iam attach-role-policy \ --policy-arn arn:aws:iam::444455556666:policy/rds-lambda-policy \ --role-name rds-lambda-role --region aws-region
  4. 使用 add-role-to-db-instance Amazon CLI 命令,将该角色应用于 RDS for PostgreSQL 数据库实例。最后一步允许数据库实例的数据库用户调用 Lambda 函数。

    aws rds add-role-to-db-instance \ --db-cluster-identifier my-cluster-name \ --feature-name Lambda \ --role-arn arn:aws:iam::444455556666:role/rds-lambda-role \ --region aws-region

完成 VPC 和 IAM 配置后,便可以安装 aws_lambda 扩展。(请注意,您可以随时安装扩展,但只有在您设置正确的 VPC 支持和 IAM 权限之后,aws_lambda 扩展才会对 RDS for PostgreSQL 数据库实例的功能添加内容。)

步骤 3:为 RDS for PostgreSQL 数据库实例安装 aws_lambda 扩展

要将 Amazon Lambda 与 RDS for PostgreSQL 数据库实例搭配使用,请将 aws_lambda PostgreSQL 扩展安装到 RDS for PostgreSQL。此扩展允许 RDS for PostgreSQL 数据库实例能从 PostgreSQL 调用 Lambda 函数。

RDS for PostgreSQL 数据库实例安装 aws_lambda 扩展

使用 PostgreSQL psql 命令行或 pgAdmin 工具连接到 RDS for PostgreSQL 数据库实例

  1. 以具有 rds_superuser 权限的用户身份,连接到 RDS for PostgreSQL 数据库实例。默认 postgres 用户如示例所示。

    psql -h instance.444455556666.aws-region.rds.amazonaws.com -U postgres -p 5432
  2. 安装 aws_lambda 扩展。aws_commons 扩展也是必要项。其为 PostgreSQL 的 aws_lambda 和许多其他 Aurora 扩展提供帮助程序函数。如果其尚未安装到 RDS for PostgreSQL 数据库实例上,则会按如下所示一并安装该扩展和 aws_lambda

    CREATE EXTENSION IF NOT EXISTS aws_lambda CASCADE; NOTICE: installing required extension "aws_commons" CREATE EXTENSION

aws_lambda 扩展已安装在 数据库实例中。现在,您可以创建易于使用结构来调用 Lambda 函数。

步骤 4:将 Lambda 帮助程序函数与 RDS for PostgreSQL 数据库实例搭配使用(可选)

您可以使用 aws_commons 扩展中的帮助程序函数来准备实体,以便更轻松地从 PostgreSQL 调用这些实体。为此,您需要获得有关 Lambda 函数的以下信息:

  • Function name(函数名称):Lambda 函数的名称、Amazon Resource Name (ARN)、版本或别名。在 步骤 2:为实例和 Lambda 配置 IAM 中创建的 IAM 策略需要 ARN,所以建议您使用函数的 ARN。

  • Amazon Region(Amazon 区域):(可选)如果其与 RDS for PostgreSQL 数据库实例不在同一个区域中,则此区域为 Lambda 函数所在的 Amazon 区域。

您可以使用 aws_commons.create_lambda_function_arn 函数保存 Lambda 函数名称信息。此帮助程序函数创建了 aws_commons._lambda_function_arn_1 复合结构,其中包含调用函数所需的详细信息。在下文中,您可以找到三种替代方法来设置此复合结构。

SELECT aws_commons.create_lambda_function_arn( 'my-function', 'aws-region' ) AS aws_lambda_arn_1 \gset
SELECT aws_commons.create_lambda_function_arn( '111122223333:function:my-function', 'aws-region' ) AS lambda_partial_arn_1 \gset
SELECT aws_commons.create_lambda_function_arn( 'arn:aws:lambda:aws-region:111122223333:function:my-function' ) AS lambda_arn_1 \gset

这些值均可用于 aws_lambda.invoke 函数调用。有关示例,请参阅 步骤 5:从 RDS for PostgreSQL 数据库实例调用 Lambda 函数

步骤 5:从 RDS for PostgreSQL 数据库实例调用 Lambda 函数

aws_lambda.invoke 函数采用同步还是异步调用方式取决于 invocation_type。此参数的两个可用选项分别为 RequestResponse(默认)和 Event,如下所示。

  • RequestResponse:此为同步调用类型。如果调用时未指定调用类型,默认此调用方式。响应有效负载包含 aws_lambda.invoke 函数的结果。如果工作流程需要接收 Lambda 函数的结果才能继续进行操作,请使用此调用类型。

  • Event:此为异步调用类型。响应不包含包含结果的有效负载。如果工作流程不需要 Lambda 函数的结果即可继续进行操作,请使用此调用类型。

要对设置进行简单测试,您可以使用 psql 连接到数据库实例,然后从命令行调用示例函数。假设在 Lambda 服务上设置了一个基本函数,例如下面屏幕截图中所示的简单 Python 函数。


            Amazon Lambda 的 Amazon CLI 中显示的示例 Lambda 函数

调用示例函数

  1. 使用 psql 或 pgAdmin 连接到数据库实例。

    psql -h instance.444455556666.aws-region.rds.amazonaws.com -U postgres -p 5432
  2. 使用函数的 ARN 调用该函数。

    SELECT * from aws_lambda.invoke(aws_commons.create_lambda_function_arn('arn:aws:lambda:aws-region:444455556666:function:simple', 'us-west-1'), '{"body": "Hello from Postgres!"}'::json );

    响应如下所示。

    status_code | payload | executed_version | log_result -------------+-------------------------------------------------------+------------------+------------ 200 | {"statusCode": 200, "body": "\"Hello from Lambda!\""} | $LATEST | (1 row)

如果调用尝试不成功,请参阅 Lambda 函数错误消息

在下文中,您可以找到调用 aws_lambda.invoke 函数的一些示例。大多数示例都使用您在 步骤 4:将 Lambda 帮助程序函数与 RDS for PostgreSQL 数据库实例搭配使用(可选) 中创建的复合结构 aws_lambda_arn_1 来简化函数详细信息的传递。有关异步调用的示例,请参阅 示例:Lambda 函数的异步(事件)调用。列出的其他示例均使用同步调用。

要了解有关 Lambda 调用类型的更多信息,请参阅《Amazon Lambda 开发人员指南》中的调用 Lambda 函数。有关 aws_lambda_arn_1 的更多信息,请参阅 aws_commons.create_lambda_function_arn

示例:Lambda 函数的同步 (RequestResponse) 调用

以下是 Lambda 函数同步调用的两个示例。这些 aws_lambda.invoke 函数调用的结果相同。

SELECT * FROM aws_lambda.invoke(:'aws_lambda_arn_1', '{"body": "Hello from Postgres!"}'::json);
SELECT * FROM aws_lambda.invoke(:'aws_lambda_arn_1', '{"body": "Hello from Postgres!"}'::json, 'RequestResponse');

参数如下所述:

  • :'aws_lambda_arn_1':此参数使用 aws_commons.create_lambda_function_arn 帮助程序函数标识在 步骤 4:将 Lambda 帮助程序函数与 RDS for PostgreSQL 数据库实例搭配使用(可选) 中创建的复合结构。您还可以通过内联方式在 aws_lambda.invoke 调用中创建此结构,如下所示。

    SELECT * FROM aws_lambda.invoke(aws_commons.create_lambda_function_arn('my-function', 'aws-region'), '{"body": "Hello from Postgres!"}'::json );
  • '{"body": "Hello from PostgreSQL!"}'::json – 要传递到 Lambda 函数的 JSON 负载。

  • 'RequestResponse' – Lambda 调用类型。

示例:Lambda 函数的异步(事件)调用

以下是异步 Lambda 函数调用的示例。Event 调用类型使用指定的输入负载计划 Lambda 函数调用并立即返回。在某些不依赖于 Lambda 函数结果的工作流程中使用 Event 调用类型。

SELECT * FROM aws_lambda.invoke(:'aws_lambda_arn_1', '{"body": "Hello from Postgres!"}'::json, 'Event');

示例:在函数响应中捕获 Lambda 执行日志

您可以使用 aws_lambda.invoke 函数调用中的 log_type 参数,在函数响应中包含执行日志的最后 4 kB。默认情况下,此参数设置为 None,但您可以指定 Tail 在响应中捕获 Lambda 执行日志的结果,如下所示。

SELECT *, select convert_from(decode(log_result, 'base64'), 'utf-8') as log FROM aws_lambda.invoke(:'aws_lambda_arn_1', '{"body": "Hello from Postgres!"}'::json, 'RequestResponse', 'Tail');

aws_lambda.invoke 函数的 log_type 参数设置为 Tail,以在响应中包含执行日志。log_type 参数的默认值为 None

返回的 log_resultbase64 编码的字符串。您可以使用 decodeconvert_from PostgreSQL 函数的组合来解码内容。

有关 log_type 的更多信息,请参阅 aws_lambda.invoke

示例:在 Lambda 函数中包含客户端上下文

aws_lambda.invoke 函数具有 context 参数,可用于传递独立于有效负载的信息,如下所示。

SELECT *, convert_from(decode(log_result, 'base64'), 'utf-8') as log FROM aws_lambda.invoke(:'aws_lambda_arn_1', '{"body": "Hello from Postgres!"}'::json, 'RequestResponse', 'Tail');

要包含客户端上下文,请将 JSON 对象用于 aws_lambda.invoke 函数的 context 参数。

有关 context 参数的更多信息,请参阅 aws_lambda.invoke 参考。

示例:调用 Lambda 函数的特定版本

通过在 aws_lambda.invoke 调用中包含 qualifier 参数,您可以指定 Lambda 函数的特定版本。在下文中,您可以找到一个使用 'custom_version' 作为版本别名完成此操作的示例。

SELECT * FROM aws_lambda.invoke(:'aws_lambda_arn_1', '{"body": "Hello from Postgres!"}'::json, 'RequestResponse', 'None', NULL, 'custom_version');

您还可以改为提供包含 Lambda 函数名称详细信息的 Lambda 函数限定符,如下所示。

SELECT * FROM aws_lambda.invoke(aws_commons.create_lambda_function_arn('my-function:custom_version', 'us-west-2'), '{"body": "Hello from Postgres!"}'::json);

有关 qualifier 和其他参数的详细信息,请参阅 aws_lambda.invoke 参考。

Lambda 函数错误消息

VPC 配置不当可能导致错误消息,如下所示。

ERROR: invoke API failed DETAIL: Amazon Lambda client returned 'Unable to connect to endpoint'. CONTEXT: SQL function "invoke" statement 1

首先检查 VPC 安全组。确保在端口 443 上打开 TCP 的出站规则,以便 VPC 连接到 Lambda VPC。

如果数据库实例为私有实例,请检查 VPC 的私有 DNS 设置。确保将 rds.custom_dns_resolution 参数设置为 1 并按照 步骤 1:配置 RDS for PostgreSQL 数据库实例,实现与 Amazon Lambda 的出站连接 所述设置 Amazon PrivateLink。有关更多信息,请参阅接口 VPC 终端节点 (Amazon PrivateLink)

如果 Lambda 函数在请求处理过程中抛出异常,则 aws_lambda.invoke 会失败并显示 PostgreSQL 错误,如下所示。

SELECT * FROM aws_lambda.invoke(:'aws_lambda_arn_1', '{"body": "Hello from Postgres!"}'::json); ERROR: lambda invocation failed DETAIL: "arn:aws:lambda:us-west-2:555555555555:function:my-function" returned error "Unhandled", details: "<Error details string>".

务必处理 Lambda 函数或 PostgreSQL 应用程序中的错误。