Что вызывает node.js обрабатывает состояние блокировки, которое удаляет многопоточность? - PullRequest
0 голосов
/ 02 февраля 2019

Я пытаюсь создать 'многопоточный' экспресс-сервер, который будет порождать процесс, который будет выполнять задачу.

Вся идея этого заключается в том, чтобы реорганизовать мой высокоинтенсивный однопоточный узелПриложение .js, чтобы я мог порождать больше процессов и, следовательно, одновременно выполнять отдельные интенсивные задачи.

// Primary app (master).
// File called: app.js
const express = require('express');
const { fork } = require('child_process');
const app = express();

var counter = 0;
app.post('/intensiveTask', async (req, res) => {
    try {
        const forked = fork('./child.js');
        console.log(`forked child: ${++counter}`)
        forked.send(counter);
        forked.on('message', (m) => {
              console.log('from child: ' + m);
              res.sendStatus(200);
              forked.kill();
        });
     } catch (err) {
        console.log(err.stack)
        res.json({ error: err.message || err.toString() });
     }
});

try {
    app.listen(8080);
} catch (err) {
    console.error(`Failed to start the server due to the following error: ${err}`);
}


// Process app (child).
// File called: child.js

process.on('message', (m) => {
    console.log('inside child: ' + m);

    var time = Math.floor(Math.random() * Math.floor(5000));
    console.log(`about to wait ${time} for process ${m}`);

    setTimeout(() => {
        process.send(`finish... ${m}`);
    }, time);

});

Основная проблема, с которой я сталкиваюсь, связана с этими результатами с использованием JMeter: для 50 потоковЯ получаю около 16 с.Для 100 потоков я получаю около 32 с.И проблема в том, что все они прибывают в одно и то же время.Я ожидал, что первые запросы будут приходить раньше, а не все одновременно в конце.Поэтому мне интересно, что может быть причиной этого состояния блокировки ...

In the begining block: 
...
forked child: 176
forked child: 177
forked child: 178
forked child: 179
...
In the midddle block:
...
about to wait 735 for process 159
about to wait 4475 for process 133
about to wait 518 for process 131
inside childe: 125
about to wait 3909 for process 100
...
At the end, a block of finishing state :
...
from child: finish... 84
from child: finish... 81
from child: finish... 83
from child: finish... 88
...

1 Ответ

0 голосов
/ 02 февраля 2019

Если вы запустите 100 процессов и попросите их выполнить одинаковую нагрузку на ЦП, ваша ОС попытается распределить ЦП между этими 100 процессами настолько равномерно, насколько это возможно.Это приведет к тому, что все 100 процессов завершатся примерно в одно и то же время.

Кроме того, для всей системы НЕ эффективнее запускать больше рабочих процессов, которые все выполняют нагрузку на ЦП, чем у вас есть ядра вваш процессор, потому что это просто создает дополнительные накладные расходы для ОС, чтобы постоянно разделять время между ними, что умаляет общую пропускную способность.

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

Вы можете создать столько рабочих процессов, сколько у вас ядер, и создать очередь для входящей работы.,Когда поступает входящий запрос, вы видите, есть ли свободный работник.Если есть, вы даете работу свободному работнику.Если свободного работника нет, запрос отправляется в очередь FIFO.Когда один из рабочих заканчивает работу, вы берете самый старый элемент из очереди и передаете этот запрос работнику, а не только что закончили.Эта архитектура позволит первым запросам завершаться раньше и заставит последующие ждать.Это также масштабируемо для гораздо больших нагрузок, потому что, очевидно, если вы создаете новый процесс для каждого нового запроса, довольно скоро у вас будет так много процессов, что вы потратили много ресурсов на вашем сервере (особенно памяти), и все процессы просто конкурируютдруг с другом.

Другой вариант - использовать модуль кластеризации в файле node.js.Это создаст один процесс для каждого ядра ЦП в вашей системе и автоматически перенаправит входящий запрос одному из этих процессов, включая передачу фактического входящего HTTP-соединения, чтобы рабочий мог даже отправить ответ за вас.

У меня нет конкретной рекомендации, но есть также модули очереди заданий, уже написанные для node.js, так что вы также можете использовать один из них вместо написания своего.

...