Для начала, вот мой кривой стартовый скрипт (кривой потому-что не работает правильно), я постарался прокомментировать в нем все чтобы вам было понятнее:
#!/usr/bin/env node
const log = require("lib/log")(module);
require('globals'); //подключаем глобальные переменные global.****
const DatabaseController = require("lib/mysql"); //конструктор mysql запросов
const LocalizationController = require("localizationController"); //Загружает данные с локализацией из mysql в глобальные переменные
const CronJob = require('cron').CronJob;
const http = require('http');
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
var app = require('config/application'); //подключаем express со всеми его настройками (мидлвары, view-engine, роуты и др)
app.set('port', _G.cfg.port); //_G - глобальная переменная с конфигами и проч
var server = http.createServer(app);
var io = require('base/socket')(server); //подключаем socket.io, в 'base/socket' находятся основные события connect/disconnect, авторизация сокета и др.
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
if (cluster.isMaster) {
var i = 0; //поскольку мы в мастере, стартуем тестовую кронджобу, предпологаем что они будут выполняться только в мастере
let job = new CronJob('* * * * * *', function() {
log.info(`You will see this message every second: ${i}`);
i++;
}, null);
job.start();
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
log.info(`worker ${worker.process.pid} died`);
});
} else {
// для воркеров
server.listen(_G.cfg.port,()=>{ //запускаем сервер на нашем порту из конфига
LocalizationController.refreshLocales(() =>{ //загружаем локализации из бд в глоб переменную
let cc = DatabaseController.cacheController; // DatabaseController.cacheController - экземпляр для работы с redis
cc.getByMask(`${_G.cfg.session.matchingID}:*`,(err,data) =>{ //из redis загружаем все сессии
for(let i in data){
_G.sess[i.split(':').pop()] = data[i]; //кладем в глобальную переменную соответствие id-юзера и session-id
//их мы потом будем использовать для отправки данных нужному сокету
}
app.set('io', io);
log.info(`App listen port: "${server.address().port}"`);
});
});
});
server.on('error', (error) =>{
//error handler
});
}
Здесь, у меня есть две наглядные проблемы,
первая - это проблема сокетов, они ведут себя безобразно, например, сокет с одним и тем-же id при одном запросе может проходить авторизацию несколько раз, я не понял как с этим разобраться, чтобы заставить из работать правильно - так же как и без cluster.
Вторая, и очень важная проблема, это глобальные переменные. Я там храню локализацию и соответствие id-сессий - id авторизованного пользователя, и возможно для чего-либо еще они будут использоваться. Здесь проблема в том, что для всех процессов свои глобальные переменные, а нужно их как-то обобщить, если один процесс что-то изменяет в глобальных переменных - то это изменение должно продублироваться для всех процессов. Я не понимаю как это сделать, единственно что приходит в голову - хранить эти данные в redis и оттуда брать при необходимости, но насколько это отразиться на производительности приложения, ведь взять из глобальной переменной проще чем делать запрос к redis.
Для меня это очень запутанная задача (особенно с сокетами), я не пойму где я делаю ошибки или что я вообще не так делаю. Надеюсь на вашу помощь...