Node.js Cluster: Управление работниками
Мы углубимся в архитектуру Node.js, чтобы полностью понять, как масштабировать наше приложение. Ясным решением является использование кластера https://nodejs.org/api/cluster.html. Все, кажется, хорошо, кроме описания управления работниками:
Однако Node.js не может автоматически управлять количеством работников для вас. Вы несете ответственность за управление рабочим пулом для нужд вашего приложения.
Я искал, как реально управлять работниками, но большинство решений говорит:
Начните столько рабочих, сколько у вас есть ядер.
Но я хотел бы динамически увеличивать или уменьшать количество моих работников, в зависимости от текущей нагрузки на сервер. Так что, если нагрузка на сервер и очередь становятся длиннее, я бы хотел начать следующий рабочий. По-другому, когда нагрузки не так много, я бы хотел закрыть рабочих (и оставить как минимум 2 из них).
Идеальным местом для меня будет очередь Мастер-процесса и событие, когда новый запрос поступает в Мастер-процесс. На этом месте мы можем решить, нужен ли нам следующий работник.
У вас есть какое-либо решение или опыт управления работниками из Master Thread в кластере? Начинать и убивать их динамически?
С Уважением,
Радек
2 ответа
Следующий код поможет вам понять, как создать кластер по запросу.
эта программа будет генерировать новый кластер через каждые 10 запросов.
Примечание: вам нужно открыть http://localhost:8000/ и обновить страницу для увеличения запроса.
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
var numReqs = 0;
var initialRequest = 10;
var maxcluster = 10;
var totalcluster = 2;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < 2; i++) {
var worker = cluster.fork();
console.log('cluster master');
worker.on('message', function(msg) {
if (msg.cmd && msg.cmd == 'notifyRequest') {
numReqs++;
}
});
}
setInterval(function() {
console.log("numReqs =", numReqs);
isNeedWorker(numReqs) && cluster.fork();
}, 1000);
} else {
console.log('cluster one initilize');
// Worker processes have a http server.
http.Server(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
// Send message to master process
process.send({ cmd: 'notifyRequest' });
}).listen(8000);
}
function isNeedWorker(numReqs) {
if( numReqs >= initialRequest && totalcluster < numCPUs ) {
initialRequest = initialRequest + 10;
totalcluster = totalcluster + 1;
return true;
} else {
return false;
}
}
Чтобы вручную управлять своими работниками, вам нужен уровень обмена сообщениями, чтобы облегчить межпроцессное взаимодействие. С главным и рабочим IPC можно эффективно обмениваться данными, по умолчанию и с точки зрения архитектуры это поведение уже реализовано в собственном модуле процесса. Однако я считаю, что нативная реализация не является гибкой или достаточно надежной для горизонтального масштабирования из-за сетевых запросов.
Одно очевидное решение Redis как посредник сообщений для облегчения этого метода связи между мастером и подчиненным. Однако это решение также как и его недостатки, а именно задержка контекста, напрямую связано с командой и ответом.
Дальнейшие исследования привели меня к RabbitMQ, который отлично подходит для распределения трудоемких задач между несколькими работниками. Основная идея рабочих очередей (или очередей задач) состоит в том, чтобы избежать немедленного выполнения ресурсоемкой задачи и ждать ее завершения. Вместо этого мы планируем задачу, которая будет сделана позже. Мы инкапсулируем задачу как сообщение и отправляем ее в очередь. Рабочий процесс, работающий в фоновом режиме, выскочит задачи и в итоге выполнит задание. Когда вы запускаете много рабочих, задачи будут распределены между ними.
Чтобы реализовать надежный сервер, прочитайте эту ссылку, она может дать некоторые идеи. Ссылка на сайт