Node.js AWS Lambda RDS连接超时

Node.js AWS Lambda RDS连接超时,node.js,amazon-web-services,aws-lambda,rds,Node.js,Amazon Web Services,Aws Lambda,Rds,我正在尝试使用Node.js编写一个Lambda函数,它连接到我的RDS数据库。数据库正在运行,可以从我的Elastic Beanstalk环境访问。当我运行该函数时,它返回一个超时错误 尝试将超时时间增加到5分钟,结果完全相同 经过一些研究,我得出的结论是,这可能是一个安全问题,但在Amazon的文档或答案中找不到解决方案(这是我在这个主题上唯一能找到的解决方案) 以下是安全详细信息: RDS和Lambda都在同一个安全组中 RDS拥有所有入站和出站流量规则 Lambda在其角色中具有Ama

我正在尝试使用Node.js编写一个Lambda函数,它连接到我的RDS数据库。数据库正在运行,可以从我的Elastic Beanstalk环境访问。当我运行该函数时,它返回一个超时错误

尝试将超时时间增加到5分钟,结果完全相同

经过一些研究,我得出的结论是,这可能是一个安全问题,但在Amazon的文档或答案中找不到解决方案(这是我在这个主题上唯一能找到的解决方案)

以下是安全详细信息:

  • 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"

我正在共享连接RDS时的经验

您需要为
Lambda功能启用
VPC
访问,在此期间,您将为其分配一个

然后,在分配给RDS实例的安全组中,您将启用对分配给Lambda函数的安全组的访问

你可以得到更多信息

RDS和Lambda都在同一个安全组中

这是关键。默认情况下,不允许在同一安全组内进行通信。您需要明确地允许它(E.x sg-xxxxx ALL TCP)。只有当lambda试图通过专用ip访问db时,此wll才起作用

如果它试图通过公共IP访问它,那么它将无法工作,您也需要为此打必要的折扣

然而,有更好的方法:

  • 为lambda创建单独的安全组
  • 允许lambdas sg的RDS sg中的端口
    3306
    上的入站流量

  • 我要感谢每一个帮助过我的人,结果问题与我想象的不同。代码中的
    回调
    由于某些原因不起作用,即使它在AMAZON自己的默认示例中

    工作代码如下所示:

    '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');
        });
    
    };
    
    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');
      });
    };
    

    问题不是源于超时,而是源于您关闭连接的方式。如果不想等待回调,请使用
    .destroy()
    ,或者在
    .end(函数(err){//Now call your callback}中关闭连接时正确使用回调


    请参阅以获得更深入的解释。

    使用上下文将起作用,但只需添加
    context.callbackaitsforemptyeventloop=false发送到处理程序,然后像这样正常使用回调:

    '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');
        });
    
    };
    
    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');
      });
    };
    
    答案在文档中(我花了几个小时才找到):

    在“比较上下文和回调方法”一节中,有一个“重要”的注释解释了一些事情

    注释的底部写着:

    因此,如果希望与上下文方法具有相同的行为,则必须将上下文对象属性callbackhaitsforemptyeventloop设置为false


    基本上,回调继续到事件循环的末尾,而上下文则结束事件循环。所以设置callbackhaitsforemptyeventloop使回调像上下文一样工作。

    我也遇到过类似的超时情况。问题是在
    connection.connect()
    之后没有执行
    connection.end()
    Connection.end()
    应该在
    回调之前完成

    工作代码:

      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',
                  },
          });
    
        };
    

    最初设置DB时,它将自动创建一个安全组。默认为设置DB时使用的IP。当您从lambda跑步时,此规则会阻止交通。查看您的db错误日志,您可以确认它正在拒绝连接

    ***** could not be resolved: Name or service not known
    
    您需要在安全组中创建一个规则以允许lambda通信。转到RDS实例控制台,单击安全组,选择inbound。在那里你会看到规则。然后呼吁向世界开放,找到AWS lambda IP或创建专有网络

    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***
    
    };
    

    我花了大约两天的时间才弄清楚确切的问题。在我的例子中,RDS和Lambda函数都在同一个VPC、子网和安全组中,并添加了所需的角色,但仍然得到套接字超时异常。我可以通过以下链接更改入站和出站规则来解决这个问题-


    是否为Lambda功能启用了VPC访问?是的,Lambda和RDS都位于同一(默认)VPC上请阅读问题。您提到的所有内容都已包含在问题中。Lambda和RDS都位于同一(默认)VPC上。为Lambda创建了一个单独的安全组,所有入站流量都位于RDS上,但仍然存在相同的问题…Lifesaver。谁会想到AWS会在默认情况下阻止同一安全组内的通信?AWS教程中没有提到这一点,它们很清楚您需要将Lambda和RDS放在同一组中,但没有提到您需要使它们能够通信。(我的首选方法是添加一个入站规则,以允许来自同一安全组的所有TCP流量,但为Lambda创建一个新规则并启用它的建议当然也会起作用。)我为此奋斗了一个多小时——接近两个小时。我以为我的防火墙规则被滥用了。天哪,简单地删除回调行怎么能解决所有问题?不管怎样,好消息,我也做了同样的事。一定是某种回调死锁之类的。在调用回调之前,需要结束连接。当连接保持打开时,lambda超时。需要向
    .connect()
    connection.end(函数(err){callback(null,response);})的回调中添加类似的内容。遇到这个答案-只想指出,根据AWS文档,回调参数是可选的,取决于您的NodeJS版本:您的答案解决了我的问题,您知道如何找到我的AWS Lambda IP吗@toonsendI不这么认为。你需要建立一个专有网络。莱根