2011-12-02 10 views
6

私はNode.js、Socket.ioとRedisstore、ClusterとSocket.ioのユーザー、Redisを使用しています。クラスタ化されたnode.js/socket.io/redis pub/subアプリケーションに重複したメッセージが届いています

1つのNode.jsノードでうまく動作するpub/subアプリケーションがあります。しかし、Node.jsはマルチコアマシン用に書かれていないので、重い負荷がかかると、サーバのコアが1つだけになります。

私は現在、Socket.ioを作ったのと同じ人であるLearnboostのClusterモジュールを使用しています。

しかし、私は4つのワーカープロセスを起動すると、来て、購読する各ブラウザクライアントは、Redisで公開されている各メッセージの4つのコピーを取得します。 3つのワーカープロセスがある場合は、3つのコピーがあります。

私は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クラスター」の良さをバイパスしていました。

私はRailsアプリケーションからメッセージを受け取り、socket.io-announceモジュールを使用してSocket.ioルームに「発表」した小さなアプリケーション(Node.js/Socket.io/Express付き)を作成しました。さて、ソケットを使って。ioルーティングマジックでは、各ノードワーカーは、直接接続されているブラウザにメッセージを取得して送信します。言い換えれば、pubとsubの両方がNode.js/Socket.ioスタック内で発生したので、重複するメッセージはもうありません。

私のコードを整理したら、どこかでgithubに例を載せます。

+1

これを解決するためにあなたが投稿したことができますか? –

+0

私たちがここで行ったことを見ることができます:https://github.com/StageIt/redis しかし、socket.ioの不具合のために1つのノードにロールバックしました。そのバグの議論がありますが、今修正されているかもしれません:https://github.com/LearnBoost/socket.io/issues/438#issuecomment-3371390 – messick

3

私は、クラスタで戦ってきましたとsocket.io。私はクラスター機能を使用するたびに(私はNodejsクラスターを使用しています)、私は多くのパフォーマンス上の問題とsocket.ioの問題を受け取ります。

これを調べようとしているうちに、私はバグ報告やsocket.io gitについて掘り下げています。クラスタや外部ロードバランサを使用している人は、socket.ioに問題があるようです。

冗長なログを増やすと表示される "クライアントは再接続する必要がありません"という問題が発生するようです。これは、socket.ioがクラスタで実行されるたびに多く現れるので、これは元に戻ります。新しい接続を行うたびにクライアントはsocket.ioクラスタ内のランダムインスタンスに接続されます(認証時には複数のhttp /ソケット/フラッシュ接続を行い、後で新しいデータをポーリングする場合はさらに時間がかかります)。

今のところ、一度に1つのsocket.ioプロセスを使用することに戻っていますが、これはバグかもしれませんが、socket.ioがどのように構築されているかの欠点かもしれません。

追加:今後この問題を解決する方法は、クラスタ内の各socket.ioインスタンスに一意のポートを割り当て、クライアント側でポートの選択をキャッシュすることです。

関連する問題