AWS Lambda 和 RDS 之间的间歇性超时

Posted

技术标签:

【中文标题】AWS Lambda 和 RDS 之间的间歇性超时【英文标题】:Intermittent timeouts between AWS Lambda and RDS 【发布时间】:2018-03-21 05:43:58 【问题描述】:

我们目前正在经历 AWS Lambda 和 RDS 之间的随机间歇超时。在部署我们的函数并成功运行它们后,它们可以随机切换到超时状态无需更改配置。需要注意的是,我们还在监视数据库连接,并且可以确认我们没有遇到最大连接问题。

以下是我们设置的详细信息:

正在执行的代码(使用 Node.JS v. 6.10):

const mysql = require('mysql');

exports.dbWrite = (events, context, callback) => 

   const db = mysql.createConnection(
       host: <redacted>,
       user: <redacted>,
       password: <redacted>,
       database: <redacted>
   );

   db.connect(function (err) 
       if (err) 
           console.error('error connecting: ' + err.stack);
           return;
       

       console.log('connected !');
   );

   db.end();

;

我们正在使用 Node.JS mysql 库,v. 2.14.1。

从网络的角度来看:

Lambda 函数与我们的 RDS 实例位于同一 VPC 中 Lambda 函数分配了子网,这些子网与具有互联网访问权限的路由表相关联(不与互联网网关相关联) RDS 数据库不可公开访问。 已创建一个安全组并与 Lambda 函数关联,该函数在所有端口上都具有广泛的开放访问权限(目前 - 一旦数据库连接可靠,情况就会改变)。 上述安全组已在与 RDS 实例关联的安全组内的端口 3306 上列入白名单。

CloudWatch 错误:


  "errorMessage": "connect ETIMEDOUT",
  "errorType": "Error",
  "stackTrace": [
    "Connection._handleConnectTimeout 
     (/var/task/node_modules/mysql/lib/Connection.js:419:13)",
     "Socket.g (events.js:292:16)",
     "emitNone (events.js:86:13)",
     "Socket.emit (events.js:185:7)",
     "Socket._onTimeout (net.js:338:8)",
     "ontimeout (timers.js:386:14)",
     "tryOnTimeout (timers.js:250:5)",
     "Timer.listOnTimeout (timers.js:214:5)",
     "    --------------------",
     "Protocol._enqueue                                     
      (/var/task/node_modules/mysql/lib/protocol/Protocol.js:145:48)",
     "Protocol.handshake 
      (/var/task/node_modules/mysql/lib/protocol/Protocol.js:52:23)",
     "Connection.connect 
      (/var/task/node_modules/mysql/lib/Connection.js:130:18)",
     "Connection._implyConnect 
      (/var/task/node_modules/mysql/lib/Connection.js:461:10)",
     "Connection.query 
      (/var/task/node_modules/mysql/lib/Connection.js:206:8)",
     "/var/task/db-write-lambda.js:52:12",
     "getOrCreateEventTypeId (/var/task/db-write-lambda.js:51:12)",
     "exports.dbWrite (/var/task/db-write-lambda.js:26:9)"
   ]
 

在已审查的参考文献中:

https://forums.aws.amazon.com/thread.jspa?threadID=221928 (CloudWatch 中的调用 ID 在所有超时情况下都不同) 此列表中的几乎所有帖子:https://***.com/search?q=aws+lambda+timeouts+to+RDS

总之,这些超时是间歇性的,这一事实使这个问题完全令人困惑。 AWS 支持声明 NodeJS-mysql 是第三方工具,技术上不支持,但我知道人们正在使用这种技术。

非常感谢任何帮助!

【问题讨论】:

当您获得一致的超时时,是否重新启动数据库(并因此删除所有连接)修复它? 我没有尝试过,但会这样做。我的想法是,因为打开的连接数量非常有限(2),所以它不应该是根本原因。谢谢! 可能是您为数据库提供的实例太小,导致其自身处于错误状态。检查 CPU 使用率与您对零负载的期望。 7% 可能没问题,但可能 40% 表示有问题。 CPU 使用率从未超过 2%。 哦,好吧,至少你已经消除了一个原因。 【参考方案1】:

考虑到 RDS 连接没有耗尽,有可能运行到特定子网的 lambda 总是无法连接到 db。我假设 RDS 实例和 lambdas 在不同的子网中运行。调查此问题的一种方法是检查流日志。

进入EC2 -> 网络接口 -> 搜索 lambda 名称 -> 复制 eni ref 然后进入 VPC -> 子网 -> 选择 lambda 的子网 -> 流日志 -> 通过 eni ref 搜索。

如果您在 db 端口的流日志中看到“REJECT OK”,则表示网络 ACL 中缺少配置。

【讨论】:

很遗憾,我没有为网络接口启用流日志,现在将遵循该路径。谢谢! Suken,关于使用 Flow Logs 帮助调试此问题的好建议。 流日志为我们解决了这样的问题,我们使用标准 ACL 设置从数据库访问回 Lambda,这是使用 Linux 临时端口范围而不是 Lambda 端口。所以它阻止了一些并非所有的连接docs.aws.amazon.com/vpc/latest/userguide/…【参考方案2】:

更新此问题:事实证明,该问题与在处理程序中建立数据库连接的事实有关!由于 Lambda 和 Node 的异步特性,这是导致间歇性超时的罪魁祸首。

这是修改后的代码:

const mysql = require('mysql');
const database = getConnection();

exports.dbWrite = (events, context, callback) => 

   database.connect(function (err) 
     if (err) 
          console.error('error connecting: ' + err.stack);
          return;
     

     console.log('connected !');
);

db.end();


function getConnection() 
   let db = mysql.createConnection(
       host: process.env.DB_HOST,
       user: process.env.DB_USER,
       password: process.env.DB_PASS,
       database: process.env.DB_NAME
   );

   console.log('Host: ' + process.env.DB_HOST);
   console.log('User: ' + process.env.DB_USER);
   console.log('Database: ' + process.env.DB_NAME);

   console.log('Connecting to ' + process.env.DB_HOST + '...');

   return db;

【讨论】:

以上是关于AWS Lambda 和 RDS 之间的间歇性超时的主要内容,如果未能解决你的问题,请参考以下文章

AWS Lambda RDS 连接超时

AWS Lambda NodeJS 连接到 RDS Postgres 数据库

AWS Lambda Task在3.00秒后超时

AWS Lambda 任务在 3.00 秒后超时

间歇性无法连接到 AWS RDS 上的 mysql(错误 2003)

阿波罗服务器 RDS 和 aws lambda