使用 (socket.io + RedisStore) 跨多个服务器进行通信

Posted

技术标签:

【中文标题】使用 (socket.io + RedisStore) 跨多个服务器进行通信【英文标题】:Using (socket.io + RedisStore) to communicate across multiple servers 【发布时间】:2014-06-09 04:02:07 【问题描述】:

我正在使用 Node.js 和 Socket.io 开发多人在线游戏。我希望有很多玩家加入游戏,所以我将它托管在 Amazon Opworks 上。

问题是服务器无法将套接字事件发送到连接到不同服务器的客户端。我正在使用 RedisStore 来管理 socket.io 会话。我相信 RedisStore 和 socket.io 以无缝的方式在后台处理了这种服务器间通信。这里引用另一个问题:How does socket.io send messages across multiple servers?

但似乎并非如此。如果消息在不同的服务器上,则消息不会传递给其他客户端;如果只有一台服务器,该应用程序可以工作,但如果我在 Opsworks 上使用使用 ELB 进行负载平衡的多台服务器,该应用程序将失败。

这只是整个代码的摘录。请忽略语法错误等。

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.

        
      )

  )

);

【问题讨论】:

你检查过redis是否有消息进入? 如果我做一个键 * ,我看不到任何存储在那里的消息相关数据。如何检查消息是否从 Redis 端发生? 你的每台服务器是否都指向同一个redis服务器?还是他们各自托管自己的 redis? 每一个指向同一个redis服务器。 我建议调整您的 Opsworks 配置,首先以最基本的方式确认您具有来自单个实例的 Redis 连接,然后绝对确保您拥有一个真正的“记录系统”,由单个 Redis 数据库管理跨多个服务器的会话。 【参考方案1】:

您不能直接广播到其他服务器上的套接字对象。 Redis 所做的是允许您向其他服务器上的“房间”广播。值得庆幸的是,使用 socket.io 1.x,新连接会自动加入一个带有其套接字 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.

     

发射到房间而不是在套接字对象上调用发射:

   if(socket_id)

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

    

你可能会有更多的运气。

【讨论】:

此信息应在文档中。 socket.io 的人总是遗漏关键信息 @geeky_monster 您的 redis + many-gameserver 实施是否通过上述解决方案证明了成功的性能?提前谢谢你

以上是关于使用 (socket.io + RedisStore) 跨多个服务器进行通信的主要内容,如果未能解决你的问题,请参考以下文章

何时使用 socket.io 何时使用 ajax

/socket.io/socket.io.js 中不提供 Socket.io

在 Heroku 上使用集群和 socket.io-redis 扩展 node.js socket.io@1.*.*

socket.io,io 未定义(JS 错误)

Node.js 使用 socket.io 进行重构

vue-socket.io 及 egg-socket.io 的简单使用