Czego powinienem używać? Socket.io pokoje Czy Redis pub-sub?

Dość proste pytanie. Buduję grę w czasie rzeczywistym używając nodejs jako zaplecza i zastanawiam się, czy są dostępne jakieś informacje, które z nich są bardziej niezawodne, a które bardziej wydajne? Używam mocno zarówno Redis jak i Socket.io w całym moim kodzie. Więc chcę wiedzieć, czy powinienem używać Socket.io 's Rooms or I would be better off using redis' pub-sub?

Aktualizacja: Właśnie sobie sprawę, że jest bardzo ważny powód, dla którego możesz chcesz użyć redis pub / sub nad socket.io pokoje. Z Socket.io pokoje kiedy publikujesz do słuchaczy, klienci (przeglądarka) otrzymują wiadomość, z redis to w rzeczywistości klienci (redis~na serwerze) odbierają wiadomości. Z tego powodu, jeśli chcesz poinformować wszystkich (serwerowych)klientów o informacjach specyficznych dla każdego klienta i być może wykonać pewne przetwarzanie przed przekazaniem do klientów przeglądarki, lepiej jest użyć redis. Korzystając z redis, możesz po prostu odpalić zdarzenie, aby wygenerować indywidualne dane każdego użytkownika, gdzie jak z socket.io trzeba faktycznie wygenerować wszystkich użytkowników unikalne dane na raz, a następnie pętli przez nich i wysłać im swoje indywidualne dane, co prawie poraża cel pokoi, przynajmniej dla mnie.

Niestety dla moich celów utknąłem na razie z redis.

Update 2: zakończył się rozwojem wtyczki do korzystania tylko z połączeń redis 2, ale nadal pozwalają na indywidualne przetwarzanie klienta, patrz odpowiedź poniżej....

Author: Josh Mc, 2013-02-18

2 answers

Redis pub / sub jest świetny w przypadku, gdy wszyscy klienci mają bezpośredni dostęp do redis. Jeśli masz wiele serwerów węzłów, jeden może wysłać wiadomość do innych.

Ale jeśli masz również klientów w przeglądarce, potrzebujesz czegoś innego do przesyłania danych z serwera do klienta, a w tym przypadku, socket.io świetnie.

Teraz, jeśli używasz socket.io ze sklepem Redis, socket.io użyje Redis pub / sub pod maską do propagowania wiadomości między serwerami, a serwery będą propagować Wiadomości do klientów.

Więc używając socket.io pokoje z socket.io skonfigurowany ze sklepem Redis jest prawdopodobnie najprostszy dla Ciebie.

 31
Author: Pascal Belloncle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-19 22:43:38

Skończyłem pisząc wtyczkę węzła, aby umożliwić wiele klientów pub-sub, ale wymaga tylko 2 połączeń redis zamiast nowego na każdym pojedynczym połączeniu socketio, powinno działać w ogóle, pomyślałem, że ktoś inny może znaleźć dla niego zastosowanie.

Ten kod zakłada, że masz socket.io uruchamianie i konfigurację, w zasadzie w tym przykładzie dowolna liczba socket.io klienci mogą się łączyć i zawsze będą używać tylko 2 połączeń redis, ale wszyscy klienci mogą subskrybować własne kanały. W tym przykład, wszyscy klienci otrzymują wiadomość ' sweet message! po 10 sekundach.

Przykład z 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);

Rzeczywisty kod wtyczki:

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;

Obijałem się i próbowałem poprawić wydajność, jak tylko mogłem, ale po kilku różnych testach prędkości, doszedłem do wniosku, że to najszybszy, jaki mogłem go zdobyć.

Dla wersji aktualnej: https://github.com/Jezternz/node-redis-pubsub

 6
Author: Josh Mc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-18 22:18:01