2014-09-30 22 views
6

Qualcuno conosce una buona soluzione per scalare un'app basata su node.js - socket.io su più core? Attualmente sto testando la soluzione presentata nella documentazione di socket.io, per utilizzare socket.io su più nodi, ma senza un successo concreto.Scala node.js [email protected]*.* con cluster e socket.io-redis su Heroku

Ho creato un parco giochi per questo su github: https://github.com/liviuignat/socket.io-clusters che è una copia leggermente modificata dell'applicazione di chat dal sito socket.io. Utilizza express, cluster, [email protected] e socket.io-redis.

Attualmente esiste anche un'implementazione utilizzando sticky-session nel ramo feature/sticky che sembra funzionare meglio.

Alla fine l'applicazione deve essere pubblicata su Heroku, ridimensionato su più dynos.

Inizialmente ho tryied fare qualcosa di simile - per avviare il server solo per i nodi del cluster, ma ho sempre l'errore: fallito: Connessione chiusa prima di ricevere una risposta stretta di mano

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

    cluster.on('exit', function(worker, code, signal) { 
    console.log('worker ' + worker.process.pid + ' died'); 
    }); 
} else { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
    }) 
    .setupApp() 
    .setupRoutes() 
    .start(); 
} 

poi ho provato avvio del server anche per nodi master:

if (cluster.isMaster) { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
    }) 
    .setupApp() 
    .setupRoutes() 
    .start(); 

    for (var i = 0; i < numCPUs; i++) { 
    cluster.fork(); 
    } 

    cluster.on('exit', function(worker, code, signal) { 
    console.log('worker ' + worker.process.pid + ' died'); 
    }); 
} else { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
    }) 
    .setupApp() 
    .setupRoutes() 
    .start(); 
} 

ho anche provato utilizzando sia sticky-session e socket.io-redis nel ramo feature/sticky, che sembra eseguire con successo, ma ancora non sembra essere una buona soluzione:

if (cluster.isMaster) { 
    sticky(function() { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
     }) 
     .setupApp() 
     .setupRoutes(); 
    return server.http; 
    }).listen(3000, function() { 
    console.log('server started on 3000 port'); 
    }); 

    for (var i = 0; i < numCPUs; i++) { 
    cluster.fork(); 
    } 

    cluster.on('exit', function(worker, code, signal) { 
    console.log('worker ' + worker.process.pid + ' died'); 
    }); 
} else { 
    sticky(function() { 
    var server = new Server({ 
     dirName: __dirname, 
     enableSocket: true 
     }) 
     .setupApp() 
     .setupRoutes(); 
    return server.http; 
    }).listen(3000, function() { 
    console.log('server started on 3000 port'); 
    }); 
} 

mi farà più test per i prossimi giorni, ma, sarebbe di grande aiuto se qualcuno potrebbe venire con alcune idee.

Grazie,

risposta

2

si sono probabilmente alla ricerca di socket.io-Redis. http://socket.io/blog/introducing-socket-io-1-0/ (scorrere fino a 'scalabilità')

Ecco un esempio accorciato su come creare l'impalcatura con socket.io + espresso:

var cluster = require('cluster'); 

var express = require('express') 
    , app = express() 
    , server = require('http').createServer(app); 

var 
    io = require('socket.io').listen(server) 
    var redis = require('socket.io-redis'); 
    io.adapter(redis({ host: 'localhost', port: 6379 })); 



var workers = process.env.WORKERS || require('os').cpus().length; 

/** 
* Start cluster. 
*/ 

if (cluster.isMaster) { 

    /** 
    * Fork process. 
    */ 

    console.log('start cluster with %s workers', workers-1); 
    workers--; 
    for (var i = 0; i < workers; ++i) { 
    var worker = cluster.fork(); 
    console.log('worker %s started.', worker.process.pid); 
    } 

    /** 
    * Restart process. 
    */ 

    cluster.on('death', function(worker) { 
    console.log('worker %s died. restart...', worker.process.pid); 
    cluster.fork(); 
    }); 


} else { 
    server.listen(process.env.PORT || 9010); 
} 

Redis è pub/sub e tutti i nodi devono socket.io iscriviti a redis per ottenere tutti i messaggi da un canale. In questo modo un processo può trasmettere un messaggio a un canale (pubblicazione) e tutti gli altri processi ricevono i messaggi con una latenza minima per trasmetterli ai client connessi (sottoscrizione). Puoi persino estenderlo con sessioni basate su redis.

Il modulo del cluster a cui ti riferisci è un po 'fuorviante secondo me. Aiuta a creare sottoprocessi invidiosi per quanto comprendo il concetto, ma non "sincronizza" i canali su più nodi. Se i tuoi clienti non hanno bisogno di comunicare con gli altri, va bene. Se si desidera trasmettere messaggi a tutti i client connessi su tutti i nodi è necessario il modulo redis.

+0

Ciao Steffen, sto usando socket.io-redis senza successo. –

+0

Ho aggiunto un esempio tratto da un progetto su cui ho lavorato un po 'di tempo fa. A quel tempo le cose erano un po 'diverse, ma l'ho aggiornato per usare socket.io-redis per socket.io> = 1.0 – Steffen

+0

Grazie, sembra che sia riuscito a farlo funzionare con un server semplice (vedi: https://github.com/liviuignat/chat-example-cluster/blob/master/index.js).Ci giocherò un po 'di più, perché nel mio progetto principale ha ancora problemi. –

Problemi correlati