ECONNRESET в Express.js (Node.js) с несколькими запросами

Учитывая стандартную настройку 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.info(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.info(result);
      return result;
    } catch(e) {
      console.info(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.info(`${worker.id} removed`);
  cluster.fork();
});

Вы пытаетесь использовать действие aync (выборка) в коде sync (цикл for). См. это, может это поможет.

lependu 16.11.2018 16:45

обновил код, теперь в некоторых случаях я получаю ECONNREFUSED из выборки.

Tamas 16.11.2018 16:55
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
7
2
6 111
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Одна из причин, по которой вы это видите, заключается в том, что вы звоните «параллельно». Вы запускаете вызовы один за другим, но циклы заканчиваются, вероятно, до того, как сервер вернет первые результаты. Цикл продолжается до конца, в результате чего стек вызовов заполняется 1000 асинхронными запросами к серверу.

Вы выходите за пределы аппаратного / программного обеспечения, и с кодом все в порядке. Если вы действительно хотите создать сервер, который может одновременно обрабатывать 1 КБ (и многое другое) запросов, я бы посмотрел на «кластерный» модуль узла.

Обратите внимание, что при выполнении сетевой работы между серверами допустимо использовать ограничение параллелизма. (например: до 4 запросов одновременно)

но вы всегда можете масштабировать свой сервер за пределы одной машины и обрабатывать гораздо больше трафика.

Есть ли способ увеличить лимит? Не могли бы вы подробнее рассказать о параллельных запросах?

Tamas 16.11.2018 16:59

Вы всегда можете попробовать настроить ограничения файловых дескрипторов (уровень ОС) и таймауты (на экспресс-сервере). но это всего лишь «мелкие» исправления, а не реальное решение. Пожалуйста, ознакомьтесь с модулем кластера, чтобы вы быстро узнали, как масштабировать свое приложение за пределами однократного процесса (многоядерный сервер).

Mazki516 16.11.2018 17:12

Что касается параллелизма, Nodejs основан на архитектуре, управляемой событиями, где вы помещаете задачи в очередь и ждете их завершения. вы первый код, только что создали 1k запросов, не дожидаясь завершения некоторых из них раньше других. Это плохая практика, особенно при работе с вводом-выводом (сеть, файловая система). Опять же, если вы хотите «больше мощности» / «сока»;), масштабируйте свое приложение и убедитесь, что вы не помещаете много задач в очередь.

Mazki516 16.11.2018 17:14

Знаете ли вы, как установить ограничение параллелизма в приложении Express?

Tamas 16.11.2018 17:20

Ограничение экспресс-параллелизма ограничено ограничениями параллелизма процесса Nodejs, которые ограничены производительностью вашего процессора / памяти / сети. это не число, которое вы устанавливаете или настраиваете, и оно зависит от производительности оборудования. (лучшая производительность, больше параллелизма)

Mazki516 16.11.2018 17:24

Другие вопросы по теме