web-dev-qa-db-fra.com

Comment réutiliser la connexion redis dans socket.io?

Voici mon code utilisant socket.io comme WebSocket et backend avec 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();
    });
});

Chaque nouvelle demande io créera une nouvelle connexion redis. Si quelqu'un ouvre un navigateur avec 100 onglets, le client redis ouvrira 100 connexions. Ça n'a pas l'air sympa.

Est-il possible de réutiliser la connexion redis si les cookies sont les mêmes? Donc, si quelqu'un ouvre de nombreux onglets de navigateur, il est également considéré comme une connexion ouverte.

40
user717166

En fait, vous ne créez un nouveau client redis pour chaque connexion que si vous instanciez le client sur l'événement "connexion". Ce que je préfère faire lors de la création d'un système de chat est de créer trois clients redis. Un pour la publication, l'abonnement et un pour le stockage des valeurs dans redis.

par exemple:

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 est optimisé pour un niveau élevé de connexions simultanées . Il y a aussi discussion sur les connexions à plusieurs bases de données et l'implémentation du pool de connexions dans le module node_redis .

Est-il possible de réutiliser la connexion redis si les cookies sont les mêmes? Donc, si quelqu'un ouvre de nombreux onglets de navigateur, il est également considéré comme une connexion ouverte.

Vous pouvez utiliser par exemple stockage HTML5 côté client pour rester activement connecté à un seul onglet et d'autres géreront la communication/messages via les événements de stockage. C'est lié à cette question.

2
yojimbo87

Vous devez supprimer l'écouteur lorsque le client se déconnecte.

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

Voir Redis, Node.js et Socket.io: authentification inter-serveurs et compréhension de node.js

1
nakwa

J'ai eu ce problème exact, avec une exigence supplémentaire que les clients doivent pouvoir s'abonner à des chaînes privées et que la publication sur ces chaînes ne doit pas être envoyée à tous les auditeurs. J'ai tenté de résoudre ce problème en écrivant un plugin miniature. Le plugin:

  • Utilise seulement 2 connexions redis, une pour pub, une pour sous
  • Ne souscrit au "message" qu'une fois au total (pas une fois à chaque connexion redis)
  • Autorisez les clients à s'abonner à leurs propres canaux privés, sans que des messages soient envoyés à tous les autres clients en écoute.

Particulièrement utile si votre prototypage dans un endroit où vous avez une limite de connexion redis (comme redis-to-go). SO lien: https://stackoverflow.com/a/16770510/685404

1
Josh Mc

L'utilisation de redis comme magasin est devenue beaucoup plus simple depuis que cette question a été posée/répondue. Il est intégré maintenant .

Notez que si vous utilisez redis parce que vous utilisez les nouvelles capacités de clustering de nœuds (en utilisant plusieurs processeurs), vous devez créer le serveur et attacher les écouteurs à l'intérieur de chacune des fourches du cluster (cela n'est en fait jamais expliqué nulle part dans aucun des La documentation ;) ). Le seul bon exemple de code en ligne que j'ai trouvé est écrit en CoffeeScript et je vois beaucoup de gens dire que ce genre de chose "ne fonctionne tout simplement pas", et cela ne fonctionne certainement pas si vous le faites mal . Voici un exemple de "bien faire les choses" (mais c'est en CoffeeScript)

0
cmcculloh