Как повторно использовать подключение Redis в socket.io?

Вот мой код, использующий socket.io в качестве WebSocket и backend с 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 соединение.

5 ответов

Решение

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

})

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

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

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

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

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.

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

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

Особенно полезно, если ваш прототип находится в месте, где у вас есть ограничение на соединение Redis (например, Redis-To-Go). ТАК ссылка: /questions/39254668/chto-ya-dolzhen-ispolzovat-komnatyi-socketio-ili-pab-sab-redis/39254674#39254674

Использование Redis в качестве магазина стало намного проще, так как этот вопрос был задан / ответил. Он встроен сейчас.

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

Другие вопросы по тегам