Кластеризация Nodejs с помощью Sticky-Session

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server



  var sticky = require('sticky-session');
  var express = require('express');
  var app = express();

  app.get('/', function (req, res) {
      console.log('worker: ' + cluster.worker.id);
      res.send('Hello World!');
  });


  var server = http.createServer(app);
      sticky.listen(server,3000);

  console.log(`Worker ${process.pid} started`);
}

Я посмотрел документацию по кластеризации nodejs и sticky-сессии и другой ответ переполнения стека относительно этого

  var cluster = require('cluster');
  var http = require('http');
  var sticky = require('sticky-session');
  var express = require('express');
  var app = express();

  app.get('/', function (req, res) {
      console.log('worker: ' + cluster.worker.id);
      res.send('Hello World!');
  });


  var server = http.createServer(app);
      sticky.listen(server,3000);

Если приведенный выше фрагмент кода выполняется без разветвления, он работает нормально, но никогда не работает, как показано в приведенном выше кластерном примере, в котором потоки запускаются, но сервер никогда не инициализируется.

Я читал, что есть альтернатива sticky-cluster, может кто-нибудь дать правильный авторитетный ответ по этой теме, который будет полезен для людей, ищущих то же самое, и другая главная проблема, связанная с этим, - это объект app.locals, который используется для хранения переменных для экземпляр приложения и вхождение нескольких экземпляров сервера приводит к его поломке, так как значения будут различаться в разных экземплярах, поэтому такой подход вызывает большие проблемы и приводит к поломке приложения. Поэтому при ответе не копируйте, не вставляйте код, дайте подробный ответ с подробным описанием подходить к его выгоде и недостаткам.

Я не ищу ответ, ограниченный использованием модуля stickj-sessionjj, я приветствую все другие подходы, в которых используются все ядра процессора, но обеспечиваю непрерывность сеанса.

Если это связано с RedisStore или MongoDb store, то все в порядке, я хочу знать о стандартном подходе в случае приложения nodejs с кластеризацией с непрерывностью сеанса.

https://github.com/indutny/sticky-session

https://nodejs.org/api/cluster.html

/questions/35540951/kak-ispolzovat-sticky-sessiyu-s-klasterom-v-ekspress-uzle-js/35540959#35540959

2 ответа

В вашем коде есть небольшая проблема. Модуль "sticky-session" уже использует модуль "cluster" в node.js. Вам не нужно "fork ()", потому что sticky-session уже сделает это за вас. Давайте узнаем, как:

var cluster = require('cluster'); // Only required if you want the worker id
var sticky = require('sticky-session');

var server = require('http').createServer(function(req, res) {
  res.end('worker: ' + cluster.worker.id);
});
sticky.listen(server, 3000);

вызов sticky.listen() уже вызовет рабочих для вас. Смотрите реализацию listen () ниже

 function listen(server, port, options) {
  if (!options)
    options = {};

  if (cluster.isMaster) {
    var workerCount = options.workers || os.cpus().length;

    var master = new Master(workerCount, options.env);
    master.listen(port);
    master.once('listening', function() {
      server.emit('listening');
    });
    return false;
  }
  return true;
}

Эта строка var master = new Master(workerCount, options.env) отвечает за порождение рабочих. см. реализацию Master() ниже:

function Master(workerCount, env) {
  net.Server.call(this, {
    pauseOnConnect: true
  }, this.balance);

  this.env = env || {};

  this.seed = (Math.random() * 0xffffffff) | 0;
  this.workers = [];

  debug('master seed=%d', this.seed);

  this.once('listening', function() {
    debug('master listening on %j', this.address());

    for (var i = 0; i < workerCount; i++)
      // spawning workers
      this.spawnWorker();
  });
}

Поэтому, действительно, когда вы вызываете sticky.listen (сервер, порт), вы на самом деле вызываете cluster.fork(). Следовательно, вам не следует явно снова вызывать fork (). Теперь ваш код должен выглядеть так:

var cluster = require('cluster'); // Only required if you want the worker id
var sticky = require('sticky-session');

var server = require('http').createServer(function(req, res) {
  res.end('worker: ' + cluster.worker.id);
});

//sticky.listen() will return false if Master
if (!sticky.listen(server, 3000)) { 
  // Master code
  server.once('listening', function() {
    console.log('server started on 3000 port');
  });
} else {
  // Worker code
}

Следует помнить одну важную вещь: у порожденных рабочих будет свой EVENTLOOP и память, поэтому ресурсы не будут распределены между собой. Вы можете использовать "REDIS" или другие модули npm, такие как "memored", для совместного использования ресурсов разными работниками.

Надеюсь, что это решит обе ваши проблемы.

Я думаю, вы путаете липкую сессию с хранилищем общей памяти.

Позвольте мне помочь:

  • Модуль Sticky-sessions балансирует запросы по их IP-адресу. Таким образом, клиент всегда будет подключаться к одному рабочему серверу, и socket.io будет работать должным образом, но с несколькими процессами!

Внедрение липких сеансов означает, что теперь у вас есть несколько узлов, принимающих соединения. Тем не менее, это НЕ гарантирует, что эти узлы будут ПОДЕЛИТЬСЯ ту же память, как каждый работник имеет свой собственный eventloop и внутреннее состояние памяти.

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

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

Таким образом, чтобы решить эту проблему, нам потребуется использовать что-то вроде Redis, чтобы данные могли совместно использоваться несколькими узлами.

Надеюсь это поможет!

Если я правильно понимаю ваши вопросы, вы имеете дело с хранением данных в памяти или сессией. Это одна из известных проблем при аутентификации на основе сеанса в многоузловой или кластерной среде. Предположим, что вы позвонили в узел A и получили сеанс с именем sessionA, но для следующего вызова вы сделали это для узла B. Узел B ничего не знает о сеансе A. Люди пытаются решить эту проблему с помощью липкой сессии, но этого недостаточно. Хорошей практикой будет использование альтернативного подхода, такого как JWT или oAuth2. Я предпочитаю JWT для обслуживания связи обслуживания. JWT ничего не хранит и не сохраняет состояния. Он отлично работает с REST, поскольку REST также не имеет состояния. Здесь https://tools.ietf.org/html/rfc7519 - это спецификация реализации JWT. Если вам нужен какой-то токен обновления, в этом случае вам нужно рассмотреть хранилище. Хранилище может быть любым, например, REDIS, MongoDB или любой другой базой данных на основе SQL. Для дальнейшего разъяснения о JWT в nodejs:

https://jwt.io/

https://jwt.io/introduction/

https://www.npmjs.com/package/jsonwebtoken

https://cloud.google.com/iot/docs/how-tos/credentials/jwts

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