如何在socket.io中重用redis连接?

时间:2011-04-21 03:59:28

标签: node.js redis socket.io

这是我的代码,使用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连接。

5 个答案:

答案 0 :(得分:60)

实际上,如果要在“连接”事件上实例化客户端,则只为每个连接创建一个新的redis客户端。创建聊天系统时我更喜欢创建三个redis客户端。一个用于发布,订阅,一个用于将值存储到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)
    })
  })

})

答案 1 :(得分:2)

Redis是optimized for a high level of concurrent connections。关于discussion模块中的多个数据库连接和连接池实现,还有node_redis

  

是否可以重复使用redis   如果cookie是相同的连接?所以   如果有人打开许多浏览器标签   视为开放1连接。

您可以在客户端使用例如HTML5 storage来保持仅主动连接一个选项卡,而其他人将通过存储事件处理通信/消息。这与this问题有关。

答案 2 :(得分:1)

我遇到了这个问题,并且要求客户端必须能够订阅私有频道,并且不应将发布到这些频道发送给所有侦听器。我试图通过编写一个微型插件来解决这个问题。插件:

  • 仅使用2个redis连接,一个用于pub,一个用于sub
  • 一次只订阅“消息”(不是每次redis连接一次)
  • 允许客户订阅自己的私人频道,而不会将消息发送给所有其他侦听客户。

如果您在具有redis连接限制的地方进行原型设计(例如redis-to-go),则特别有用。 SO链接:https://stackoverflow.com/a/16770510/685404

答案 3 :(得分:1)

您需要在客户端断开连接时删除侦听器。

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, and Socket.io : Cross server authentication and node.js understanding

答案 4 :(得分:0)

使用redis作为商店变得更加简单,因为这个问题被提出/回答了。 It is built in now

请注意,如果您使用的是redis,因为您正在使用新节点群集功能(使用多个CPU),则必须创建服务器并将侦听器附加到每个群集分支中(这在任何地方都不会实际解释)在任何文件中;))。我发现的唯一优秀的在线代码示例是用CoffeeScript编写的,我看到很多人说这种类型的东西“只是不起作用”,如果你做错了肯定不会 Here's an example of "doing it right" (but it is in CoffeeScript)