Использование (socket.io + RedisStore) для связи между несколькими серверами

Я работаю над многопользовательской онлайн-игрой, используя Node.js и Socket.io. Я ожидаю, что к игре присоединится много игроков, поэтому я размещаю ее на Amazon Opworks.

Проблема в том, что серверы не могут отправлять события сокетов клиентам, подключенным к другому серверу. Я использую RedisStore для управления сеансами socket.io. Я полагал, что RedisStore и socket.io позаботились об этом межсерверном взаимодействии под капотом без проблем. Вот ссылка на другой вопрос: Как работает socket. io отправлять сообщения на несколько серверов?

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

Это просто выдержка из всего кода. Пожалуйста, игнорируйте синтаксические ошибки и т. д., если они есть.

app.js

    //Redis Client Initialization
   var redis = require("redis");
   redis_client = require('redis-url').connect('redis://xxxxx');

//setting RedisStore for socket.io 

var RedisStore = require('socket.io/lib/stores/redis')
, redis  = require('socket.io/node_modules/redis')
, pub    = redis.createClient(11042,'-----')
, sub    = redis.createClient(11042,'-----')
, client = redis.createClient(11042,'-----');

// using RedisStore in combo with Socket.io to allow communications across multiple servers

io.set('store', new RedisStore({
  redis    : redis,
  redisPub : pub,
  redisSub : sub,
  redisClient : client
}));

//socket communication specific code 


io.of('/game')
.on('connection', function (socket) {

  socket.on('init' , function(data){

    var user_id = data.user_id; // collecting user_id that was sent by the client
    var socket_id = socket.id;
    redis_client.set("user_socket:"+user_id, socket_id, function(err, reply){

          //stored a referece to the socket id for that user in the redis database

    });

  });

  socket.on('send_message', function(data){

      var sender = data.sender_id;

      var reciepient = data.reciepient_id ; // id of the user to whom message is to be sent to
      redis_client.get("user_socket:"+reciepient, function(err,socket_id){

        if(socket_id){

            var socket = io.of('/game').sockets[socket_id];
            socket.emit("message", {sender : sender}); // This fails. Messages to others servers dont go through.

        }
      })

  })

});

person geeky_monster    schedule 24.04.2014    source источник
comment
Вы проверили Redis, чтобы увидеть, приходят ли какие-либо сообщения?   -  person Timothy Strimple    schedule 29.04.2014
comment
Если я делаю ключи * , я не вижу хранящихся там данных, связанных с сообщениями. Как мне проверить, происходит ли обмен сообщениями со стороны Redis?   -  person geeky_monster    schedule 29.04.2014
comment
Каждый из ваших серверов указывает на один и тот же сервер Redis? Или каждый из них размещает свой собственный Redis?   -  person clay    schedule 29.04.2014
comment
Каждая точка указывает на один и тот же сервер Redis.   -  person geeky_monster    schedule 30.04.2014
comment
Я рекомендую настроить вашу конфигурацию Opsworks, чтобы сначала убедиться, что у вас есть подключение к Redis из одного экземпляра самым простым способом, а затем быть абсолютно уверенным, что у вас есть настоящая система записи одной базы данных Redis, управляющая сеансами на многих серверах.   -  person Charney Kaye    schedule 01.05.2014
comment
Если я использую только один экземпляр в Opsworks, все работает. Так что Redis определенно работает для одного экземпляра. Если я использую несколько экземпляров, вход и аутентификация пользователя работают на всех серверах. Следовательно, подключение к Redis работает на всех серверах.   -  person geeky_monster    schedule 01.05.2014
comment
Не могли бы вы помочь уточнить, как проверить «систему записи»?   -  person geeky_monster    schedule 01.05.2014
comment
столкнулся с точно такой же проблемой. работать на одном экземпляре и терпеть неудачу на нескольких. Вы нашли решение?   -  person mkto    schedule 23.12.2014
comment
@mkto — используйте комнаты и транслируйте в эти комнаты. В основном pub-sub логика.   -  person geeky_monster    schedule 24.12.2014
comment
Привет, спасибо, а как насчет участников комнаты? если, скажем, один участник покинул комнату в одном экземпляре, будет ли другой экземпляр волшебным образом получать обновленных участников комнаты, когда код проходит через список клиентов?   -  person mkto    schedule 25.12.2014


Ответы (1)


Вы не можете напрямую транслировать объекты сокетов на других серверах. Что делает Redis, так это позволяет вам транслировать в «комнаты» на других серверах. К счастью, с socket.io 1.x новые соединения автоматически присоединяются к комнате с именем их идентификатора сокета. Чтобы решить вашу проблему, измените:

    if(socket_id){

        var socket = io.of('/game').sockets[socket_id];
        socket.emit("message", {sender : sender}); // This fails. Messages to others servers dont go through.

    } 

излучать в комнату вместо вызова emit для объекта сокета:

   if(socket_id){

        io.to(socket_id).emit("message", {sender : sender}); // This fails. Messages to others servers dont go through.

    }

А может тебе повезет больше.

person Michael Westcott    schedule 02.10.2014
comment
эта информация должна быть в документах. Люди socket.io всегда упускают важную информацию - person r3wt; 01.07.2016
comment
@geeky_monster доказала ли ваша реализация redis + many-gameserver с вышеуказанным решением успешную производительность? заранее спасибо - person PathToLife; 17.07.2021