【问题标题】:(async) JSON RPC API performance optimization(async) JSON RPC API 性能优化
【发布时间】:2019-11-19 21:52:41
【问题描述】:

我必须创建一个 JSON RPC API,它必须支持大流量并管理 postgreSQL 数据库。 为此,我为服务器选择了“http”,为数据库选择了pg-promise。 我的问题是我在理解和使用 Promise 和 async/wait 时遇到了一些困难,所以我不确定我做对了

我在下面放了一些代码

我做了什么

  1. ./server/server.js 创建一个使用requestHandler() 作为请求处理程序的http 服务器。它会做一些检查,然后调用async requestProcessor() 来执行该方法
  2. 这些方法在 repos(这里是 devices.js 中的事务)中定义为 async,在我下面的示例中,使用 await 来等待所需的结果

一些问题:

  1. 我必须将应该使用 await 的方法定义为 async 吗?
  2. 在我的 SystemRepository 中,是否需要将“InsertOneSystem”定义为 async
  3. 如何做一个简单的测试脚本来测试负载?比如每秒请求数,...?

提前致谢!

一点代码

server.js

const http = require('http');
const Database = require('../db');

const path = '/api/v1', port = 9000;
const methods = Database.methods;

/* hidden for brevity */

function sendResponse(res, response) {
  if (response) {
    const responseStr = JSON.stringify(response);
    res.setHeader('Content-Type', 'application/json');
    res.setHeader('Content-Length', responseStr.length);
    res.write(responseStr);
  } else {
    /* hidden for brevity */
  }
  res.end();
}

const requestHandler = (req, res) => {
  /* some checks, hidden for brevity */

  const body = [];
  req.on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    const bodyStr = Buffer.concat(body).toString();

    // parse body en JSON
    let request = JSON.parse(bodyStr);

    requestProcessor(request).then((response) => {
      sendResponse(res, response);
    });
  });
}

async function requestProcessor(request) {
  let response = {
    id: request.id,
    jsonrpc: '2.0',
  };

  try {
    response.result = await Promise.resolve(methods[request.method](request.params));
  } catch (err) {
    /* hidden for brevity */
  }

  return response;
}

const server = http.createServer(requestHandler);
server.listen(port, (err) => { /* hidden for brevity */ });

devices.js

'use strict';

/* hidden for brevity */

async function InsertOne(params) {
  return Database.tx('Insert-New-Device', async function(transaction) {
    let system = null, disks = null, cpus = null;

    const query = pgp.helpers.insert(params.data.device, Collections.insert) + " RETURNING *";
    let device = await transaction.one(query);

    // if a system is present, insert with diviceId and return
    if(params.data.system) {
      params.data.system.deviceid = device.deviceid;
      system = transaction.systems.InsertOne(params);
    }

    // same as system
    if(params.data.disks) {
      params.data.disks.deviceid = device.deviceid;
      disks = transaction.disks.InsertOne(params);
    }

    // same as system
    if(params.data.cpus) {
      params.data.cpus.deviceid = device.deviceid;
      cpus = transaction.cpus.InsertOne(params);
    }

    return {
      device: device,
      system: await system,
      disks: await disks,
      cpus: await cpus
    }
  })
  .then(data => {
    return data;
  })
  .catch(ex => {
    console.log(ex)
    throw new Error(ex);
  });
}

/* hidden for brevity */

const DevicesRepository = {
  InsertOne: InsertOne
};

module.exports = (db, pgpLib) => {
  /* hidden for brevity */
  return DevicesRepository;
}

systems.js

'use strict';

/* hidden for brevity */

async function InsertOneSystem(params) {
  var system = params.data.system;
  system.archid=2;
  system.distributionid=3;

  var query = pgp.helpers.insert(system, Collections.insert);
  if(params.return) query += " RETURNING *";

  return Database.one(query)
          .then(data => {
            return data;
          })
          .catch(ex => {
            throw new Error(ex);
          });
}

/* hidden for brevity */

const SystemsRepository = {
  InsertOne: InsertOneSystem
};

module.exports = (db, pgpLib) => {
/* hidden for brevity */

  return SystemsRepository;
}

【问题讨论】:

  • 看起来您在三个数据库调用中缺少await - transaction.systems.InsertOne,以及它下面的两个。哦等等,你在下面的变量上使用await,这有点不寻常,哈哈。

标签: node.js http asynchronous json-rpc pg-promise


【解决方案1】:

我只需要将应该使用 await 的方法定义为 async 吗?

必须 - 是的。但是你应该在所有返回 promise 的方法上使用async,这只是一种很好的编码风格,尤其是在 TypeScript 中。

在我的SystemRepository 中,我需要将InsertOneSystem 定义为异步吗?

你不必,但和上面一样,这是一种很好的编码风格;)

如何做一个简单的测试脚本来测试负载?比如每秒请求数,...?

我现在不回答这个问题,因为这是一个完全独立的领域,值得单独提问。您应该自己调查一下,如何测试 HTTP 服务负载。

稍微改进一下代码,因为你有很多冗余:

async function InsertOne(params) {
  return Database.tx('Insert-New-Device', async t => {
    let system = null, disks = null, cpus = null;

    const query = pgp.helpers.insert(params.data.device, Collections.insert) + " RETURNING *";
    let device = await t.one(query);

    // if a system is present, insert with diviceId and return
    if(params.data.system) {
      params.data.system.deviceid = device.deviceid;
      system = await t.systems.InsertOne(params);
    }

    // same as system
    if(params.data.disks) {
      params.data.disks.deviceid = device.deviceid;
      disks = await t.disks.InsertOne(params);
    }

    // same as system
    if(params.data.cpus) {
      params.data.cpus.deviceid = device.deviceid;
      cpus = await t.cpus.InsertOne(params);
    }

    return {device, system, disks, cpus};
  })
  .catch(ex => {
    console.log(ex); // it is better use "pg-monitor", or handle events globally
    throw ex;
  });
}

【讨论】:

  • 如果我错了,请纠正我,但是await 将代码“阻止”为同步函数对吗?像我一样放置await 不允许 pg-promise 异步执行所有插入并在所有插入完成后返回对象?
  • @Firlfire 一般来说异步逻辑会有区别。但是在这种情况下,您将针对同一个物理 IO 端口执行所有操作,因此您的代码和我的代码的结果将是相同的。
猜你喜欢
  • 2017-10-09
  • 1970-01-01
  • 2013-10-05
  • 1970-01-01
  • 2013-03-17
  • 2016-05-14
  • 2011-10-17
  • 2014-01-08
  • 1970-01-01
相关资源
最近更新 更多