次に、socket.ioをWebSocketとして使用し、バックエンドをpub/sub redisで使用する私のコードを示します。
var io = io.listen(server),
buffer = [];
var redis = require("redis");
var subscribe = redis.createClient(); **<--- open new connection overhead**
io.on('connection', function(client) {
console.log(client.request.headers.cookie);
subscribe.get("..", function (err, replies) {
});
subscribe.on("message",function(channel,message) {
var msg = { message: [client.sessionId, message] };
buffer.Push(msg);
if (buffer.length > 15) buffer.shift();
client.send(msg);
});
client.on('message', function(message){
});
client.on('disconnect', function(){
subscribe.quit();
});
});
新しいioリクエストごとに新しいredis接続が作成されます。誰かが100個のタブでブラウザーを開くと、redisクライアントは100個の接続を開きます。見た目が良くありません。
Cookieが同じ場合、redis接続を再利用できますか?したがって、誰かが多くのブラウザタブを開いた場合も、オープン1接続として扱われます。
実際には、「接続」イベントでクライアントをインスタンス化する場合にのみ、すべての接続に対して新しいredisクライアントを作成しています。チャットシステムを作成するときに行うことは、3つのredisクライアントを作成することです。 1つはパブリッシュ、サブスクライブ、もう1つはredisに値を保存するためのものです。
例えば:
var socketio = require("socket.io")
var redis = require("redis")
// redis clients
var store = redis.createClient()
var pub = redis.createClient()
var sub = redis.createClient()
// ... application paths go here
var socket = socketio.listen(app)
sub.subscribe("chat")
socket.on("connection", function(client){
client.send("welcome!")
client.on("message", function(text){
store.incr("messageNextId", function(e, id){
store.hmset("messages:" + id, { uid: client.sessionId, text: text }, function(e, r){
pub.publish("chat", "messages:" + id)
})
})
})
client.on("disconnect", function(){
client.broadcast(client.sessionId + " disconnected")
})
sub.on("message", function(pattern, key){
store.hgetall(key, function(e, obj){
client.send(obj.uid + ": " + obj.text)
})
})
})
Redisは 高レベルの同時接続用に最適化 です。 node_redis モジュールには、複数のデータベース接続と接続プールの実装について discussion もあります。
Cookieが同じ場合、redis接続を再利用できますか?したがって、誰かが多くのブラウザタブを開いた場合も、オープン1接続として扱われます。
たとえば、クライアント側で HTML5 storage を使用すると、1つのタブのみをアクティブに接続し続けることができ、他のタブはストレージイベントを通じて通信/メッセージを処理します。 this 質問に関連しています。
クライアントの切断時にリスナーを削除する必要があります。
var io = io.listen(server),
buffer = [];
var redis = require("redis");
var subscribe = redis.createClient();
io.on('connection', function(client) {
console.log(client.request.headers.cookie);
subscribe.get("..", function (err, replies) {
});
var redis_handler = function(channel,message) {
var msg = { message: [client.sessionId, message] };
buffer.Push(msg);
if (buffer.length > 15) buffer.shift();
client.send(msg);
};
subscribe.on("message", redis_handler);
client.on('message', function(message){
});
client.on('disconnect', function(){
subscribe.removeListerner('message', redis_handler)
//subscribe.quit();
});
});
クライアントがプライベートチャネルにサブスクライブできなければならず、それらのチャネルへのパブリッシュがすべてのリスナーに送信されるべきではないという追加の要件とともに、この正確な問題がありました。ミニチュアプラグインを作成して、この問題を解決しようとしました。プラグイン:
特にredis接続制限がある場所(redis-to-goなど)でプロトタイプを作成する場合に役立ちます。 SO link: https://stackoverflow.com/a/16770510/685404
この質問が尋ねられたので、redisをストアとして使用することはずっと簡単になりました。 現在は組み込まれています 。
新しいノードクラスタリング機能(複数のCPUを使用)を使用しているためにredisを使用している場合、サーバーを作成し、各クラスターフォーク内にリスナーを接続する必要があることに注意してください(これは、ドキュメント;))。私が見つけたオンラインで唯一の良いコード例はCoffeeScriptで書かれており、多くの人がこのタイプのことを「ただ機能しない」と言っていますが、間違いなくifあなたはそれを間違っています。 「正しく実行する」例です(ただし、CoffeeScriptにあります)