【问题标题】:How do you handle MySQL connections for a SaaS platform?您如何处理 SaaS 平台的 MySQL 连接?
【发布时间】:2020-12-20 00:52:44
【问题描述】:

几个月来我一直在构建一个 SaaS 平台,当我开始扩展时,我遇到了一笔巨额 GCP Cloud SQL 账单,这让我意识到我没有正确处理我的连接。

我在 Node.js 上使用 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);
  });
});

在这种情况下通常会怎么做?考虑到它已经来自安全的 Firestore 数据库,将连接保存在 Vue 客户端实例中并进行直接查询?连接池?还是完全不同的东西?

【问题讨论】:

  • 通常你会做连接池,如果配置得当,MySQL 可以轻松处理数千个连接。如果不够,请使用 MySQL 代理,其中有几个很棒的代理可供选择。

标签: mysql sql node.js firebase nodejs-server


【解决方案1】:

是的,使用连接池 并且不要直接从客户端连接 - 在服务器端进行。 连接将被延迟创建。使用池时一旦创建连接,就会将其存储在池中以供重复使用。

见节点mysqlhttps://github.com/mysqljs/mysql#pooling-connections

另一个要检出的库也是promise-mysql。阳极 mysql 的承诺包装器。 使用池时,您可以从池中请求连接(在创建作为事务的一部分所需的多个查询时很方便),也可以直接在池对象本身上执行查询。

pool.query('my statement')
.then((result) => doSomething(result))`

【讨论】:

    猜你喜欢
    • 2020-08-04
    • 2010-10-02
    • 2011-12-26
    • 1970-01-01
    • 2016-05-15
    • 2016-01-05
    • 1970-01-01
    • 2014-12-22
    • 2010-12-26
    相关资源
    最近更新 更多