2011-12-19 40 views
10

Estoy buscando que Socket.io trabaje en subprocesos múltiples con native load balancing ("clúster") en Node.js v.0.6.0 y posterior.Node.js, multi-threading y Socket.io

Según tengo entendido, Socket.io usa Redis para almacenar sus datos internos. Según tengo entendido, en lugar de generar una nueva instancia de Redis para cada trabajador, queremos obligar a los trabajadores a utilizar la misma instancia de Redis que el maestro. Por lo tanto, los datos de conexión se compartirían entre todos los trabajadores.

Algo como esto en el maestro:

RedisInstance = new io.RedisStore; 

La tenemos que de alguna manera pasar RedisInstance a los trabajadores y hacer lo siguiente:

io.set('store', RedisInstance); 

Inspirado por this implementation utilizando el módulo de clúster tercera parte vieja , Tengo la siguiente implementación no operativa:

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); 
    }) 
    }); 
} 

¿Pensamientos? Podría estar yendo por completo en la dirección equivocada, ¿alguien puede señalar algunas ideas?

+1

me pregunto qué enfoque que terminan usando. –

Respuesta

10

En realidad su código debería tener este aspecto:

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); 
    }) 
    }); 
} 

Otra opción es abrir Socket.IO a escuchar en varios puertos y tener algo como HAProxy materia de equilibrio de carga. De todos modos, usted sabe lo más importante: usar RedisStore para escalar fuera de un proceso.

Recursos:

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

¿No creará esa implementación una nueva RedisStore para cada trabajador? Además, ¿cuál sería la ventaja de usar algo como HAProxy? Parece que usar la funcionalidad presente de forma nativa en Nodo es mejor. –

+2

Ventajas de HAProxy: tendría procesos en diferentes puertos, que podría supervisar con más cuidado y reiniciar cuando mueran (usando monit, upstart). También sí, necesitas crear una nueva RedisStore para cada trabajador. Piensa que el clúster es una implementación sobre child_process.fork(), así que básicamente copias la aplicación N veces (los procesos comparten el mismo descriptor de archivo hasta donde yo sé). – alessioalex

+0

Acabo de probar su código de muestra, parece no estar funcionando. Cuando se realiza un subprocesamiento único, 1500 conexiones ejecutan hasta 50% de CPU (cada trabajador está haciendo un poco más de trabajo que en la muestra). Usando su muestra, no puedo obtener hasta 500 conexiones antes de que * cada * proceso ejecute hasta 80-90% de CPU. Entonces, claramente, algo está mal ya que esto está empeorando la situación. –