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, который отлично подходит для распределения трудоемких задач между несколькими работниками. Основная идея рабочих очередей (или очередей задач) состоит в том, чтобы избежать немедленного выполнения ресурсоемкой задачи и ждать ее завершения. Вместо этого мы планируем задачу, которая будет сделана позже. Мы инкапсулируем задачу как сообщение и отправляем ее в очередь. Рабочий процесс, работающий в фоновом режиме, выскочит задачи и в итоге выполнит задание. Когда вы запускаете много рабочих, задачи будут распределены между ними.

Чтобы реализовать надежный сервер, прочитайте эту ссылку, она может дать некоторые идеи. Ссылка на сайт

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