Lambda查询RDS数据库时表现不稳定问题求助
Lambda调用RDS Proxy时响应不稳定问题
测试代码时,Lambda有时无任何响应,有时可正常执行查询并返回数据,表现极不稳定,且无报错信息。已使用RDS Proxy,也未触发任何报错,怀疑问题与async/await的使用有关,代码如下:
async function RDSToken() { var signer = new AWS.RDS.Signer({ region: 'us-east-1', hostname: 'proxy', port: 3306, username: 'username' }); var host ='proxy' var user ='username' var db ='name' let token = signer.getAuthToken({username: 'admin' }); let connectionConfig = { host: host, user: user, database: db, ssl: { rejectUnauthorized: false}, password: token, authSwitchHandler: function ({pluginName, pluginData}, cb) { console.log("Setting new auth handler."); } }; connectionConfig.authSwitchHandler = (data, cb) => { if (data.pluginName === 'mysql_clear_password') { let password = token + '\0'; let buffer = Buffer.from(password); cb(null, password); }}; try { connection = await mysql2.createConnection(connectionConfig); } catch(err) { console.error('error connecting to the database'); console.error(err); var response = { statusCode: 500, "headers": { "Content-Type": "application/json" }, body: 'error connecting to the database' +err }; return response; } return connection } async function randomfact() { var connection = await RDSToken(); let sql = 'SELECT * FROM quote_header;'; return await new Promise((resolve, reject) => { connection.query(sql, (err, result) => { if (err) { reject(err); } else { resolve(result); } }); }); } async function Dashboard() { const result = await randomfact(); console.log(result) }
问题排查与修复
核心问题点
- 异步操作未等待:
signer.getAuthToken()是异步方法,直接赋值给token会得到一个未resolved的Promise,用它作为密码会导致认证流程随机失败,引发无响应。 - 连接泄漏:每次调用
RDSToken都会创建新连接,但使用后未关闭,Lambda复用执行环境时会耗尽连接资源,导致后续请求无响应。 - 全局变量污染:
connection未用let/const声明,成为全局变量,在Lambda复用环境中会导致连接混乱。 - 认证逻辑不完整:
authSwitchHandler只处理了mysql_clear_password插件,未处理其他情况,可能导致认证卡住无报错。
修复后的代码
const AWS = require('aws-sdk'); const mysql2 = require('mysql2/promise'); // 使用Promise版mysql2,避免手动封装 async function getRDSToken() { const signer = new AWS.RDS.Signer({ region: 'us-east-1', hostname: 'proxy', port: 3306, username: 'username' }); // 必须await获取token,确保拿到有效字符串 const token = await signer.getAuthToken({ username: 'admin' }); const connectionConfig = { host: 'proxy', user: 'username', database: 'name', ssl: { rejectUnauthorized: false }, password: token, authSwitchHandler: (data, cb) => { if (data.pluginName === 'mysql_clear_password') { const password = token + '\0'; cb(null, password); } else { // 处理未知认证插件,避免无响应 cb(new Error(`不支持的认证插件: ${data.pluginName}`)); } } }; try { const connection = await mysql2.createConnection(connectionConfig); return connection; } catch (err) { console.error('数据库连接错误:', err); return { statusCode: 500, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ error: '数据库连接失败', details: err.message }) }; } } async function getRandomFact() { const connection = await getRDSToken(); // 检查是否是连接错误响应 if (connection.statusCode) { return connection; } try { // 使用execute方法(Promise版)替代回调式query const [rows] = await connection.execute('SELECT * FROM quote_header;'); return rows; } catch (err) { console.error('查询错误:', err); return { statusCode: 500, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ error: '查询失败', details: err.message }) }; } finally { // 无论成功失败,都关闭连接,避免泄漏 await connection.end(); } } async function Dashboard() { const result = await getRandomFact(); console.log(result); }
额外优化建议
- 使用RDS Proxy时,建议用
createPool创建连接池,复用连接减少开销,避免频繁创建销毁连接。 - 给数据库操作添加超时配置,比如在
connectionConfig中设置timeout: 10000,防止无响应挂起。 - Lambda中避免全局创建资源,每次请求都通过连接池获取/释放连接,适配执行环境复用机制。
内容的提问来源于stack exchange,提问作者Ryan518
相关产品推荐
相关产品推荐

