您如何处理SaaS平台的MySQL连接?

问题描述

几个月来我一直在构建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))`