2014-09-30 148 views
6

有沒有人知道一個很好的解決方案來擴展node.js - 基於socket.io的應用程序在多個內核上?我目前正在測試socket.io文檔中介紹的解決方案,以在多個節點上使用socket.io,但沒有取得具體的成功。在Heroku上使用cluster和socket.io-redis縮放node.js [email protected]*.*

我在github上爲此創建了一個遊樂場:https://github.com/liviuignat/socket.io-clusters這是從socket.io站點修改聊天應用程序的一個副本。它使用express,cluster,[email protected]socket.io-redis

目前還有一個使用sticky-session在分支feature/sticky這似乎更好的實施。

最後,應用程序需要發佈到Heroku,縮放多個dynos。

起初我tryied做這樣的事情 - 啓動服務器只爲羣集節點,但我總是得到錯誤:失敗:連接接收握手響應之前關閉

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

然後我試圖啓動服務器也是主節點:

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

我也試了一下在分支feature/sticky,這似乎同時使用sticky-sessionsocket.io-redis成功執行,但仍然不似乎是一個很好的解決方案:

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

我會爲接下來的日子裏更多的測試,但是,這將有很大的幫助,如果有人能想出一些想法。

謝謝,

回答

2

您可能正在尋找socket.io-redis。 http://socket.io/blog/introducing-socket-io-1-0/(滾動到「可擴展性」)

這裏有一個關於如何創建socket.io +快遞腳手架縮短的例子:

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的已發佈/訂閱和所有socket.io節點需要訂閱redis以獲取來自頻道的所有消息。通過這種方式,一個進程可以將消息廣播到一個通道(發佈),而所有其他進程以最小的延遲接收消息,以將它們廣播到他們連接的客戶端(訂閱)。你甚至可以用基於redis的會話來擴展它。

您所指的集羣模塊在我看來有點誤導。就我理解這個概念而言,它有助於創建永久的子流程,但不會在多個節點之間「同步」渠道。如果你的客戶不需要與他人溝通,那很好。如果您想在所有節點上向所有連接的客戶端廣播消息,則需要使用redis模塊。

+0

嗨Steffen,我使用socket.io-redis沒有成功。 – 2014-09-30 14:52:22

+0

我已經添加了一個從我工作過的項目中取得的例子。那時候情況有點不同,但我已經更新了它,使用socket.io-redis for socket.io> = 1.0 – Steffen 2014-09-30 15:17:25

+0

謝謝,我似乎已經設法使它與一個簡單的服務器一起工作(請參閱: https://github.com/liviuignat/chat-example-cluster/blob/master/index.js)。我會多玩一點,因爲在我的主要項目中它仍然存在問題。 – 2014-09-30 17:30:24

相關問題