(async) JSON RPC API 性能优化

(async) JSON RPC API performance optimization

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

我在下面放了一些代码

我做了什么

  1. ./server/server.js 创建一个带有 requestHandler() 作为请求处理程序的 http 服务器。它会做一些检查,然后调用 async requestProcessor() 来执行方法
  2. 方法在回购协议(这里是 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;
}

I have to define as async only the methods that should use await ?

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

In my SystemRepository, do I need to define InsertOneSystem as async ?

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

How can I do a simple test script to test the load ? Like requests per second, ... ?

我现在不回答这个问题,因为这是一个完全独立的领域,值得单独提问。你应该自己调查一下,如何测试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;
  });
}