在服务器之间扩展socket.io

时间:2012-03-27 16:05:55

标签: node.js socket.io

扩展socket.io应用程序的方法有哪些?我看到以下问题,我不明白如何解决:

  • 如何将缩放的socket.io应用程序广播到房间?换句话说,socket.io将如何知道来自其他服务器的邻居?

我很难想象它应该如何运作 - 也许是所有必要信息的共享变体商店,例如redis - 这是否可能?

编辑:我发现了这篇文章:http://www.ranu.com.ar/2011/11/redisstore-and-rooms-with-socketio.html

基于此,我做了以下几点:

   var pub = redis.createClient();  
   var sub = redis.createClient();
   var store = redis.createClient();
   pub.auth("pass");
   sub.auth("pass");
   store.auth("pass");

    io.configure( function(){
io.enable('browser client minification');  // send minified client
io.enable('browser client etag');          // apply etag caching logic based on version number
    io.enable('browser client gzip');          // gzip the file
io.set('log level', 1);                    // reduce logging
io.set('transports', [                     // enable all transports (optional if you want flashsocket)
    'websocket'
  , 'flashsocket'
  , 'htmlfile'
  , 'xhr-polling'
  , 'jsonp-polling'
]);
var RedisStore = require('socket.io/lib/stores/redis');
io.set('store', new RedisStore({redisPub:pub, redisSub:sub, redisClient:store}));
    });

但是我收到以下错误:

      Error: Uncaught, unspecified 'error' event.
     at RedisClient.emit (events.js:50:15)
     at Command.callback (/home/qwe/chat/io2/node_modules/socket.io/node_modules/redis/index.js:232:29)
     at RedisClient.return_error (/home/qwe/chat/io2/node_modules/socket.io/node_modules/redis/index.js:382:25)
     at RedisReplyParser.<anonymous> (/home/qwe/chat/io2/node_modules/socket.io/node_modules/redis/index.js:78:14)
     at RedisReplyParser.emit (events.js:67:17)
     at RedisReplyParser.send_error (    /home/qwe/chat/io2/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js:265:14)
     at RedisReplyParser.execute (/home/qwe/chat/io2/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js:124:22)
     at RedisClient.on_data (/home/qwe/chat/io2/node_modules/socket.io/node_modules/redis/index.js:358:27)
     at Socket.<anonymous> (/home/qwe/chat/io2/node_modules/socket.io/node_modules/redis/index.js:93:14)
     at Socket.emit (events.js:67:17)

我的Redis凭据绝对正确。

编辑:非常奇怪,但禁用Redis授权,一切正常。所以这个问题仍然有效。另外,我有一个关于如何在此RedisStorage模式下为组(房间)的所有参与者获取信息(例如用户名)的问题,是否可以实现此功能?理想情况下,这可以通过Redis Pub / Sub功能完成。

5 个答案:

答案 0 :(得分:0)

您可以使用socket.io群集来实现此功能 https://github.com/muchmala/socket.io-cluster

答案 1 :(得分:0)

尝试添加此代码;

pub.on('error', function (err) {
  console.error('pub', err.stack);
});
sub.on('error', function (err) {
  console.error('sub', err.stack);
});
store.on('error', function (err) {
  console.error('store', err.stack);
});

它不会修复它,但它至少应该给你一个更有用的错误。

答案 2 :(得分:0)

我建议你不要使用RedisStore。它有一个CPU使用问题,因为它使用pub-sub很差导致不可扩展(它可以接收少于一个纯socket.io的实例与socket.io的负载相当无用)。我个人使用Redis作为数据存储来保存房间列表并实现我自己的房间功能(Redis是内存中的键值数据库,但具有持久性机制)。当你想要房间数据时,只需从相同的redis中获取数据即可。但是,为了能够在多个实例中运行Socket.io,您还需要像HAProxy,Nginx这样的负载均衡器将工作分离到多个node.js端口,否则,您的用户仍将只使用一个node.js进程。这是一项巨大的工作。如果你还有其他语言的其他网络前端,那也更有效,因为有些网络会阻止除端口80和443之外的所有端口。您可以在以下网址阅读有关这些内容的更多信息:

http://book.mixu.net/node/ch13.html

答案 3 :(得分:0)

另一种可能的解决方案是使用像PubNub这样的替代方案来扩展实时交互。我在开发Mote.io时遇到了类似的问题,并决定采用托管解决方案而不是构建负载均衡器。我现在为PubNub工作。

PubNub将处理您正在讨论的数据同步问题。通常,您需要跨服务器同步redis或将客户端负载平衡到同一实例,以确保它们获得所有相同的消息。 PubNub抽象了这个,所以你不必担心它。

10行代码中的实时聊天应用

enter image description here

Enter Chat and press enter
<div><input id=input placeholder=you-chat-here /></div>

Chat Output
<div id=box></div>

<script src=http://cdn.pubnub.com/pubnub.min.js></script>
<script>(function(){
var box = PUBNUB.$('box'), input = PUBNUB.$('input'), channel = 'chat';
PUBNUB.subscribe({
    channel  : channel,
    callback : function(text) { box.innerHTML = (''+text).replace( /[<>]/g, '' ) + '<br>' + box.innerHTML }
});
PUBNUB.bind( 'keyup', input, function(e) {
    (e.keyCode || e.charCode) === 13 && PUBNUB.publish({
        channel : channel, message : input.value, x : (input.value='')
    })
} )
})()</script>

答案 4 :(得分:0)

使用RabbitMQ

我使用rabbitMQ实现了socket.io应用程序扩展。在我当前的设置中,我在docker swarm中运行了两个socket.io应用程序容器的副本并与它们通信。这是每个消息显示的带有容器ID的演示: enter image description here

如何

RabbitMQ是一个消息代理,基本上,它同步应用程序后端的所有实例。后端的每个实例都将其消息推送到rabbitMQ上的队列,该队列由所有其他实例使用。 NodeJS中的RabbitMQ处理程序如下所示。

function rabbitHandler(io){
  rabbitMQHandler('amqp://test_rabbit', function(err, options){

    if(err){
      throw err;  
    }

    options.onMessageReceived = onMessageReceived;

    io.on('connection', websocketConnect);

    function websocketConnect(socket){

      console.log('New connection')
      io.emit('start', {ipHost: os.hostname()})

      socket.on('disconnect', socketDisconnect);
      socket.on('message', socketMessage);

      function socketDisconnect(e){
        console.log('Disconnect ', e);
      }

      function socketMessage(text){
        var message =  {text: text, date: new Date(), ip: os.hostname()};
  //      io.emit('message', message) // Instead of emitting the message on socket, it is being pushed on rabbitMQ queue.
        options.emitMessage(message);
      }
    }

    function onMessageReceived(message){

      io.emit('message', message)
    }

  });
} 

套接字客户端没有任何变化。

整个项目在以下链接中给出了docker image和docker compose文件。你可以尝试一下。

https://github.com/saqibahmed515/chat-scaling