Answer the question
In order to leave comments, you need to log in
Node.js, socket.io, cluster. How to organize the architecture of a multiplayer game?
Good afternoon!
There is a game server on node.js + socket.io. Game rooms are spinning on the server. Each room is for 2-4 players. The room is essentially an instance of the game engine with the current state of the game + the players that are connected to this game room (from the point of view of the code, the room is a js object, and the players differ by socket id).
Clients interact with the server using socket.io and only enter game moves, get the updated game state from the server.
On the server, game events are routed - from which player the move came, to which game room this move should be given.
Now the task is to improve the application for a higher load. There are two goals for optimization - 1) a greater number of simultaneous connections and 2) parallel calculation of game moves. The option of using the cluster module is being considered. It would be desirable to take out costly operations in worker'y. But there is the following difficulty. An array of game rooms with their current state should be stored centrally. And this data (rather complex js-objects) cannot be placed in the database. It seems like the storage of this data on the master suggests itself. And from workers it is required to provide access to them. Moreover, some other locking mechanism is required so that two workers do not try to work simultaneously with one piece of memory.
Has anyone encountered a similar problem? How did you implement the interaction between workers and master?
Any other options are also being considered - maybe it’s worth doing something differently at all? Share your experience, you have probably already faced similar tasks.
Answer the question
In order to leave comments, you need to log in
In general, you yourself answered your own question: we use a cluster, a master and several workers (usually by the number of cores). The data that everyone needs is stored either on the master or in the noskl, as indicated above. Workers ask permission to update the data, and if the current record is now blocked by someone, then they wait. If not locked, then lock and update, then release. At least he did just that.
И эти данные (достаточно сложные js-объекты) нельзя поместить в БД
1. We scattered the server through the cluster http server (we did not use our own long-polling, socket.io) into several threads according to the number of cores in the system. There was also a need to store data in the main thread and process it there if necessary. Cluster provides the ability to communicate between child threads and the head one, this is done as follows:
In the head thread (master) we set the message event - which waits for a message from child threads
, we divide all the logic into 2 files server.js (Master) and worker.js
var config = {
numWorkers: require('os').cpus().length,
refreshTime: 1000, // Milliseconds between data refreshes.
waitTime: 90, //Время в секундах когда пользователь считается оффлайн
worker: {
port: XXXX,
setNoDelay: true,
mongoUrl: 'mongodb://XXX:[email protected]/tmp/mongodb-270XX.sock'
}
};
cluster.setupMaster({
exec: "worker.js"
});
for (var i = 0; i < config.numWorkers; i++)
(function(worker) {
worker.on('message', function(data) {
switch(data.routeType){ // мы в сообщениях преедавали массив , routeType - переменная масисива которую мы ввели и в нашем случае она обозначала какоето действие
case 'act1':
// Что то делаем, выполняем какойто код массив data может содержать еще какието элементы котоыре вы будете обрабатывать
break;
case 'act1':
// Второе действие
break;
default:
break;
}
});
worker.on('exit', function(code, signal) {
console.log('Worker died: ', worker.process.pid, code, signal); // Сообщаем в консоль что у нас подох один из потоков
});
})(cluster.fork({WORKER_CONFIG: JSON.stringify(config.worker)})); // Форкаем потоки
process.on('message', function(data){ // получаем сообщение от головного потока
switch(data.routeType){
case 'myMess1':
// Выполняем свой код
break;
case 'myMess2':
// Второе действие
break;
default:
break;
}
}
var procMess = {
routeType: 'myMess',
//.......... любые ваши данные которые нужно передать
};
process.send(procMess); // Отправка данных в головной поток
2.After the new year, we decided to try out socket.io - we liked the fact that it immediately implements both web sockets and long-polling in itself, we assembled the solution without any problems in one thread.
An interesting thing began when they tried to parallelize
until a solution was found, they ran into people with the same problems, they used Reddis - until they really want to install it.
adamnengland.wordpress.com/2013/01/30/node-js-clus...
Александр, доброго времени суток. Полагаю, на свой вопрос ответ уже нашли, теперь хотел бы обратиться к вам за консультацией. Сам проектирую браузерку — клиент на Unity, сервер на node.js, бд на redis (orm для неё на jugglingdb, очень похожа на mongoose), связь на tcp. Хочу сразу попробовать кластерную архитектуру, дабы потом не пришлось в спешке переписывать логику под неё в случае неожиданного роста онлайна.
Как и у вас, игрушка будет пошаговой (боёвка — в стиле jrpg). Единственное, что в бою завязано на таймер — выдача тому или иному игроку права хода на определённый лимит времени (таймаут хода) и централизованное управление просмотра анимаций ударов и заклинаний («анимация удара файрболлом 5 секунд, после передача хода следующему игроку»).
Вне боёв персонажам нужен временной луп для постепенного восстановления параметров.
Какого рода задачи логично распределить в воркеры? Допустимо ли использовать redis pub-sub для обмена очень большим количеством сообщений между потоками? Буду очень признателен вашим советам.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question