2011-12-02 13 views
6

Sto usando Node.js, Socket.io con Redisstore, Cluster da Socket.io ragazzi e Redis.Sto ricevendo messaggi duplicati nel mio cluster node.js/socket.io/redis pub/sub application

Ho una pubblicazione/applicazione secondaria che funziona bene su un solo nodo Node.js. Tuttavia, quando viene sottoposto a un carico pesante, viene eseguito il massimo di un solo core del server poiché Node.js non viene scritto per macchine multi-core.

Come potete vedere qui sotto, sto usando il modulo Cluster di Learnboost, le stesse persone che creano Socket.io.

Tuttavia, quando accendo 4 processi di lavoro, ogni client browser che arriva e si iscrive riceve 4 copie di ciascun messaggio pubblicato in Redis. Se ci sono tre processi di lavoro, ci sono tre copie.

Suppongo di dover spostare la funzionalità di pubblicazione/sottosistema redis in qualche modo sul file cluster.js.

Cluster.js

var cluster = require('./node_modules/cluster'); 

cluster('./app') 
    .set('workers', 4) 
    .use(cluster.logger('logs')) 
    .use(cluster.stats()) 
    .use(cluster.pidfiles('pids')) 
    .use(cluster.cli()) 
    .use(cluster.repl(8888)) 
    .listen(8000); 

App.js

redis = require('redis'), 
sys = require('sys'); 

var rc = redis.createClient(); 

var path = require('path') 
    , connect = require('connect') 
    , app = connect.createServer(connect.static(path.join(__dirname, '../'))); 

// require the new redis store 
var sio = require('socket.io') 
    , RedisStore = sio.RedisStore 
    , io = sio.listen(app); 

io.set('store', new RedisStore);io.sockets.on('connection', function(socket) { 
    sys.log('ShowControl -- Socket connected: ' + socket.id); 

    socket.on('channel', function(ch) { 
     socket.join(ch) 
     sys.log('ShowControl -- ' + socket.id + ' joined channel: ' + ch); 
    }); 

    socket.on('disconnect', function() { 
     console.log('ShowControll -- Socket disconnected: ' + socket.id); 
    }); 
}); 

rc.psubscribe('showcontrol_*'); 

rc.on('pmessage', function(pat, ch, msg) { 
    io.sockets.in(ch).emit('show_event', msg); 
    sys.log('ShowControl -- Publish sent to channel: ' + ch); 
}); 

// cluster compatiblity 
if (!module.parent) { 
    app.listen(process.argv[2] || 8081); 
    console.log('Listening on ', app.address()); 
} else { 
    module.exports = app; 
} 

client.html

<script src="http://localhost:8000/socket.io/socket.io.js"></script> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script> 
<script> 
    var socket = io.connect('localhost:8000'); 
    socket.emit('channel', 'showcontrol_106'); 
    socket.on('show_event', function (msg) { 
     console.log(msg); 
     $("body").append('<br/>' + msg); 
    }); 
</script> 

risposta

3

Risulta che questo non è un problema con Node.js/Socket.io, stavo proprio andando su di esso nel modo completamente sbagliato.

Non solo stavo pubblicando nel server Redis al di fuori dello stack Node/Socket, ma ero ancora direttamente iscritto al canale Redis. Su entrambe le estremità della situazione di pubblico/sub ho bypassato il "cluster Socket.io con Redis Store sul back-end".

Così, ho creato una piccola app (con Node.js/Socket.io/Express) che ha preso i messaggi dalla mia app Rails e li ha "annunciati" in una stanza Socket.io utilizzando il modulo socket.io-announce. Ora, usando Socket.io routing magic, ogni worker nodo otterrebbe e invierà solo messaggi ai browser ad essi connessi direttamente. In altre parole, non più messaggi duplicati dal momento che sia il pub sia il sub si sono verificati nello stack Node.js/Socket.io.

Dopo aver ripulito il codice, inserisco un esempio in un github da qualche parte.

+1

puoi pubblicare cosa hai fatto per risolvere questo? –

+0

Puoi vedere cosa abbiamo fatto qui: https://github.com/StageIt/redis Tuttavia, lo abbiamo riportato su un singolo nodo a causa di un bug nel socket.io. Ecco una discussione su questo bug, che potrebbe essere corretto ora: https://github.com/LearnBoost/socket.io/issues/438#issuecomment-3371390 – messick

3

Sono stato in lotta con il gruppo e socket.io. Ogni volta che utilizzo la funzione cluster (utilizzo però il cluster Nodejs integrato), ho un sacco di problemi di prestazioni e problemi con socket.io.

Durante il tentativo di ricerca di questo, ho scavato attorno alle segnalazioni di bug e simile sul git socket.io e chiunque utilizzi cluster o bilanciatori di carico esterni ai loro server sembra avere problemi con socket.io.

Sembra che venga generato il problema "client non handshaken deve riconnettersi", che verrà visualizzato se si aumenta la registrazione dettagliata. Questo appare molto quando socket.io viene eseguito in un cluster, quindi penso che ritorni a questo. I.E il client si connette a un'istanza randomizzata nel cluster socket.io ogni volta che esegue una nuova connessione (esegue numerose connessioni http/socket/flash quando si autorizza e più tutto il tempo successivo quando si esegue il polling per i nuovi dati).

Per ora sono tornato a utilizzare solo 1 processo socket.io alla volta, questo potrebbe essere un bug, ma potrebbe anche essere un difetto di come viene costruito socket.io.

Aggiunto: Il mio modo di risolverlo in futuro sarà assegnare una porta univoca a ciascuna istanza socket.io all'interno del cluster e quindi selezionare la porta della cache sul lato client.

Problemi correlati