Что я должен использовать? Socket.io номера или Redis pub-sub?
Довольно простой вопрос. Я создаю игру в реальном времени, используя nodejs в качестве моего бэкэнда, и мне интересно, есть ли какая-либо информация, по которой более надежна и какая из них более эффективна?
Я сильно использую как Redis, так и Socket.io во всем моем коде. Поэтому я хочу знать, должен ли я использовать Socket.io Rooms, или мне было бы лучше использовать redis 'pub-sub?
Update:
Просто понял, что есть очень важная причина, почему вы можете использовать redis pub/sub over socket.io комнаты. С помощью Socket.io комнат, когда вы публикуете слушателям, клиенты (браузер) получают сообщение, с redis - это фактически клиенты (redis ~ on server), которые получают сообщения. По этой причине, если вы хотите сообщить всем (серверным) клиентам информацию, специфичную для каждого клиента, и, возможно, выполнить некоторую обработку, прежде чем переходить к клиентам браузера, вам лучше использовать redis. Используя redis, вы можете просто запустить событие для генерации индивидуальных данных каждого пользователя, где, как и в случае с socket.io, вы должны фактически генерировать все уникальные данные пользователей сразу, затем прокручивать их и отправлять им свои отдельные данные, что почти побеждает цель комнат, по крайней мере для меня.
К сожалению, для моих целей я застрял с redis на данный момент.
Обновление 2: Завершение разработки плагина для использования только 2 подключений redis, но все же позволяет обрабатывать отдельные клиенты, см. ниже ответ.
Ответы
Ответ 1
Redis pub/sub отлично, если все клиенты имеют прямой доступ к redis. Если у вас несколько серверов node, можно отправить сообщение другим.
Но если у вас также есть клиенты в браузере, вам нужно что-то еще для передачи данных с сервера клиенту, и в этом случае socket.io отлично.
Теперь, если вы используете socket.io с хранилищем Redis, socket.io будет использовать Redis pub/sub под капотом для распространения сообщений между серверами, а серверы будут распространять сообщения клиентам.
Таким образом, использование комнат socket.io с socket.io, настроенным с помощью магазина Redis, возможно, является самым простым для вас.
Ответ 2
Я закончил тем, что написал плагин node, чтобы позволить многим клиентам pub-sub, но требует только 2 redis-соединения вместо нового на каждом подключении сокетов, он должен работать вообще, полагал, что кто-то еще может найти использование для он.
Этот код предполагает, что вы запускаете и настраиваете socket.io, в основном в этом примере любое количество клиентов socket.io может подключаться, и он всегда будет использовать только два соединения redis, но все клиенты могут подписаться на свои собственные каналы. В этом примере все клиенты получают сообщение "сладкое сообщение!". через 10 секунд.
Пример с socket.io(с использованием redis pub-sub):
var
RPubSubFactory = require('rpss.js');
var
redOne = redis.createClient(port, host),
redTwo = redis.createClient(port, host);
var pSCFactory = new RPubSubFactory(redOne);
io.sockets.on('connection', function(socket){
var cps = pSCFactory.createClient();
cps.onMessage(function(channel, message){
socket.emit('message', message);
});
io.sockets.on('disconnect', function(socket){
// Dont actually need to unsub, because end() will cleanup all subs,
// but if you need to sometime during the connection lifetime, you can.
cps.unsubscribe('cool_channel');
cps.end();
});
cps.subscribe('cool_channel')
});
setTimeout(function(){
redTwo.publish('cool_channel', 'sweet message!');
},10000);
Фактический код плагина:
var RPubSubFactory = function(){
var
len,indx,tarr;
var
dbcom = false,
rPubSubIdCounter = 1,
clientLookup = {},
globalSubscriptions = {};
// public
this.createClient = function()
{
return new RPubSupClient();
}
// private
var constructor = function(tdbcom)
{
dbcom = tdbcom;
dbcom.on("message", incommingMessage);
}
var incommingMessage = function(rawchannel, strMessage)
{
len = globalSubscriptions[rawchannel].length;
for(var i=0;i<len;i++){
//console.log(globalSubscriptions[rawchannel][i]+' incomming on channel '+rawchannel);
clientLookup[globalSubscriptions[rawchannel][i]]._incommingMessage(rawchannel, strMessage);
}
}
// class
var RPubSupClient = function()
{
var
id = -1,
localSubscriptions = [];
this.id = -1;
this._incommingMessage = function(){};
this.subscribe = function(channel)
{
//console.log('client '+id+' subscribing to '+channel);
if(!(channel in globalSubscriptions)){
globalSubscriptions[channel] = [id];
dbcom.subscribe(channel);
}
else if(globalSubscriptions[channel].indexOf(id) == -1){
globalSubscriptions[channel].push(id);
}
if(localSubscriptions.indexOf(channel) == -1){
localSubscriptions.push(channel);
}
}
this.unsubscribe = function(channel)
{
//console.log('client '+id+' unsubscribing to '+channel);
if(channel in globalSubscriptions)
{
indx = globalSubscriptions[channel].indexOf(id);
if(indx != -1){
globalSubscriptions[channel].splice(indx, 1);
if(globalSubscriptions[channel].length == 0){
delete globalSubscriptions[channel];
dbcom.unsubscribe(channel);
}
}
}
indx = localSubscriptions.indexOf(channel);
if(indx != -1){
localSubscriptions.splice(indx, 1);
}
}
this.onMessage = function(msgFn)
{
this._incommingMessage = msgFn;
}
this.end = function()
{
//console.log('end client id = '+id+' closing subscriptions='+localSubscriptions.join(','));
tarr = localSubscriptions.slice(0);
len = tarr.length;
for(var i=0;i<len;i++){
this.unsubscribe(tarr[i]);
}
localSubscriptions = [];
delete clientLookup[id];
}
var constructor = function(){
this.id = id = rPubSubIdCounter++;
clientLookup[id] = this;
//console.log('new client id = '+id);
}
constructor.apply(this, arguments);
}
constructor.apply(this, arguments);
};
module.exports = RPubSubFactory;
Я удалился и попытался повысить эффективность настолько, насколько мог, но после нескольких тестов скорости, я пришел к выводу, что это было самым быстрым, что я мог получить.
Для обновленной версии: https://github.com/Jezternz/node-redis-pubsub