Firebase 函数云 SQL 连接太多
Firebase Functions Cloud SQL Too Many connections
我正在开发一个应用程序,它使用 Firebase Functions 作为我的 Web 应用程序和 Google Cloud SQL (MySQL 5.7) 之间的 API 接口。
我有一个从客户端应用程序导入记录的过程;基本上,客户端应用程序读取一个 CSV 文件,然后为 CSV 文件中的每一行执行一个函数。该函数在处理记录期间执行三个或四个查询(检查主记录是否存在,创建它 and/or 其他需要的记录,更新此过程的统计记录)。
该函数按顺序为每一行调用,因此在 return 将数据发送到客户端应用程序然后处理下一行之前,一次处理的请求(行)不会超过一个,执行 3 或 4 个查询(async/await).
该过程适用于 1 到 100 行的 CSV 文件。一旦超过 900 行,Firebase 函数就会开始报告 ERROR Error: ER_CON_COUNT_ERROR: Too many connections
我的代码(如下所示)最初的连接限制为 10,但我将其增加到 100 个连接,但仍然失败。
这是我执行 SQL 查询的代码:
import * as functions from "firebase-functions";
import * as mysql from 'mysql';
export async function executeQuery(cmd: string) {
const mySQLConfig = {
host: functions.config().sql.prodhost,
user: functions.config().sql.produser,
password: functions.config().sql.prodpswd,
database: functions.config().sql.proddatabase,
connectionLimit: 100,
}
var pool: any;
if (!pool) {
pool = mysql.createPool(mySQLConfig);
}
return new Promise(function (resolve, reject) {
//@ts-ignore
pool.query(cmd, function (error, results) {
if (error) {
return reject(error);
}
resolve(results);
});
});
}
据我了解,使用我认为我在上面实现的池,每个请求都会获得一个连接,最多可达最大连接数。一旦处理完请求,每个连接都会自动 return 到池中。因此,即使释放连接需要一段时间,连接限制为 100,我应该能够在连接争用之前处理相当多的行(至少 20 行左右),然后进程将排队并在继续之前等待空闲连接。如果是的话,这里发生了什么?
我在这里找到了一篇文章:https://cloud.google.com/sql/docs/mysql/manage-connections,其中描述了一些我可以用来调整连接管理的附加设置:
// 'connectTimeout' is the maximum number of milliseconds before a timeout
// occurs during the initial connection to the database.
connectTimeout: 10000,
// 'acquireTimeout' is the maximum number of milliseconds to wait when
// checking out a connection from the pool before a timeout error occurs.
acquireTimeout: 10000,
// 'waitForConnections' determines the pool's action when no connections are
// free. If true, the request will queued and a connection will be presented
// when ready. If false, the pool will call back with an error.
waitForConnections: true, // Default: true
// 'queueLimit' is the maximum number of requests for connections the pool
// will queue at once before returning an error. If 0, there is no limit.
queueLimit: 0, // Default: 0
我很想尝试增加超时,但我不确定这是否真的影响了我。
由于我在 Firebase Functions(Google Cloud Functions 的幕后)中 运行 这个,这些设置真的适用吗?难道我的函数的 VM 不是在每次执行后都会重置,或者至少我的函数不会在每次执行后终止吗?在这种情况下,游泳池甚至存在吗?如果没有,那么如何在函数中进行此类处理?
当然,一个选择是将我的所有处理都推送给函数,只需为行数组发送一个 JSON 对象,然后让函数一次处理它们。我认为这应该正确使用池,但我担心我会遇到函数(5 分钟)的执行限制,这就是为什么我像我那样构建它。
愚蠢的开发人员把戏,我非常关注我的池代码,以至于我错过了我在错误的地方声明池变量。将池声明移到方法之外解决了我的问题。按照原来的代码,我正在为每个 SQL 查询创建一个池,这很快就用完了我所有的连接。
我正在开发一个应用程序,它使用 Firebase Functions 作为我的 Web 应用程序和 Google Cloud SQL (MySQL 5.7) 之间的 API 接口。
我有一个从客户端应用程序导入记录的过程;基本上,客户端应用程序读取一个 CSV 文件,然后为 CSV 文件中的每一行执行一个函数。该函数在处理记录期间执行三个或四个查询(检查主记录是否存在,创建它 and/or 其他需要的记录,更新此过程的统计记录)。
该函数按顺序为每一行调用,因此在 return 将数据发送到客户端应用程序然后处理下一行之前,一次处理的请求(行)不会超过一个,执行 3 或 4 个查询(async/await).
该过程适用于 1 到 100 行的 CSV 文件。一旦超过 900 行,Firebase 函数就会开始报告 ERROR Error: ER_CON_COUNT_ERROR: Too many connections
我的代码(如下所示)最初的连接限制为 10,但我将其增加到 100 个连接,但仍然失败。
这是我执行 SQL 查询的代码:
import * as functions from "firebase-functions";
import * as mysql from 'mysql';
export async function executeQuery(cmd: string) {
const mySQLConfig = {
host: functions.config().sql.prodhost,
user: functions.config().sql.produser,
password: functions.config().sql.prodpswd,
database: functions.config().sql.proddatabase,
connectionLimit: 100,
}
var pool: any;
if (!pool) {
pool = mysql.createPool(mySQLConfig);
}
return new Promise(function (resolve, reject) {
//@ts-ignore
pool.query(cmd, function (error, results) {
if (error) {
return reject(error);
}
resolve(results);
});
});
}
据我了解,使用我认为我在上面实现的池,每个请求都会获得一个连接,最多可达最大连接数。一旦处理完请求,每个连接都会自动 return 到池中。因此,即使释放连接需要一段时间,连接限制为 100,我应该能够在连接争用之前处理相当多的行(至少 20 行左右),然后进程将排队并在继续之前等待空闲连接。如果是的话,这里发生了什么?
我在这里找到了一篇文章:https://cloud.google.com/sql/docs/mysql/manage-connections,其中描述了一些我可以用来调整连接管理的附加设置:
// 'connectTimeout' is the maximum number of milliseconds before a timeout
// occurs during the initial connection to the database.
connectTimeout: 10000,
// 'acquireTimeout' is the maximum number of milliseconds to wait when
// checking out a connection from the pool before a timeout error occurs.
acquireTimeout: 10000,
// 'waitForConnections' determines the pool's action when no connections are
// free. If true, the request will queued and a connection will be presented
// when ready. If false, the pool will call back with an error.
waitForConnections: true, // Default: true
// 'queueLimit' is the maximum number of requests for connections the pool
// will queue at once before returning an error. If 0, there is no limit.
queueLimit: 0, // Default: 0
我很想尝试增加超时,但我不确定这是否真的影响了我。 由于我在 Firebase Functions(Google Cloud Functions 的幕后)中 运行 这个,这些设置真的适用吗?难道我的函数的 VM 不是在每次执行后都会重置,或者至少我的函数不会在每次执行后终止吗?在这种情况下,游泳池甚至存在吗?如果没有,那么如何在函数中进行此类处理?
当然,一个选择是将我的所有处理都推送给函数,只需为行数组发送一个 JSON 对象,然后让函数一次处理它们。我认为这应该正确使用池,但我担心我会遇到函数(5 分钟)的执行限制,这就是为什么我像我那样构建它。
愚蠢的开发人员把戏,我非常关注我的池代码,以至于我错过了我在错误的地方声明池变量。将池声明移到方法之外解决了我的问题。按照原来的代码,我正在为每个 SQL 查询创建一个池,这很快就用完了我所有的连接。