问题描述
几个月来我一直在构建SaaS平台,当我开始扩展时,我遇到了相当庞大的GCP Cloud sql帐单,这使我意识到我没有正确处理连接。
我在Node上使用MysqL 5.7和MysqLjs。这是使用Vue构建的SPA。它分为客户端和服务器。云MysqL数据库的MysqL凭据保存在GCP Cloud Firestore中。最终用户登录后,将从Firestore中检索其数据库信息,并将其保存在客户端的状态管理区域中。
这是当前的数据流(从下至上)
CGP Cloud sql Database - Stores all of the bulk account data.
⬆
Server - responsible for transferring data between the Google Cloud sql Database and the Client.
⬆
Client - Responsible for UI and basic logic. Stores sql connection string behind the scenes to send to the server with queries.
⬆
Cloud Firestore - Stores 'environment variables' for the end users (MysqL database login data) which is sent to the client after authentication.
⬆
Firebase authentication - OAuth to ensure the proper party is logged in before retrieving their database information from Firestore and allowing access to the app.
当需要运行MySQL查询时,参数以及sql数据库连接字符串/对象将从客户端传递到服务器。服务器进行查询,然后将结果发送回客户端。
这意味着每次查询都会建立一个新的连接。因此,如果此人碰巧快速浏览了帐户,那么他们可能很快就会进行很多查询。
自从我实施了该系统以来,我的GCP云sql账单已经飙升。考虑到敏感信息保存在Firestore中,我想我可以将Vue客户端直接连接到数据库,数据库访问是IP敏感的,最终用户甚至都不知道它是后端的MysqL数据库。
我不知道那是不好的架构。我需要一些指导。我正计划迁移到Firebase Cloud Functions,因此我的服务器目前已设置为好像有几十个独立功能,例如:
getAccountsByStatus()
showAccountDataById()
notateAccountByFileNumber()
etc...
这里是一个例子:
客户
this.searchValue = this.$route.params.name;
axios
.post(`${rootUrl}/api/v1/search/name`,{
searchName: this.searchValue,host: this.serverDBase,user: this.userDBase,password: this.passDBase,schema: this.schemaDBase,})
.then((response) => (this.searchResults = response.data))
.finally(this.updateOverlay)
.catch((error) => {
throw error;
});
服务器
//* Search by name
app.post(`/api/v1/search/name`,(req,res) => {
let fullName = req.body.searchName;
let host = req.body.host;
let user = req.body.user;
let password = req.body.password;
let schema = req.body.schema;
// DELETED SANITIZATON BLOCK 1 FOR BREVITY
let selectStatement = `SELECT id,file_number,full_name,balance FROM devdb.primary WHERE fullname LIKE '%${full_name}%'`;
// DELETED SANITIZATON BLOCK 2 FOR BREVITY
let connection = MysqL.createConnection({
host: host,user: user,password: password,database: schema,port: 3306,});
if (connection.state === 'disconnected') {
connection.connect();
}
connection.query(selectStatement.toString(),(err,results) => {
if (err) {
console.log(err);
} else if (results.length() == 0) {
res.send([]);
return;
}
res.send(results);
});
});
在这种情况下通常会做什么?将连接保存在Vue客户端实例中并考虑是否已经来自安全的Firestore数据库进行直接查询?连接池?还是完全其他?
解决方法
是的,使用连接池 并且不要直接从客户端连接-请在服务器端进行连接。 连接将被延迟创建。使用池创建连接后,它将被存储在池中以供重用。
请参见节点mysql https://github.com/mysqljs/mysql#pooling-connections
另一个要签出的库也将是promise-mysql
。阳极mysql的答应包装器。
使用池时,可以从池中请求连接(在创建作为事务一部分所需的多个查询时很方便),也可以直接在池对象本身上执行查询。
即
pool.query('my statement')
.then((result) => doSomething(result))`