What should I be using? Socket.io rooms or Redis pub-sub?

前端 未结 2 409
Happy的楠姐
Happy的楠姐 2020-12-12 11:52

Pretty simple question. I am building a realtime game using nodejs as my backend and I am wondering if there is any information available on which one is more reliable and w

相关标签:
2条回答
  • 2020-12-12 12:12

    Redis pub/sub is great in case all clients have direct access to redis. If you have multiple node servers, one can push a message to the others.

    But if you also have clients in the browser, you need something else to push data from a server to a client, and in this case, socket.io is great.

    Now, if you use socket.io with the Redis store, socket.io will use Redis pub/sub under the hood to propagate messages between servers, and servers will propagate messages to clients.

    So using socket.io rooms with socket.io configured with the Redis store is probably the simplest for you.

    0 讨论(0)
  • 2020-12-12 12:25

    I ended up writing a node plugin to allow for many pub-sub clients but only require 2 redis connections instead of a new one on every single socketio connection, it should work in general, figured someone else may find use for it.

    This code assumed you have socket.io running and setup, basically in this example any number of socket.io clients can connect and it will always still only use 2 redis connections, but all clients can subscribe to their own channels. In this example, all clients get a message 'sweet message!' after 10 seconds.

    Example with socket.io (utilizing 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);
    

    Actual plugin code:

    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;
    

    I mucked around and tried to improve the efficiency as much as I could, but after doing some different speed tests, I concluded this was the fastest I could get it.

    For up-to-date version: https://github.com/Jezternz/node-redis-pubsub

    0 讨论(0)
提交回复
热议问题