web-dev-qa-db-ja.com

socket.ioでredis接続を再利用する方法は?

次に、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接続として扱われます。

40
user717166

実際には、「接続」イベントでクライアントをインスタンス化する場合にのみ、すべての接続に対して新しい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)
    })
  })

})
60
sintaxi

Redisは 高レベルの同時接続用に最適化 です。 node_redis モジュールには、複数のデータベース接続と接続プールの実装について discussion もあります。

Cookieが同じ場合、redis接続を再利用できますか?したがって、誰かが多くのブラウザタブを開いた場合も、オープン1接続として扱われます。

たとえば、クライアント側で HTML5 storage を使用すると、1つのタブのみをアクティブに接続し続けることができ、他のタブはストレージイベントを通じて通信/メッセージを処理します。 this 質問に関連しています。

2
yojimbo87

クライアントの切断時にリスナーを削除する必要があります。

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、Node.js、およびSocket.ioを参照してください:クロスサーバー認証とnode.jsの理解

1
nakwa

クライアントがプライベートチャネルにサブスクライブできなければならず、それらのチャネルへのパブリッシュがすべてのリスナーに送信されるべきではないという追加の要件とともに、この正確な問題がありました。ミニチュアプラグインを作成して、この問題を解決しようとしました。プラグイン:

  • 2つのRedis接続のみを使用します。1つはパブ用、もう1つはサブ用です
  • 合計1回だけ「メッセージ」にサブスクライブする(redis接続ごとに1回ではない)
  • 他のすべてのリッスンしているクライアントにメッセージが送信されることなく、クライアントが独自のプライベートチャネルにサブスクライブできるようにします。

特にredis接続制限がある場所(redis-to-goなど)でプロトタイプを作成する場合に役立ちます。 SO link: https://stackoverflow.com/a/16770510/685404

1
Josh Mc

この質問が尋ねられたので、redisをストアとして使用することはずっと簡単になりました。 現在は組み込まれています

新しいノードクラスタリング機能(複数のCPUを使用)を使用しているためにredisを使用している場合、サーバーを作成し、各クラスターフォーク内にリスナーを接続する必要があることに注意してください(これは、ドキュメント;))。私が見つけたオンラインで唯一の良いコード例はCoffeeScriptで書かれており、多くの人がこのタイプのことを「ただ機能しない」と言っていますが、間違いなくifあなたはそれを間違っています「正しく実行する」例です(ただし、CoffeeScriptにあります)

0
cmcculloh