我现在正在处理一个显示项目列表的项目。为了检索这些数据,页面调用了一个可调用的云函数,该函数从MySQL服务器查询数据。这个MySQL服务器和我们的云功能一样,是我们在谷歌云平台上项目的一部分。
我们的客户经常使用显示这些项目的页面,上周二他们报告了一些数据没有显示或显示时间很长的问题。查看了当时的云功能日志后,我们看到了很多超时,然后出现了一些错误:
CloudSQL警告:需要您的操作来更新您的功能并避免潜在的中断。请参阅https://cloud.google.com/functions/docs/sql#troubleshooting有关其他详细信息:googleapi:错误429:超出了配额组"default"的配额,并限制了消费者"project_number:[some-number]'的服务"sqladmin.googleapis.com"的"每100秒每个用户的查询数"。,速率限制超出
我不完全确定这是否是问题的原因,但这似乎是我们无论如何都应该做的事情。据我所知,我们可以每100秒向MySQL服务器发送每个用户300个查询。所以大约每秒3次。云功能本身只向服务器发送2个查询。一个用于检索具有应用的筛选器的当前页面的数据,另一个用于获取总记录计数。但是,在执行查询时,我们不会发送任何用户信息。因此,我认为,如果每个150个用户触发可调用,那么将执行300个查询,并将其计入配额,就像它们是由单个用户完成的一样。因为它是一个服务器,云功能,实际执行查询。该错误还提到配额组"default"。
下一页告诉我应该能够传递一个"quotaUser"参数来指定请求应该计入配额的特定用户。
https://cloud.google.com/apis/docs/capping-api-usage#limiting_requests_per_second_per_user
然而。。。我不知道如何在查询中传递该参数。我读到一些东西,这个参数可以在url参数或头中使用,但我们使用Node.js-mysql包来执行这些查询,我不知道如何告诉它发送这个参数。这是我们设置mysql连接时遵循的指南。我们使用的是相同的mysql包。
https://cloud.google.com/sql/docs/mysql/connect-functions#node.js
我认为,如果GCP指南告诉我们使用mysql包,那么它也应该以某种方式指定这个quotaUser。
如果有人能帮我解决这个问题,我将不胜感激。我有点卡住了,找不到任何关于如何为MySQL查询传递此参数的文档或示例。
这就是我们连接MySQL服务器的方式:
import { config } from '../config';
import { createConnection, Connection, ConnectionConfig } from 'mysql';
export function connectToMySQLDatabase(): Connection {
const connectionName: string | undefined = process.env.INSTANCE_CONNECTION_NAME || `${config.firebaseProjectId}:${config.mysqlConfig.regionId}:${config.mysqlConfig.instanceId}`;
const dbUser: string | undefined = process.env.SQL_USER || config.mysqlConfig.user;
const dbPassword: string | undefined = process.env.SQL_PASSWORD || config.mysqlConfig.password;
const dbName: string | undefined = process.env.SQL_NAME || config.mysqlConfig.databaseName;
const mysqlConfig: ConnectionConfig = {
user: dbUser,
password: dbPassword,
database: dbName,
dateStrings: true,
socketPath = `/cloudsql/${connectionName}`;
};
return createConnection(mysqlConfig);
}
以及我们如何执行查询:
exports.itemQuerySQL = functions
.region(config.region)
.runWith({
timeoutSeconds: 60,
memory: '1GB'
})
.https
.onCall(async (request: GetItemsRequest, context) => {
const mysqlConnection: Connection = connectToMySQLDatabase();
try {
return await queryItems(request, mysqlConnection);
} catch (error) {
throw error;
}
finally {
mysqlConnection.end();
}
});
async function queryItems(request: GetItemsRequest, mysqlConnection: Connection): Promise<CallableQueryResponse<string>> {
let query = '';
let values = [];
// Removed a bunch of code irrelevant to the issue that builds up the query and values array.
const results: any[] = await performQuery(mysqlConnection, sqlQuery, sqlQueryValues);
return {
results: results,
// Some other properties
};
}
async function performQuery(mysqlConnection: Connection, query: string, values?: (string | string[] | number | null)[]): Promise<any> {
return new Promise((resolve: (value?: unknown) => void, reject: (reason?: any) => void): void => {
mysqlConnection.query(query, values, (error: MysqlError, results: any) => {
if (error) {
return reject(error);
} else {
return resolve(results);
}
});
});
}
除了构造查询本身的代码外,我还省略了大部分错误处理,以保持这些示例的规模较小。
quotaUser指的是最终用户,它不是与您可能使用的其他GCP产品相关联的配额,因此在这个问题上对您没有帮助。
要解决您的问题,您需要实现连接池。现在,您正在为每个请求创建一个新的连接,这样可以更快地达到此配额。通过使用连接池,您将重用这些连接。