在服务器之间扩展socket.io

7
什么是扩展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

使用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镜像和docker-compose文件都在下面的链接中。您可以在那里进行尝试。

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


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

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


0

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>

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);
});

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接