2011-12-19 27 views
10

Szukam, aby Socket.io działał wielowątkowo z native load balancing ("cluster") w Node.js w wersji 0.6.0 i nowszych.Node.js, multi-threading i Socket.io

Z tego co rozumiem, Socket.io używa Redis do przechowywania swoich wewnętrznych danych. Moje rozumienie jest następujące: zamiast tworzenia nowej instancji Redis dla każdego pracownika, chcemy zmusić pracowników do korzystania z tej samej instancji Redis, co master. W związku z tym dane dotyczące połączenia będą udostępniane wszystkim pracownikom.

Coś takiego w Master:

RedisInstance = new io.RedisStore; 

musimy jakoś przejść RedisInstance do robotników i wykonaj następujące czynności:

io.set('store', RedisInstance); 

Zainspirowany this implementation pomocą starego, moduł klastra 3rd party Mam następujące niedziałające wdrożenie:

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

Myśli? Być może idę całkowicie w złą stronę, czy ktoś może wskazać jakieś pomysły?

+1

Zastanawiam się jakie podejście kończy się użyciem. –

Odpowiedz

10

Właściwie Twój kod powinien wyglądać tak:

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

Innym rozwiązaniem jest otwarcie Socket.IO słuchać na wielu portów i mieć coś podobnego HAProxy obciążenia bilansu rzeczy. W każdym razie wiesz najważniejszą rzeczą: używanie RedisStore do skalowania poza procesem!

Zasoby:

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

Czy ta implementacja nie utworzy nowego magazynu Redis dla każdego pracownika? Co może być zaletą używania czegoś takiego jak HAProxy? Wygląda na to, że korzystanie z funkcjonalności obecnej w trybie Node jest lepsze. –

+2

Zalety HAProxy: będziesz mieć procesy na różnych portach, które możesz monitorować ostrożniej i ponownie uruchomić po ich śmierci (za pomocą monit, upstart). Również tak, musisz utworzyć nowy magazyn RedisStore dla każdego pracownika. Pomyśl, że klaster jest implementacją powyżej child_process.fork(), więc zasadniczo kopiujesz aplikację N razy (procesy dzielą ten sam deskryptor pliku, o ile wiem). – alessioalex

+0

Po prostu próbowałem twojej próbki kodu, wydaje się nie działać. Przy pojedynczym wątku 1500 połączeń obsługuje do 50% CPU (każdy robotnik wykonuje nieco więcej pracy niż w próbie). Korzystając z próbki, nie mogę uzyskać do 500 połączeń, zanim * każdy * proces zostanie uruchomiony do 80-90% procesora. Tak więc, coś jest nie tak, ponieważ to pogarsza sytuację. –

Powiązane problemy