Как повторно использовать соединение 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 подключений. Это не выглядит хорошо.

Можно ли повторно использовать соединение redis, если файлы cookie одинаковы? Поэтому, если кто-то открывает многие вкладки браузера, также рассматривайте как открытое 1 соединение.

Ответ 1

На самом деле вы создаете новый клиент 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)
    })
  })

})

Ответ 2

Redis оптимизирован для высокого уровня параллельных подключений. Существует также обсуждение о нескольких подключениях к базе данных и реализации пула соединений в node_redis.

Можно ли повторно использовать redis если файлы cookie одинаковы? Так если кто-то открывает много вкладок браузера обрабатывать как открытое 1 соединение.

Вы можете использовать, например, хранилище HTML5 на стороне клиента, чтобы активно подключаться только к одной вкладке, а другие будут обрабатывать сообщения/сообщения через хранилище Мероприятия. Это связано с этим вопросом.

Ответ 3

У меня была эта точная проблема, с дополнительным требованием, чтобы клиенты могли подписаться на частные каналы, а публикация этих каналов не должна быть отправлена ​​всем слушателям. Я попытался решить эту проблему, написав миниатюрный плагин. Плагин:

  • Использует только 2 соединения redis, один для pub, один для sub
  • Только подписчивается на "сообщение" после полного (не один раз на повторное соединение)
  • Разрешить клиентам подписываться на собственные частные каналы, без отправки сообщений всем другим слушающим клиентам.

Особенно полезно, если ваше прототипирование в месте, где у вас есть предел redis-соединения (например, redis-to-go). Ссылка SO: fooobar.com/questions/8447/...

Ответ 4

Вам нужно удалить слушателя, когда клиент отключится.

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

Ответ 5

Использование redis в качестве магазина стало намного проще, так как этот вопрос задавался/отвечал. Теперь он встроен.

Обратите внимание, что если вы используете redis, потому что используете новые возможности кластеризации node (используя несколько процессоров), вам необходимо создать сервер и подключить слушателей внутри каждой из кластерных вилок (это никогда не происходит объясняется где угодно в любой документации;)). Единственный хороший пример кода, который я нашел, написан в CoffeeScript, и я вижу, что многие люди говорят, что этот тип вещей "просто не работает", и он определенно не делает, если вы делаете это неправильно. Вот пример "делать это правильно" (но это в CoffeeScript)