AWS Lambda RDS 连接超时
Posted
技术标签:
【中文标题】AWS Lambda RDS 连接超时【英文标题】:AWS Lambda RDS connection timeout 【发布时间】:2017-07-25 02:39:42 【问题描述】:我正在尝试使用连接到我的 RDS 数据库的 Node.js 编写一个 Lambda 函数。该数据库正在运行并且可以从我的 Elastic Beanstalk 环境中访问。当我运行该函数时,它会返回一个超时错误。
尝试将超时时间增加到 5 分钟,结果完全相同。
经过一番研究,我得出的结论是,这可能是一个安全问题,但在亚马逊的文档或this 答案中找不到解决方案(这是我唯一能找到的关于该主题的答案)。
以下是安全细节:
RDS 和 Lambda 都在同一个安全组中。 RDS 具有所有流量入站和出站规则。 Lambda 在其角色中具有 AmazonVPCFullAccess 策略。我的代码是:
'use strict';
console.log("Loading getContacts function");
var AWS = require('aws-sdk');
var mysql = require('mysql');
exports.handler = (event, context, callback) =>
var connection = mysql.createConnection(
host : '...',
user : '...',
password : '...',
port : 3306,
database: 'ebdb',
debug : false
);
connection.connect(function(err)
if (err) callback(null, 'error ' +err);
else callback(null, 'Success');
);
;
我得到的结果是:
"errorMessage": "2017-03-05T05:57:46.851Z 9ae64c49-0168-11e7-b49a-a1e77ae6f56c Task timed out after 10.00 seconds"
【问题讨论】:
您是否为 Lambda 函数启用了 VPC 访问? 是的,Lambda 和 RDS 都在同一个(默认)VPC 上 notebookbft.wordpress.com/2018/01/09/… 【参考方案1】:我正在分享我在连接 RDS 时的经验。
您需要为
Lambda function
启用VPC
访问权限,在此期间您将为其分配Security Group。
然后,在分配给 RDS 实例的安全组内,您将为分配给 Lambda 函数的安全组启用访问权限。
您可以获取更多信息here
【讨论】:
请阅读问题。您提到的所有内容都已包含在问题中。 Lambda 和 RDS 都在同一个(默认)VPC 上【参考方案2】:RDS 和 Lambda 都在同一个安全组中。
这是关键。默认情况下,不允许在同一安全组内进行通信。而且您需要明确允许它(E.x sg-xxxxx ALL TCP)。这仅在您的 lambda 尝试通过私有 ip 访问 db 时才有效。
如果它试图通过公共 IP 访问它,它将无法正常工作,您还需要为此打出必要的整体。
但是有更好的方法:
-
为您的 lambda 创建单独的安全组
允许 RDS sg 中端口
3306
上的入站流量用于 lambdas sg。
【讨论】:
为 Lambda 创建了一个单独的安全组,并且所有流量都在 RDS 上入站,但仍然是同样的问题... 救命稻草。谁会想到 AWS 在默认情况下会阻止同一安全组内的通信? AWS 教程都没有提到这一点,他们很清楚您需要将您的 Lambda 和 RDS 在同一个组中,但没有提到您需要使它们能够通信。 (我的首选方法是添加一个入站规则以允许来自同一安全组内的所有 TCP 流量,但是为 Lambda 创建一个新的并启用它的建议当然也可以。)【参考方案3】:我要感谢所有提供帮助的人,问题结果与我想象的不同。代码中的 callback
出于某种原因不起作用,即使它位于亚马逊自己的默认示例中。
工作代码如下所示:
'use strict';
console.log("Loading getContacts function");
var AWS = require('aws-sdk');
var mysql = require('mysql');
exports.handler = (event, context) =>
var connection = mysql.createConnection(
host : '...',
user : '...',
password : '...',
port : 3306,
database: 'ebdb',
debug : false
);
connection.connect(function(err)
if (err) context.fail();
else context.succeed('Success');
);
;
【讨论】:
我为此奋斗了一个多小时——将近两个小时。我以为我的防火墙规则被破坏了。 OMG,简单地删除回调线如何解决所有问题?无论如何,好的提示,我做过同样的事情。一定是某种回调死锁什么的。 您需要在调用回调之前结束连接。由于连接保持打开状态,lambda 超时。需要在.connect()
、connection.end(function (err) callback(null, response););
的回调中添加这样的东西。
遇到了这个答案 - 只是想指出回调参数是可选的,具体取决于您的 NodeJS 版本,根据 AWS Docs:docs.aws.amazon.com/lambda/latest/dg/…【参考方案4】:
问题不在于超时,而在于您关闭连接的方式。如果您不想等待回调或在关闭.end(function(err) //Now call your callback );
中的连接时正确使用回调,请改用.destroy()
请参阅this thread 以获得更深入的解释。
【讨论】:
【参考方案5】:虽然可以使用上下文,但您只需将context.callbackWaitsForEmptyEventLoop = false;
添加到处理程序,然后像这样正常使用回调:
exports.handler = (event, context) =>
context.callbackWaitsForEmptyEventLoop = false;
var connection = mysql.createConnection(
//connection info
);
connection.connect(function(err)
if (err) callback(err);
else callback(null, 'Success');
);
;
答案在文档中(我花了几个小时才找到这个): http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-using-old-runtime.html
在“比较上下文和回调方法”部分中,它有一个“重要”说明来解释事情。
在注释的底部写着:
因此,如果您想要与上下文方法相同的行为,则必须将上下文对象属性 callbackWaitsForEmptyEventLoop 设置为 false。
基本上,回调会持续到事件循环的结束,而不是结束事件循环的上下文。所以设置 callbackWaitsForEmptyEventLoop 使得回调像上下文一样工作。
【讨论】:
传奇!谢谢,这是正确答案:context.callbackWaitsForEmptyEventLoop = false; 不是所有的英雄都穿斗篷!谢谢。 context.callbackWaitsForEmptyEventLoop = false;是正确的 context.callbackWaitsForEmptyEventLoop = false; const response = statusCode: 200, body: JSON.stringify( headers: 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': true, , message: await mysqlConnector .create('table_name', test: 50), 输入:事件, ), ;回调(空,响应);【参考方案6】:我也遇到过类似的超时情况。在connection.connect()
之后,问题不在connection.end()
上。 Connection.end()
应该在callback
之前完成。
工作代码:
var mysql = require('mysql');
var connection = mysql.createConnection(
host : 'host_name',
user : 'root',
password : 'password'
);
module.exports.handler = (event, context, callback) =>
// **Connection to database**
connection.connect(function(err)
if (err)
console.error('Database connection failed: ' + err.stack);
return;
console.log('Connected to database.');
);
// **Hit DB Query**
connection.query("Query", function(err, rows, fields)
console.log(rows);
);
//**Close Connection**
connection.end(); ***// Missing this section will result in timeout***
//**Send API Response**
callback(null,
statusCode: '200',
body: "Success",
headers:
'Content-Type': 'application/json',
,
);
;
【讨论】:
【参考方案7】:当您最初设置数据库时,它会自动创建一个安全组。默认为您设置数据库的 IP。当您从 lambda 运行时,此规则会阻止流量。查看您的数据库错误日志,您可以确认它拒绝连接。
***** could not be resolved: Name or service not known
您需要在安全组中创建规则以允许 lambda 流量。转到您的 RDS 实例控制台并单击安全组,选择入站。在那里你会看到规则。然后拨打电话向世界开放,查找 AWS lambda IP 或创建 VPC。
【讨论】:
您的回答解决了我的问题,您知道如何找到我的 AWS Lambda IP 吗? @toonsend 我不认为它是这样工作的。您需要设置 VPC。 docs.aws.amazon.com/lambda/latest/dg/vpc.html【参考方案8】:connection.end() 应该在回调之后:
这样的工作代码:
'use strict';
var mysql = require('mysql');
var connection = mysql.createConnection(
host : 'xxxxxx.amazonaws.com',
user : 'testuser',
password : 'testPWD',
port : 3306,
database: 'testDB',
debug : false
);
module.exports.handler = (event, context, callback) =>
// **Connection to database**
connection.connect(function(err)
if (err)
console.error('Database connection failed: ' + err.stack);
context.fail();
return;
else
console.log('Connected to database.');
);
connection.query('show tables from testDB', function (error, results, fields)
if (error)
console.log("error: connection failed with db!");
connection.destroy();
throw error;
else
// connected!
console.log("info: connection ok with db!");
console.log(results);
context.succeed("done");
callback(error, results);
);
//Send API Response
callback(null,
statusCode: '200',
body: 'succeed',
headers:
'Content-Type': 'application/json',
,
);
//Close Connection
connection.end(); // Missing this section will result in timeout***
;
【讨论】:
【参考方案9】:我花了大约 2 天的时间才弄清楚确切的问题。在我的情况下,RDS 和 Lambda 函数都在相同的 VPC、子网和安全组中,并添加了所需的角色,但仍然出现 Socket 超时异常。我可以通过以下链接更改入站和出站规则来解决问题 -
https://aws.amazon.com/premiumsupport/knowledge-center/connect-lambda-to-an-rds-instance/
【讨论】:
感谢上帝,我已经为此苦苦挣扎了一周以上是关于AWS Lambda RDS 连接超时的主要内容,如果未能解决你的问题,请参考以下文章
AWS Lambda NodeJS 连接到 RDS Postgres 数据库
连接节点 v5.10.1 时握手不活动超时错误。到 aws mysql RDS
AWS RDS / EC2:TimeoutError:Knex:获取连接超时。游泳池可能已满