40

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

4

5 回答 5

62

实际上,如果您在“连接”事件上实例化客户端,那么您只是为每个连接创建一个新的 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)
    })
  })

})
于 2011-04-21T20:49:58.497 回答
2

Redis针对高级并发连接进行了优化在node_redis模块中也有关于多数据库连接和连接池实现的讨论。

如果cookie相同,是否可以重用redis连接?因此,如果有人打开许多浏览器选项卡也视为打开 1 个连接。

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

于 2011-04-21T10:16:30.187 回答
1

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

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

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

于 2013-06-07T01:49:46.147 回答
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 和 Socket.io:跨服务器身份验证和 node.js 理解

于 2014-02-14T02:32:24.900 回答
0

自从提出/回答了这个问题以来,使用 redis 作为存储变得更加简单。它现在内置

请注意,如果您因为使用新的节点集群功能(使用多个 CPU)而使用 redis,则必须创建服务器并将侦听器附加到每个集群分叉中(这实际上从未在任何地方解释过)文档;))。我在网上找到的唯一一个很好的代码示例是用 CoffeeScript 编写的,我看到很多人说这种事情“根本行不通”,如果你做错了肯定不会。这是一个“做对了”的例子(但它在 CoffeeScript 中)

于 2013-08-05T15:18:32.803 回答