2011-12-02 88 views
6

我正在使用Node.js,Socket.io與Redisstore,來自Socket.io傢伙的羣集以及Redis。我在羣集node.js/socket.io/redis pub/sub應用程序中收到重複消息

我已經有一個pub/sub應用程序,只在一個Node.js節點上運行良好。但是,當它承受沉重的負載時,最大限度地只是服務器的一個核心,因爲Node.js不是爲多核機器編寫的。

正如您在下面看到的,我現在使用的是來自Learnboost的Cluster模塊,這些模塊與製作Socket.io的人相同。

但是,當我啓動4個工作進程時,每個進入和訂閱的瀏覽器客戶端都會獲得Redis中發佈的每條消息的4個副本。如果有三個工作進程,則有三個副本。

我猜我需要將redis pub/sub功能以某種方式移動到cluster.js文件。

Cluster.js

var cluster = require('./node_modules/cluster'); 

cluster('./app') 
    .set('workers', 4) 
    .use(cluster.logger('logs')) 
    .use(cluster.stats()) 
    .use(cluster.pidfiles('pids')) 
    .use(cluster.cli()) 
    .use(cluster.repl(8888)) 
    .listen(8000); 

App.js

redis = require('redis'), 
sys = require('sys'); 

var rc = redis.createClient(); 

var path = require('path') 
    , connect = require('connect') 
    , app = connect.createServer(connect.static(path.join(__dirname, '../'))); 

// require the new redis store 
var sio = require('socket.io') 
    , RedisStore = sio.RedisStore 
    , io = sio.listen(app); 

io.set('store', new RedisStore);io.sockets.on('connection', function(socket) { 
    sys.log('ShowControl -- Socket connected: ' + socket.id); 

    socket.on('channel', function(ch) { 
     socket.join(ch) 
     sys.log('ShowControl -- ' + socket.id + ' joined channel: ' + ch); 
    }); 

    socket.on('disconnect', function() { 
     console.log('ShowControll -- Socket disconnected: ' + socket.id); 
    }); 
}); 

rc.psubscribe('showcontrol_*'); 

rc.on('pmessage', function(pat, ch, msg) { 
    io.sockets.in(ch).emit('show_event', msg); 
    sys.log('ShowControl -- Publish sent to channel: ' + ch); 
}); 

// cluster compatiblity 
if (!module.parent) { 
    app.listen(process.argv[2] || 8081); 
    console.log('Listening on ', app.address()); 
} else { 
    module.exports = app; 
} 

client.html

<script src="http://localhost:8000/socket.io/socket.io.js"></script> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script> 
<script> 
    var socket = io.connect('localhost:8000'); 
    socket.emit('channel', 'showcontrol_106'); 
    socket.on('show_event', function (msg) { 
     console.log(msg); 
     $("body").append('<br/>' + msg); 
    }); 
</script> 

回答

3

原來,這不是Node.js/Socket.io的問題,我只是用完全錯誤的方式去解決它。

我不僅從Node/Socket堆棧外發布到Redis服務器,還直接訂閱了Redis通道。在pub/sub情況的兩端,我繞過了「後端有Redis Store的Socket.io集羣」的優點。因此,我創建了一個小應用程序(使用Node.js/Socket.io/Express),它從我的Rails應用程序獲取消息,並使用socket.io-announce模塊將它們「宣佈」到Socket.io房間中。現在,通過使用Socket。io路由魔法,每個節點工作人員只會直接發送消息給連接到他們的瀏覽器。換句話說,由於pub和sub發生在Node.js/Socket.io堆棧中,因此不會有更多重複的消息。

在我清理完代碼之後,我會把一個例子放在某個地方的github上。

+1

你可以發佈你做了什麼來解決這個問題嗎? –

+0

你可以看到我們在這裏所做的:https://github.com/StageIt/redis 但是,由於socket.io中的錯誤,我們將它放回單個節點。以下是對該錯誤的討論,現在可以修復它:https://github.com/LearnBoost/socket.io/issues/438#issuecomment-3371390 – messick

3

我一直在解決與集羣和socket.io。每次我使用集羣功能(儘管我使用內置的Nodejs集羣),我會遇到很多性能問題和socket.io問題。

在試圖研究這個,我已經挖周圍的錯誤報告,並在socket.io git的相似,並使用集羣或外部負載平衡器到他們的服務器的人似乎也與socket.io問題。

它似乎產生的問題「客戶端不握手客戶端應該重新連接」,如果您增加詳細日誌記錄,您將看到它。每當socket.io在集羣中運行時都會出現這種情況,所以我認爲它會恢復到此狀態。 I.E客戶端每次進行新連接時都會連接到socket.io集羣中的隨機實例(授權時執行多個http /套接字/閃存連接,而在後續輪詢新數據時會連接多個http /套接字/閃存連接)。

現在我已經恢復到只使用1個socket.io進程,這可能是一個錯誤,但也可能是如何構建socket.io的一個缺點。

補充:我未來解決這個問題的方法是爲集羣內的每個socket.io實例分配一個唯一的端口,然後在客戶端緩存端口選擇。

相關問題