是否可以在 lambda 函数被终止并冷启动之前拦截终止信号以关闭数据库连接?

Is it possible to intercept kill signals to close DB connections right before a lambda function is killed and started cold?

为了加快 Lambda 的执行速度,我试图将我的 Python 代码的某些部分移到处理程序函数之外

根据Lambda's documentation

After a Lambda function is executed, AWS Lambda maintains the Execution Context for some time in anticipation of another Lambda function invocation. In effect, the service freezes the Execution Context after a Lambda function completes, and thaws the context for reuse, if AWS Lambda chooses to reuse the context when the Lambda function is invoked again. This Execution Context reuse approach has the following implications:

Any declarations in your Lambda function code (outside the handler code, see Programming Model) remains initialized, providing additional optimization when the function is invoked again. For example, if your Lambda function establishes a database connection, instead of reestablishing the connection, the original connection is used in subsequent invocations…

按照他们的例子,我将我的数据库连接逻辑移到了处理程序函数之外,因此函数的后续 WARM 运行s 可以重新使用连接而不是每次函数执行时创建一个新的。

但是,AWS Lambda 不保证启动 COLD 的函数的所有后续调用都将 运行 预热,因此如果 Lambda 决定 COLD 必须启动,我的代码会重新创建数据库连接。

发生这种情况时,我假设 Lambda 拆除的我的函数的前一个 (WARM) 实例将与从未关闭的数据库建立活动连接,并且如果模式不断重复,我怀疑我有很多孤立的数据库连接。

Python 中是否有一种方法可以检测 Lambda 是否试图终止我的函数实例(也许它们会发送 SIGTERM 信号?)并让它关闭活动的数据库连接?

我使用的数据库是 Postgres。

不幸的是,无法知道 lambda 容器何时会被销毁。

除此之外,冷启动和数据库连接都是使用 Lambda 的热门话题。最糟糕的是,没有明确的答案,应该在 use-case 的基础上处理。

就个人而言,我认为解决此问题的最佳方法是创建连接并根据超时 postgres 端终止空闲连接。为此,我将您引导至 How to close idle connections in PostgreSQL automatically?

您可能还想随时微调您拥有的 lambda 的数量 运行。为此,我建议在您的 lambda aws-docs 中设置并发级别。这样您就可以限制 运行 lambda 的数量,并且可能不会淹没您的数据库服务器。

Jeremy Daly(无服务器英雄)有一篇关于此的精彩博客 post。 How To: Manage RDS Connections from AWS Lambda Serverless Functions

他还有一个项目,不幸的是在节点中,它是 mysql 连接的包装器。这会监视连接并像杀死僵尸一样自动管理它们 serverless-mysql。您可能会发现 python.

的类似内容

我完全同意@dudemullet。

目前您无法确定 lambda 函数何时会消亡。最好的方法是首先了解连接的目的。如果它只是一个简单的 select/update 查询,理想情况下执行时间不会太长,我建议您打开和关闭处理程序函数内的连接。这样至少你可以 100% 确定不会有任何孤立的连接

但另一方面,您可能不得不忍受冷启动的那几毫秒!

我没有时间对此进行测试,但是 trap - 我目前处于 AFK 状态,但是当我进入时我会在进行一些实验后编辑此答案?

仅供参考,我不知道当容器被杀死时会发送什么信号,这不是我看过的东西,所以这个答案是基于它们以与普通 Linux 机器相同的方式退役下来。

在您的处理程序中,您将添加一个 shell 命令来 运行 这个脚本,然后设置一个变量,该变量将在容器 re-used 时保留在原位 -我不是 python 人,但你的逻辑是这样的:

处理程序

const { exec } = require('child_process');

if(typeof isNewContainer === 'undefined'){
     const isNewContainer = true 

    // run a shell script, in javascript we use shell exec and 
    // then have a callback for when it exits so the execution is non blocking and allows 
    // the code below to execute.
    exec('./script.sh & sleep 1 && kill -- -$(pgrep script.sh)', (err, stdout, stderr) => {
    // close db connections
   }


}

// handle the request

Shell 脚本基于 this 答案:

#!/bin/bash
exitCallback() {
    trap - SIGTERM # clear the trap
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

trap exitCallback SIGTERM

sleep infinity

请确保您阅读了对该问题的已接受答案的评论,因为它为您提供了 运行 脚本的 shell 命令。

我会说让容器保持温暖很容易,但你的问题是 "Is there a way in Python to detect if Lambda is trying to kill my function instance (maybe they send a SIGTERM signal?) and have it close active DB connections?"

我不认为你正在寻找的是目前可能的。黑客可能有用,但我建议不要依赖它们,因为在封闭源系统中,未记录的东西可能会在任何时间停止工作,恕不另行通知。

我猜您关心的是您的 lambda 函数创建的新连接数及其对数据库服务器造成的负载。

你见过 pgbouncer (https://pgbouncer.github.io/) 它是著名的 postgres 连接池之一。我建议在您的 lambda 函数和数据库之间使用类似 pgbouncer 的东西。

这将消除由于 pgbouncer 和 postgres 之间的连接可以保持很长时间而创建新连接而导致的数据库服务器负载。 lambda 函数可以与 pgbouncer 建立新连接,它不仅能够处理 un-closed 具有各种超时配置设置的连接。

2019 年 12 月 9 日更新

AWS 最近宣布了能够连接池的 RDS 代理。目前它处于预览状态,不支持 postresql,但他们说它即将推出。

https://aws.amazon.com/rds/proxy/

https://aws.amazon.com/blogs/compute/using-amazon-rds-proxy-with-aws-lambda/

已接受的答案不再正确,过去可能是正确的,但今天当 AWS 打算终止时,您的 lambda 应该会收到 SIGTERM

AWS 在此处有 python 和其他语言处理正常关机的官方示例:

https://github.com/aws-samples/graceful-shutdown-with-aws-lambda/tree/main/python-demo

但实际上你这样做了:

import signal

def exit_gracefully():
  print('SIGTERM RECEIVED')

signal.signal(signal.SIGTERM, exit_gracefully)

这会在容器关闭时调用,您有 300 毫秒的时间进行清理。