AWS Lambda 和 RDS 之间的间歇性超时
Intermittent timeouts between AWS Lambda and RDS
我们目前正在经历 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 函数分配了子网,这些子网与路由 table 关联,但 没有 互联网访问权限(未与互联网网关关联)
- 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 在所有超时情况下都不同)
- 此列表中几乎每个 post:https://whosebug.com/search?q=aws+lambda+timeouts+to+RDS
总而言之,这些超时是 间歇性 的事实使这个问题完全令人困惑。 AWS 支持已声明 NodeJS-mysql
是第三方工具,技术上 不受支持,但我知道人们正在使用这种技术。
非常感谢任何帮助!
考虑到RDS连接没有耗尽,有可能lambda 运行进入特定子网总是无法连接到数据库。我假设 RDS 实例和 lambdas 运行 在不同的子网中。调查此问题的一种方法是检查流日志。
转到 EC2 -> 网络接口 -> 搜索 lambda 名称 -> 复制 eni ref 然后转到 VPC -> 子网 -> select lambda 的子网 -> 流日志 -> 搜索eni 参考
如果您在数据库端口的流日志中看到 "REJECT OK",则表示网络 ACL 中缺少配置。
更新此问题:原来这个问题与数据库连接是在处理程序中进行的事实有关!由于 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 之间的 随机间歇性 超时。部署我们的功能并运行成功后,它们可以随机切换到超时状态,无需更改配置。需要注意的重要一点是,我们还在监视数据库连接,并且可以确认我们没有 运行 陷入最大连接问题。
以下是我们设置的详细信息:
正在执行的代码(使用 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 函数分配了子网,这些子网与路由 table 关联,但 没有 互联网访问权限(未与互联网网关关联)
- 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 在所有超时情况下都不同)
- 此列表中几乎每个 post:https://whosebug.com/search?q=aws+lambda+timeouts+to+RDS
总而言之,这些超时是 间歇性 的事实使这个问题完全令人困惑。 AWS 支持已声明 NodeJS-mysql
是第三方工具,技术上 不受支持,但我知道人们正在使用这种技术。
非常感谢任何帮助!
考虑到RDS连接没有耗尽,有可能lambda 运行进入特定子网总是无法连接到数据库。我假设 RDS 实例和 lambdas 运行 在不同的子网中。调查此问题的一种方法是检查流日志。
转到 EC2 -> 网络接口 -> 搜索 lambda 名称 -> 复制 eni ref 然后转到 VPC -> 子网 -> select lambda 的子网 -> 流日志 -> 搜索eni 参考
如果您在数据库端口的流日志中看到 "REJECT OK",则表示网络 ACL 中缺少配置。
更新此问题:原来这个问题与数据库连接是在处理程序中进行的事实有关!由于 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;
}