【问题标题】:ECONNRESET in Express.js (Node.js) with multiple requestsExpress.js (Node.js) 中的 ECONNRESET 与多个请求
【发布时间】:2019-04-19 19:41:26
【问题描述】:

给定一个标准的 Express.js 设置

const express = require('express');
const app = express();
const router = express.Router();

router.get('/test/:id', (req, res) => {
  return res.status(200).json({ hello: 'world' });
});

app.use('/api', router);

app.listen(3000, () => console.info('Up on port 3000));

我正在向端点发出 1000 个请求,一个接一个:

const fetch = require('node-fetch');
for (let i = 0; i < 1000; i++) {
  let id = Math.floor(Math.random() * 12) + 1;
  fetch(`http://localhost:3000/api/test/${id}`).then(res => res.json()).then(data => console.log(data)).catch(error => console.error(error));
}

我确实看到返回的数据,但我时不时地看到 ECONNRESET 错误。 ECONNRESET 错误消息的数量也各不相同:有时我收到一些,有时更多。我确实理解该信息,但我无法解决其背后的问题。

这是一个错误示例:

{ FetchError: request to http://localhost:3000/api/test/8 failed, reason: connect ECONNRESET 127.0.0.1:3000
    at ClientRequest.<anonymous> (node_modules/node-fetch/lib/index.js:1345:11)
    at ClientRequest.emit (events.js:182:13)
    at Socket.socketErrorListener (_http_client.js:399:9)
    at Socket.emit (events.js:182:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process.internalTickCallback (internal/process/next_tick.js:72:19)
  message:
   'request to http://localhost:3000/api/departments/8 failed, reason: connect ECONNRESET 127.0.0.1:3000',
  type: 'system',
  errno: 'ECONNRESET',
  code: 'ECONNRESET' }

请注意,我已尝试使用 axios 发出请求,内置的 HTTP 模块全部可用。我确定问题出在我的 Express 应用程序处理请求但不确定如何准确修复它。

更新 1:

根据评论中的建议,这是异步版本:

async function f() {
  const array = Array.from(Array(1000).keys());
  for (const el of array) {
    try {
      let id = Math.floor(Math.random() * 12) + 1;
      const result = await fetch(`http://localhost:3000/api/test/${id}`).then(res => res.json());
      console.log(result);
      return result;
    } catch(e) {
      console.log(e);
    }
  }
}

f();

现在我偶尔会收到ECONNREFUSED 消息。

更新 2:

根据 Mazki516 的回答,这是可行的解决方案:

// previous require statements
const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  const cpuCount = os.cpus().length
  for (let i = 0; i < cpuCount; i++) {
      cluster.fork()
  }
} else {
  const app = express();
  // rest of the route definitions
  // also app.listen() etc...
}
cluster.on('exit', worker => {
  console.log(`${worker.id} removed`);
  cluster.fork();
});

【问题讨论】:

  • 您正在尝试在 sync 代码(for 循环)中使用 aync 操作(获取)。见this,也许有帮助。
  • 更新了代码,现在在某些情况下我会从 fetch 中得到 ECONNREFUSED。

标签: javascript node.js http express econnreset


【解决方案1】:

您看到这种情况的原因之一是您以“并行”方式进行调用。 您确实开始一个接一个地调用,但循环可能会在服务器返回的第一个结果之前结束。 循环一直持续到结束,使调用堆栈充满了对服务器的 1000 个异步请求。

您正在达到硬件/软件限制,并且代码没有任何问题。 如果您确实想构建一个可以同时处理 1k(以及更多)请求的服务器,我会查看 node 的“集群”模块。

请注意,在服务器之间进行网络工作时,可以使用并发限制。 (例如:最多并发 4 个请求)

但您始终可以将服务器扩展到一台机器之外并处理更多流量。

【讨论】:

  • 有没有办法提高限制?您能否详细说明并发请求?
  • 您可以随时尝试调整文件描述符限制(操作系统级别)和超时(在快速服务器中)。但这些只是“小”修复,而不是真正的解决方案。请查看集群模块,以便您快速了解如何扩展您的应用程序超越一次进程(多核服务器)。
  • 关于并发,Nodejs是基于事件驱动的架构,你将任务放入队列中等待它们完成。您的第一个代码,只是创建了 1k 个请求,而无需等待其中一些在其他请求之前完成。这是一种不好的做法,尤其是在 IO(网络、文件系统)上工作。同样,如果您想要“更多功能”/“果汁”;),请扩展您的应用程序,并确保您不会将许多任务放入队列中。
  • 您知道如何在 Express 应用中设置并发限制吗?
  • Express 并发限制受限于 Nodejs 进程并发限制,这受限于你的 cpu/memory/network 的性能。这不是您设置或调整的数字,它取决于硬件性能。 (更好的性能,更多的并发)
猜你喜欢
  • 2015-04-16
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 2019-07-26
  • 2018-07-14
相关资源
最近更新 更多