【问题标题】:many queries postgres (node), no parallel queries?许多查询postgres(节点),没有并行查询?
【发布时间】:2019-08-20 19:55:48
【问题描述】:

我正在使用 postgres-node (pg) 包运行节点服务器。

我编写了一个程序,它一次向我的 postgres 数据库请求 n 个查询(例如 20,000 个)。

当我对 几个客户 也想同时查询 20,000 个客户执行此操作时,没有并行性。这意味着,第二个客户端的请求将排队,直到第一个客户端完成所有查询。

这是 postgres 的正常行为吗?如果是,如果没有并行性,我如何防止一个用户获得所有资源(而其他用户必须等待)?

这是我的代码:

const express = require('express');
const app = express();
const { Pool } = require("pg");
const pool = new Pool();


benchmark(){
    pool.connect((err, client, done) => {
      if (err) throw err;
      client.query("SELECT * from member where m_id = $1", [1], (err, res) => {
        done();
        if (err) {
          console.log(err.stack);
        } else {
          console.log(res.rows[0]);
        }
      });
    }); 
}


app.get('/', function(req, res) {
  for(let i=0;i<20000;i++){
    benchmark();
  }
});

【问题讨论】:

  • 听起来好像 Node.js 在同一个连接上运行每个查询。您是否创建了连接池?
  • 我稍微编辑了我的代码,但是你可以看到我创建了一个连接池。
  • " 没有并行性.." 节点是异步的,您可以使用 Promise 或生成更多客户端/池并调整您的最大连接数(如我的答案),但是由于多个客户端运行大约 20.000 个查询,它们不会立即或并行地解决结果。您尝试实现的确切目标是什么?

标签: node.js postgresql node-postgres node-pg-pool


【解决方案1】:

首先你需要创建一个连接池,为了方便起见,这里有一个单独的模块(node-pg-sql.js)中节点的pg的例子:

节点-pg-sql.js:

const { Pool } = require('pg');

const pool = new Pool(fileNameConfigPGSQL);

module.exports = {
  query: (text, params, callback) => {
    const start = Date.now()
    return pool.query(text, params, (err, res) => {
      const duration = Date.now() - start
  //    console.log('executed query', { text, duration, rows: res.rowCount })
      callback(err, res)
    })
  },
  getClient: (callback) => {
    pool.connect((err, client, done) => {
      const query = client.query.bind(client)

      // monkey patch 
      client.query = () => {
        client.lastQuery = arguments
        client.query.apply(client, arguments)
      }

      // Timeout 5 sek
      const timeout = setTimeout(() => {
     //   console.error('A client has been checked out for more than 5 seconds!')
     //   console.error(`The last executed query on this client was: ${client.lastQuery}`)
      }, 5000)

      const release = (err) => {
        // 'done' Methode - returns client to the pool
        done(err)

        // clear Timeouts
        clearTimeout(timeout)

        // reset der Query-Method before Monkey Patch
        client.query = query
      }

      callback(err, client, done)
    })
  }
}

在您的 postgresql.conf 中(在 Linux 上通常在 /var/lib/pgsql/data/postgresql.conf 下)将 max-connection 设置为所需的值:

max_connection = 300

记住:

每个 PostgreSQL 连接都会消耗 RAM 来管理连接或使用它的客户端。您拥有的连接越多,您将使用的 RAM 就越多,而这些 RAM 可用于运行数据库。

在增加max-connections 的同时,您还需要增加shared_bufferskernel.shmmax 以使客户端连接增加有效。

当您想从您的一个路由/端点运行查询时,只需要单独的客户端池文件,例如:

const db = require('../../../node-pg-sql');

module.exports = (router) => {

router.get('/someRoute', (req, res) => {
    console.log(`*****************************************`);
    console.log(`Testing pg..`);
    let sqlSelect = `SELECT EXISTS (
          SELECT 1 
          FROM   pg_tables
          WHERE  schemaname = 'someschema'
        )`;
    db.query(sqlSelect, (errSelect, responseSelect) => {
      if (errSelect) {
        /* INFO: Error while querying table */
        console.log(`*****************************************`);
        console.log(`ERROR WHILE CHECKING CONNECTION: ${errSelect}`);
      } 
      else {
        // INFO: No error from database
        console.log(`*****************************************`);
        console.log(`CONNECTION TO PGSQL WAS SUCCESSFUL..`);
        res.json({ success: true, message: responseSelect, data:responseSelect.rows[0].exists });

      }
    })
  });

}

编辑:

“没有并行性..”

Node 是异步的,您可以使用 Promise 或生成更多客户端/池并调整您的最大连接数(如我的回答中所述,但请记住主机的性能),但有多个客户端运行20.000 个查询,它们不会立即或并行地得到结果。您尝试实现的具体目标是什么?

“这是 postgres 的正常行为吗?”

这是由于节点的事件循环以及运行 Postgres 的主机的某些性能限制。

【讨论】:

  • 如果你看一下我的代码,这几乎就是我所做的(只是没有所有这些开销)
  • Postgres 端的 max-connection = 1000 太高了。即使使用真正高端的硬件,500 也可能超过服务器的处理能力
  • @a_horse_with_no_name 感谢您提供信息 - 我将编辑我的答案。通过分发到多个高性能 postgre 服务器的权重共享是否可以解决 OP 的问题?
  • 配置应该基于并发客户端的数量,而不是发送到数据库的查询总数(所有客户端)。
  • @a_horse_with_no_name 我很清楚,我的问题如下:当并发客户端的数量及其负载过高时,唯一的解决方案是使用多个主机/sql-servers并分发客户端连接,对吗?
猜你喜欢
  • 2015-07-17
  • 1970-01-01
  • 1970-01-01
  • 2020-02-05
  • 1970-01-01
  • 2020-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多