2011-12-19 15 views
10

Sto cercando di ottenere Socket.io per lavorare multi-threaded con native load balancing ("cluster") in Node.js v.0.6.0 e versioni successive.Node.js, multi-threading e Socket.io

Da quello che ho capito, Socket.io utilizza Redis per memorizzare i suoi dati interni. La mia comprensione è questa: invece di generare una nuova istanza di Redis per ogni lavoratore, vogliamo forzare i lavoratori ad usare la stessa istanza di Redis del master. Pertanto, i dati di connessione sarebbero condivisi tra tutti i lavoratori.

Qualcosa di simile nel master:

RedisInstance = new io.RedisStore; 

Il dobbiamo in qualche modo passare RedisInstance ai lavoratori e procedere come segue:

io.set('store', RedisInstance); 

Ispirato this implementation utilizzando il vecchio, il modulo gruppo 3a parte , Ho la seguente implementazione non funzionante:

var cluster = require('cluster'); 
var http = require('http'); 
var numCPUs = require('os').cpus().length; 

if (cluster.isMaster) { 
    // Fork workers. 
    for (var i = 0; i < numCPUs; i++) { 
    cluster.fork(); 
    } 

    var sio = require('socket.io') 
    , RedisStore = sio.RedisStore 
    , io = sio.listen(8080, options); 

    // Somehow pass this information to the workers 
    io.set('store', new RedisStore); 

} else { 
    // Do the work here 
    io.sockets.on('connection', function (socket) { 
    socket.on('chat', function (data) { 
     socket.broadcast.emit('chat', data); 
    }) 
    }); 
} 

Pensieri? Potrei andare completamente nella direzione sbagliata, qualcuno può indicare alcune idee?

+1

mi chiedo quale approccio si finisce per utilizzare. –

risposta

10

In realtà il codice dovrebbe essere così:

var cluster = require('cluster'); 
var http = require('http'); 
var numCPUs = require('os').cpus().length; 

if (cluster.isMaster) { 
    // Fork workers. 
    for (var i = 0; i < numCPUs; i++) { 
    cluster.fork(); 
    } 
} else { 
    var sio = require('socket.io') 
    , RedisStore = sio.RedisStore 
    , io = sio.listen(8080, options); 

    // Somehow pass this information to the workers 
    io.set('store', new RedisStore); 

    // Do the work here 
    io.sockets.on('connection', function (socket) { 
    socket.on('chat', function (data) { 
     socket.broadcast.emit('chat', data); 
    }) 
    }); 
} 

Un'altra opzione è quella di aprire Socket.IO per l'ascolto su più porte e avere qualcosa di simile HAProxy roba di bilanciamento del carico. Ad ogni modo si conosce la cosa più importante: usare RedisStore per scalare all'esterno di un processo!

Risorse:

http://nodejs.org/docs/latest/api/cluster.html
How can I scale socket.io?
How to reuse redis connection in socket.io?
Node: Scale socket.io/nowjs - scale across different instances
http://delicious.com/alessioaw/socket.io

+0

L'implementazione non creerà un nuovo RedisStore per ogni lavoratore? Inoltre, quale sarebbe il vantaggio di usare qualcosa come HAProxy? Sembra che l'uso della funzionalità presente in Node sia migliore. –

+2

Vantaggi di HAProxy: si avrebbero processi su porte diverse, che potreste monitorare con più attenzione e riavviare quando muoiono (usando monit, upstart). Inoltre sì, è necessario creare un nuovo RedisStore per ogni lavoratore. Pensa che cluster è un'implementazione sopra child_process.fork(), quindi basicamente copia l'app N volte (i processi condividono lo stesso descrittore di file per quanto ne so). – alessioalex

+0

Ho appena provato il tuo esempio di codice, sembra non funzionare. Quando si esegue il single-threading, 1500 connessioni eseguono fino al 50% di CPU (ogni lavoratore sta facendo un po 'più di lavoro che nell'esempio). Utilizzando il campione, non riesco a ottenere fino a 500 connessioni prima che * ogni * processo venga eseguito fino all'80-90% della CPU. Quindi, chiaramente, c'è qualcosa di sbagliato dal momento che sta peggiorando la situazione. –