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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5739357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:03:53  来源:igfitidea点击:

How to reuse redis connection in socket.io?

node.jsredissocket.io

提问by user717166

Here is my code using socket.io as WebSocket and backend with pub/sub 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();
    });
});

Every new io request will create new redis connection. If someone open browser with 100 tabs then the redis client will open 100 connections. It doesn't look nice.

每个新的 io 请求都会创建新的 redis 连接。如果有人打开带有 100 个选项卡的浏览器,那么 redis 客户端将打开 100 个连接。看起来不好看。

Is it possible to reuse redis connection if the cookies are same? So if someone open many browser tabs also treat as open 1 connection.

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

回答by sintaxi

Actually you are only creating a new redis client for every connection if you are instantiating the client on the "connection" event. What I prefer to do when creating a chat system is to create three redis clients. One for publishing, subscribing, and one for storing values into redis.

实际上,如果您在“连接”事件上实例化客户端,则只是为每个连接创建一个新的 redis 客户端。在创建聊天系统时,我更喜欢做的是创建三个 redis 客户端。一种用于发布、订阅,一种用于将值存储到 redis 中。

for example:

例如:

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

})

回答by yojimbo87

Redis is optimized for a high level of concurrent connections. There is also discussionabout multiple database connections and connection pool implementation in node_redismodule.

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

Is it possible to reuse redis connection if the cookies are same? So if someone open many browser tabs also treat as open 1 connection.

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

You can use for example HTML5 storageon the client side to keep actively connected only one tab and others will handle communication/messages through storage events. It's related to thisquestion.

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

回答by Josh Mc

I had this exact problem, with an extra requirement that clients must be able to subscribe to private channels, and publish to those channels should not be sent to all listeners. I have attempted to solve this problem by writing a miniature plugin. The plugin:

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

  • Uses only 2 redis connections, one for pub, one for sub
  • Only subscribes to "message" once total (not once every redis connection)
  • Allow clients to subscribe to their own private channels, without messages being sent to all other listening clients.
  • 仅使用 2 个 redis 连接,一个用于 pub,一个用于 sub
  • 总共只订阅一次“消息”(而不是每个 redis 连接一次)
  • 允许客户端订阅他们自己的私人频道,而不会将消息发送到所有其他收听客户端。

Especially useful if your prototyping in a place where you have a redis connection limit (such as redis-to-go). SO link: https://stackoverflow.com/a/16770510/685404

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

回答by nakwa

You need to remove the listener when client disconnect.

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

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

See Redis, Node.js, and Socket.io : Cross server authentication and node.js understanding

参见Redis、Node.js 和 Socket.io:跨服务器认证和 node.js 理解

回答by cmcculloh

Using redis as a store has become much simpler since this question was asked/answered. It is built in now.

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

Note, that if you are using redis because you are using the new node clustering capabilities (utilizing multiple CPUs), you have to create the server and attach the listeners inside of each of the cluster forks (this is never actually explained anywhere in any of the documentation ;) ). The only good code example online that I have found is written in CoffeeScript and I see a lot of people saying this type of thing "just doesn't work", and it definitely doesn't if you do it wrong. Here's an example of "doing it right" (but it is in CoffeeScript)

请注意,如果您使用 redis 是因为您正在使用新的节点集群功能(利用多个 CPU),您必须创建服务器并将侦听器附加到每个集群分叉中(这在任何文档;))。我在网上找到的唯一好的代码示例是用 CoffeeScript 编写的,我看到很多人说这种类型的东西“不起作用”,如果你做错了,它肯定不会。这是一个“做对了”的例子(但它在 CoffeeScript 中)